silosdk 0.0.0 → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +3 -1
  2. package/dist/_virtual/rolldown_runtime.cjs +29 -0
  3. package/dist/cli/d1.cjs +93 -0
  4. package/dist/cli/d1.mjs +92 -0
  5. package/dist/cli/index.cjs +93 -0
  6. package/dist/cli/index.d.cts +1 -0
  7. package/dist/cli/index.d.mts +1 -0
  8. package/dist/cli/index.mjs +94 -0
  9. package/dist/cli/init.cjs +134 -0
  10. package/dist/cli/init.mjs +133 -0
  11. package/dist/cli/kv.cjs +63 -0
  12. package/dist/cli/kv.mjs +60 -0
  13. package/dist/cli/r2.cjs +83 -0
  14. package/dist/cli/r2.mjs +82 -0
  15. package/dist/cli/wrangler.cjs +93 -0
  16. package/dist/cli/wrangler.mjs +89 -0
  17. package/dist/local/adapters/cloudflare.cjs +200 -0
  18. package/dist/local/adapters/cloudflare.d.cts +50 -0
  19. package/dist/local/adapters/cloudflare.d.mts +50 -0
  20. package/dist/local/adapters/cloudflare.mjs +200 -0
  21. package/dist/local/auth-context.cjs +14 -0
  22. package/dist/local/auth-context.d.cts +7 -0
  23. package/dist/local/auth-context.d.mts +7 -0
  24. package/dist/local/auth-context.mjs +12 -0
  25. package/dist/local/auth.cjs +109 -0
  26. package/dist/local/auth.d.cts +26 -0
  27. package/dist/local/auth.d.mts +26 -0
  28. package/dist/local/auth.mjs +99 -0
  29. package/dist/local/commit.cjs +350 -0
  30. package/dist/local/commit.d.cts +59 -0
  31. package/dist/local/commit.d.mts +59 -0
  32. package/dist/local/commit.mjs +349 -0
  33. package/dist/local/config.cjs +17 -0
  34. package/dist/local/config.mjs +15 -0
  35. package/dist/local/index.cjs +16 -0
  36. package/dist/local/index.d.cts +10 -0
  37. package/dist/local/index.d.mts +10 -0
  38. package/dist/local/index.mjs +9 -0
  39. package/dist/local/provider.cjs +204 -0
  40. package/dist/local/provider.d.cts +25 -0
  41. package/dist/local/provider.d.mts +25 -0
  42. package/dist/local/provider.mjs +203 -0
  43. package/dist/local/query-store.cjs +276 -0
  44. package/dist/local/query-store.mjs +274 -0
  45. package/dist/local/storage.cjs +71 -0
  46. package/dist/local/storage.d.cts +7 -0
  47. package/dist/local/storage.d.mts +7 -0
  48. package/dist/local/storage.mjs +68 -0
  49. package/dist/local/sync.cjs +124 -0
  50. package/dist/local/sync.d.cts +36 -0
  51. package/dist/local/sync.d.mts +36 -0
  52. package/dist/local/sync.mjs +122 -0
  53. package/dist/local/view.cjs +257 -0
  54. package/dist/local/view.d.cts +24 -0
  55. package/dist/local/view.d.mts +24 -0
  56. package/dist/local/view.mjs +254 -0
  57. package/dist/package.cjs +11 -0
  58. package/dist/package.mjs +5 -0
  59. package/dist/schema/index.cjs +276 -0
  60. package/dist/schema/index.d.cts +207 -0
  61. package/dist/schema/index.d.mts +207 -0
  62. package/dist/schema/index.mjs +265 -0
  63. package/dist/server/auth.cjs +132 -0
  64. package/dist/server/auth.d.cts +49 -0
  65. package/dist/server/auth.d.mts +49 -0
  66. package/dist/server/auth.mjs +122 -0
  67. package/dist/server/d1.cjs +120 -0
  68. package/dist/server/d1.mjs +116 -0
  69. package/dist/server/do.cjs +132 -0
  70. package/dist/server/do.d.cts +21 -0
  71. package/dist/server/do.d.mts +21 -0
  72. package/dist/server/do.mjs +131 -0
  73. package/dist/server/index.cjs +355 -0
  74. package/dist/server/index.d.cts +65 -0
  75. package/dist/server/index.d.mts +65 -0
  76. package/dist/server/index.mjs +348 -0
  77. package/dist/server/protect.cjs +34 -0
  78. package/dist/server/protect.d.cts +32 -0
  79. package/dist/server/protect.d.mts +32 -0
  80. package/dist/server/protect.mjs +33 -0
  81. package/dist/server/r2.cjs +58 -0
  82. package/dist/server/r2.d.cts +4 -0
  83. package/dist/server/r2.d.mts +4 -0
  84. package/dist/server/r2.mjs +53 -0
  85. package/package.json +55 -2
@@ -0,0 +1,122 @@
1
+ //#region src/local/sync.ts
2
+ /**
3
+ * Abstract sync adapter base class.
4
+ */
5
+ var SyncAdapter = class {
6
+ constructor(options) {
7
+ this.merge = options?.merge;
8
+ }
9
+ };
10
+ /**
11
+ * Apply remote ops to local SQLite with LWW conflict resolution.
12
+ */
13
+ async function applyRemoteOps(db, ops, subscribers, merge) {
14
+ const touchedViews = /* @__PURE__ */ new Set();
15
+ await db.withTransactionAsync(async () => {
16
+ for (const op of ops) if (op.kind === "add") {
17
+ await handleRemoteAdd(db, op, merge);
18
+ touchedViews.add(op.view.name);
19
+ } else if (op.kind === "update") {
20
+ await handleRemoteUpdate(db, op, merge);
21
+ touchedViews.add(op.view.name);
22
+ } else if (op.kind === "remove") {
23
+ await handleRemoteRemove(db, op);
24
+ touchedViews.add(op.view.name);
25
+ } else if (op.kind === "link" || op.kind === "unlink") {
26
+ await handleRemoteLink(db, op);
27
+ touchedViews.add(op.parent.view.name);
28
+ touchedViews.add(op.child.view.name);
29
+ }
30
+ });
31
+ for (const [key, sub] of subscribers) for (const viewName of touchedViews) if (key.includes(viewName)) {
32
+ sub.update();
33
+ break;
34
+ }
35
+ }
36
+ async function handleRemoteAdd(db, op, merge) {
37
+ const existing = await db.getFirstAsync(`SELECT version, data FROM views WHERE id = ? AND view = ?`, [op.id, op.view.name]);
38
+ if (!existing) await db.runAsync(`INSERT INTO views (id, view, data, createdAt, updatedAt, version)
39
+ VALUES (?, ?, ?, ?, ?, ?)`, [
40
+ op.id,
41
+ op.view.name,
42
+ JSON.stringify(op.value),
43
+ op.timestamp,
44
+ op.timestamp,
45
+ op.version
46
+ ]);
47
+ else if (op.version > existing.version) {
48
+ const finalData = merge ? merge({
49
+ data: JSON.parse(existing.data),
50
+ version: existing.version
51
+ }, {
52
+ data: op.value,
53
+ version: op.version
54
+ }, op.view.name) : op.value;
55
+ await db.runAsync(`UPDATE views SET data = ?, updatedAt = ?, version = ? WHERE id = ? AND view = ?`, [
56
+ JSON.stringify(finalData),
57
+ op.timestamp,
58
+ op.version,
59
+ op.id,
60
+ op.view.name
61
+ ]);
62
+ }
63
+ }
64
+ async function handleRemoteUpdate(db, op, merge) {
65
+ const existing = await db.getFirstAsync(`SELECT version, data FROM views WHERE id = ? AND view = ?`, [op.id, op.view.name]);
66
+ if (!existing) return;
67
+ if (op.version > existing.version) {
68
+ const localData = JSON.parse(existing.data);
69
+ const mergedData = merge ? merge({
70
+ data: localData,
71
+ version: existing.version
72
+ }, {
73
+ data: {
74
+ ...localData,
75
+ ...op.value
76
+ },
77
+ version: op.version
78
+ }, op.view.name) : {
79
+ ...localData,
80
+ ...op.value
81
+ };
82
+ await db.runAsync(`UPDATE views SET data = ?, updatedAt = ?, version = ? WHERE id = ? AND view = ?`, [
83
+ JSON.stringify(mergedData),
84
+ op.timestamp,
85
+ op.version,
86
+ op.id,
87
+ op.view.name
88
+ ]);
89
+ }
90
+ }
91
+ async function handleRemoteRemove(db, op) {
92
+ await db.runAsync(`DELETE FROM views WHERE id = ? AND view = ?`, [op.id, op.view.name]);
93
+ await db.runAsync(`DELETE FROM relations WHERE (parent = ? AND pid = ?) OR (child = ? AND cid = ?)`, [
94
+ op.view.name,
95
+ op.id,
96
+ op.view.name,
97
+ op.id
98
+ ]);
99
+ }
100
+ async function handleRemoteLink(db, op) {
101
+ if (op.kind === "link") {
102
+ if (!await db.getFirstAsync(`SELECT 1 FROM relations WHERE parent = ? AND pid = ? AND child = ? AND cid = ?`, [
103
+ op.parent.view.name,
104
+ op.parent.id,
105
+ op.child.view.name,
106
+ op.child.id
107
+ ])) await db.runAsync(`INSERT INTO relations (parent, pid, child, cid) VALUES (?, ?, ?, ?)`, [
108
+ op.parent.view.name,
109
+ op.parent.id,
110
+ op.child.view.name,
111
+ op.child.id
112
+ ]);
113
+ } else await db.runAsync(`DELETE FROM relations WHERE parent = ? AND pid = ? AND child = ? AND cid = ?`, [
114
+ op.parent.view.name,
115
+ op.parent.id,
116
+ op.child.view.name,
117
+ op.child.id
118
+ ]);
119
+ }
120
+
121
+ //#endregion
122
+ export { SyncAdapter, applyRemoteOps };
@@ -0,0 +1,257 @@
1
+ const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
+ const require_schema_index = require('../schema/index.cjs');
3
+ const require_auth = require('./auth.cjs');
4
+ const require_query_store = require('./query-store.cjs');
5
+ const require_config = require('./config.cjs');
6
+ let react = require("react");
7
+ let expo_sqlite = require("expo-sqlite");
8
+ let jotai = require("jotai");
9
+ let jotai_family = require("jotai-family");
10
+ let jotai_utils = require("jotai/utils");
11
+ let nanoid_non_secure = require("nanoid/non-secure");
12
+
13
+ //#region src/local/view.ts
14
+ const viewRegistry = /* @__PURE__ */ new Map();
15
+ let _queryStore = null;
16
+ function getQueryStore() {
17
+ if (!_queryStore) _queryStore = new require_query_store.QueryStore();
18
+ return _queryStore;
19
+ }
20
+ const elementsFamilies = /* @__PURE__ */ new Map();
21
+ const listsFamilies = /* @__PURE__ */ new Map();
22
+ function getElementsFamily(name) {
23
+ if (!elementsFamilies.has(name)) {
24
+ const family = (0, jotai_family.atomFamily)((args) => (0, jotai_utils.atomWithRefresh)(async () => {
25
+ const { options, db } = args;
26
+ return await require_schema_index.getRow({
27
+ name,
28
+ options,
29
+ db
30
+ });
31
+ }), (a, b) => require_schema_index.stableStringify(a.options) === require_schema_index.stableStringify(b.options));
32
+ elementsFamilies.set(name, family);
33
+ }
34
+ return elementsFamilies.get(name);
35
+ }
36
+ function getListsFamily(name) {
37
+ if (!listsFamilies.has(name)) {
38
+ const family = (0, jotai_family.atomFamily)((args) => (0, jotai_utils.atomWithRefresh)(async () => {
39
+ const { options, db } = args;
40
+ let count = void 0;
41
+ if (args.offset !== void 0) count = (await db.getFirstAsync(`SELECT COUNT(*) AS count FROM views WHERE view = ?;`, [name]))?.count;
42
+ return {
43
+ count,
44
+ rows: await require_schema_index.getRows({
45
+ name,
46
+ options,
47
+ db,
48
+ offset: args.offset,
49
+ count
50
+ })
51
+ };
52
+ }), (a, b) => require_schema_index.stableStringify(a.options) === require_schema_index.stableStringify(b.options));
53
+ listsFamilies.set(name, family);
54
+ }
55
+ return listsFamilies.get(name);
56
+ }
57
+ function registerView(v) {
58
+ viewRegistry.set(v.name, v);
59
+ }
60
+ function useView(v, options) {
61
+ const scope = options.scope ?? "private";
62
+ (0, react.useMemo)(() => registerView(v), [v]);
63
+ if (scope === "public") return usePublicView(v, options);
64
+ return usePrivateView(v, options);
65
+ }
66
+ function usePrivateView(v, options) {
67
+ const db = (0, expo_sqlite.useSQLiteContext)();
68
+ const { subscribers } = require_config.useConfig();
69
+ const instanceId = (0, react.useRef)((0, nanoid_non_secure.nanoid)()).current;
70
+ const subscriberKey = `${v.name}:${instanceId}`;
71
+ const elementsFamily = getElementsFamily(v.name);
72
+ const [data, refreshData] = (0, jotai.useAtom)((0, react.useMemo)(() => elementsFamily({
73
+ options,
74
+ db
75
+ }), [
76
+ v.name,
77
+ options,
78
+ db
79
+ ]));
80
+ (0, react.useEffect)(() => {
81
+ subscribers.set(subscriberKey, { update: () => refreshData() });
82
+ return () => {
83
+ subscribers.delete(subscriberKey);
84
+ };
85
+ }, [
86
+ subscriberKey,
87
+ subscribers,
88
+ refreshData
89
+ ]);
90
+ const { data: rowData, id, view: view$1, createdAt, updatedAt } = data ?? {};
91
+ return {
92
+ data: rowData,
93
+ id: id ?? null,
94
+ view: view$1 ?? null,
95
+ createdAt: createdAt ?? null,
96
+ updatedAt: updatedAt ?? null,
97
+ refresh: () => refreshData()
98
+ };
99
+ }
100
+ function usePublicView(v, options) {
101
+ const { url, getToken, authReady, authReadyPromise } = require_config.useConfig();
102
+ const qs = getQueryStore();
103
+ const key = require_query_store.createCacheKey(v.name, options);
104
+ const fetcher = () => fetchPublicRow(url, v.name, options, getToken);
105
+ if (!authReady) throw authReadyPromise ?? new Promise(() => {});
106
+ qs.ensureFetching(key, fetcher, getToken);
107
+ const { data: rowData, id, view: view$1, createdAt, updatedAt } = (0, react.useSyncExternalStore)((cb) => qs.subscribe(key, cb), () => qs.getSnapshot(key), () => null) ?? {};
108
+ const parsedData = rowData;
109
+ const refresh = () => {
110
+ qs.invalidateKey(key);
111
+ qs.ensureFetching(key, fetcher, getToken);
112
+ };
113
+ return {
114
+ data: parsedData,
115
+ id: id ?? null,
116
+ view: view$1 ?? null,
117
+ createdAt: createdAt ?? null,
118
+ updatedAt: updatedAt ?? null,
119
+ refresh
120
+ };
121
+ }
122
+ function useListView(v, options = {}) {
123
+ const scope = options.scope ?? "private";
124
+ (0, react.useMemo)(() => registerView(v), [v]);
125
+ if (scope === "public") return usePublicListView(v, options);
126
+ return usePrivateListView(v, options);
127
+ }
128
+ function usePrivateListView(v, options) {
129
+ const db = (0, expo_sqlite.useSQLiteContext)();
130
+ const { subscribers } = require_config.useConfig();
131
+ const instanceId = (0, react.useRef)((0, nanoid_non_secure.nanoid)()).current;
132
+ const subscriberKey = `${v.name}:${instanceId}`;
133
+ const [offset, setOffset] = (0, react.useState)(options.take ? 0 : void 0);
134
+ const listsFamily = getListsFamily(v.name);
135
+ const [data, refreshData] = (0, jotai.useAtom)((0, react.useMemo)(() => listsFamily({
136
+ options,
137
+ db,
138
+ offset
139
+ }), [
140
+ v.name,
141
+ options,
142
+ offset,
143
+ db
144
+ ]));
145
+ (0, react.useEffect)(() => {
146
+ subscribers.set(subscriberKey, { update: () => refreshData() });
147
+ return () => {
148
+ subscribers.delete(subscriberKey);
149
+ };
150
+ }, [
151
+ subscriberKey,
152
+ subscribers,
153
+ refreshData
154
+ ]);
155
+ const { rows, count } = data;
156
+ function hasNext() {
157
+ if (count === void 0 || options.take === void 0 || offset === void 0) return false;
158
+ return offset + options.take < count;
159
+ }
160
+ function hasPrev() {
161
+ if (offset === void 0 || options.take === void 0) return false;
162
+ return offset - options.take >= 0;
163
+ }
164
+ const prev = () => {
165
+ if (offset !== void 0 && hasPrev() && options.take !== void 0) setOffset(offset - options.take);
166
+ };
167
+ const next = () => {
168
+ if (hasNext() && offset !== void 0 && options.take !== void 0) setOffset(offset + options.take);
169
+ };
170
+ return {
171
+ list: rows,
172
+ hasPrev,
173
+ hasNext,
174
+ prev,
175
+ next,
176
+ refresh: () => refreshData()
177
+ };
178
+ }
179
+ function usePublicListView(v, options) {
180
+ const { url, getToken, authReady, authReadyPromise } = require_config.useConfig();
181
+ const qs = getQueryStore();
182
+ const key = require_query_store.createCacheKey(v.name, options);
183
+ const fetcher = () => fetchPublicList(url, v.name, options, getToken);
184
+ if (!authReady) throw authReadyPromise ?? new Promise(() => {});
185
+ qs.ensureFetching(key, fetcher, getToken);
186
+ const rows = (0, react.useSyncExternalStore)((cb) => qs.subscribe(key, cb), () => qs.getSnapshot(key), () => []);
187
+ const refresh = () => {
188
+ qs.invalidateKey(key);
189
+ qs.ensureFetching(key, fetcher, getToken);
190
+ };
191
+ return {
192
+ list: rows,
193
+ hasPrev: () => false,
194
+ hasNext: () => false,
195
+ prev: () => {},
196
+ next: () => {},
197
+ refresh
198
+ };
199
+ }
200
+ async function fetchPublicRow(baseUrl, viewName, options, getToken) {
201
+ const params = new URLSearchParams({ id: options.id });
202
+ const headers = {};
203
+ let token = null;
204
+ if (getToken) {
205
+ token = await getToken();
206
+ if (token) headers["Authorization"] = `Bearer ${token}`;
207
+ }
208
+ const res = await fetch(`${baseUrl}/public/${viewName}?${params.toString()}`, { headers });
209
+ if (res.status === 401) {
210
+ if (token) await require_auth.handleUnauthorized(baseUrl);
211
+ throw new Error("Unauthorized");
212
+ }
213
+ if (!res.ok) throw new Error(`Public read failed: ${res.status}`);
214
+ return res.json();
215
+ }
216
+ async function fetchPublicList(baseUrl, viewName, options, getToken) {
217
+ const headers = { "Content-Type": "application/json" };
218
+ let token = null;
219
+ if (getToken) {
220
+ token = await getToken();
221
+ if (token) headers["Authorization"] = `Bearer ${token}`;
222
+ }
223
+ const params = new URLSearchParams();
224
+ if (options.where) params.set("where", JSON.stringify(options.where));
225
+ if (options.order) params.set("order", JSON.stringify(options.order));
226
+ if (options.take !== void 0) params.set("take", String(options.take));
227
+ if ("parent" in options && options.parent) {
228
+ const [parentView, parentId] = options.parent;
229
+ params.set("parentView", parentView.name);
230
+ params.set("parentId", parentId);
231
+ }
232
+ if ("child" in options && options.child) {
233
+ const [childView, childId] = options.child;
234
+ params.set("childView", childView.name);
235
+ params.set("childId", childId);
236
+ }
237
+ const url = params.size ? `${baseUrl}/public/${viewName}?${params.toString()}` : `${baseUrl}/public/${viewName}`;
238
+ const res = await fetch(url, {
239
+ method: "GET",
240
+ headers
241
+ });
242
+ if (res.status === 401) {
243
+ if (token) await require_auth.handleUnauthorized(baseUrl);
244
+ throw new Error("Unauthorized");
245
+ }
246
+ if (res.status === 403) throw new Error("Forbidden");
247
+ if (!res.ok) throw new Error(`Public list failed: ${res.status}`);
248
+ return res.json();
249
+ }
250
+ function getQueryStoreInstance() {
251
+ return getQueryStore();
252
+ }
253
+
254
+ //#endregion
255
+ exports.getQueryStoreInstance = getQueryStoreInstance;
256
+ exports.useListView = useListView;
257
+ exports.useView = useView;
@@ -0,0 +1,24 @@
1
+ import { AnyViewsOptions, Infer, ParsedViewResult, Prettify, View, ViewOptions, view } from "../schema/index.cjs";
2
+
3
+ //#region src/local/view.d.ts
4
+
5
+ interface ElementViewResult<T extends View> {
6
+ data: Prettify<Infer<T>> | null;
7
+ id: string | null;
8
+ view: string | null;
9
+ createdAt: string | null;
10
+ updatedAt: string | null;
11
+ refresh: () => void;
12
+ }
13
+ interface ListViewResult<T extends View> {
14
+ list: Prettify<ParsedViewResult<Infer<T>>>[];
15
+ hasPrev: () => boolean;
16
+ hasNext: () => boolean;
17
+ prev: () => void;
18
+ next: () => void;
19
+ refresh: () => void;
20
+ }
21
+ declare function useView<SomeView extends View>(v: SomeView, options: ViewOptions): ElementViewResult<SomeView>;
22
+ declare function useListView<SomeView extends View>(v: SomeView, options?: AnyViewsOptions<SomeView['schema']['type']>): ListViewResult<SomeView>;
23
+ //#endregion
24
+ export { useListView, useView };
@@ -0,0 +1,24 @@
1
+ import { AnyViewsOptions, Infer, ParsedViewResult, Prettify, View, ViewOptions, view } from "../schema/index.mjs";
2
+
3
+ //#region src/local/view.d.ts
4
+
5
+ interface ElementViewResult<T extends View> {
6
+ data: Prettify<Infer<T>> | null;
7
+ id: string | null;
8
+ view: string | null;
9
+ createdAt: string | null;
10
+ updatedAt: string | null;
11
+ refresh: () => void;
12
+ }
13
+ interface ListViewResult<T extends View> {
14
+ list: Prettify<ParsedViewResult<Infer<T>>>[];
15
+ hasPrev: () => boolean;
16
+ hasNext: () => boolean;
17
+ prev: () => void;
18
+ next: () => void;
19
+ refresh: () => void;
20
+ }
21
+ declare function useView<SomeView extends View>(v: SomeView, options: ViewOptions): ElementViewResult<SomeView>;
22
+ declare function useListView<SomeView extends View>(v: SomeView, options?: AnyViewsOptions<SomeView['schema']['type']>): ListViewResult<SomeView>;
23
+ //#endregion
24
+ export { useListView, useView };
@@ -0,0 +1,254 @@
1
+ import { getRow, getRows, stableStringify, view } from "../schema/index.mjs";
2
+ import { handleUnauthorized } from "./auth.mjs";
3
+ import { QueryStore, createCacheKey } from "./query-store.mjs";
4
+ import { useConfig } from "./config.mjs";
5
+ import { useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
6
+ import { useSQLiteContext } from "expo-sqlite";
7
+ import { useAtom } from "jotai";
8
+ import { atomFamily } from "jotai-family";
9
+ import { atomWithRefresh } from "jotai/utils";
10
+ import { nanoid } from "nanoid/non-secure";
11
+
12
+ //#region src/local/view.ts
13
+ const viewRegistry = /* @__PURE__ */ new Map();
14
+ let _queryStore = null;
15
+ function getQueryStore() {
16
+ if (!_queryStore) _queryStore = new QueryStore();
17
+ return _queryStore;
18
+ }
19
+ const elementsFamilies = /* @__PURE__ */ new Map();
20
+ const listsFamilies = /* @__PURE__ */ new Map();
21
+ function getElementsFamily(name) {
22
+ if (!elementsFamilies.has(name)) {
23
+ const family = atomFamily((args) => atomWithRefresh(async () => {
24
+ const { options, db } = args;
25
+ return await getRow({
26
+ name,
27
+ options,
28
+ db
29
+ });
30
+ }), (a, b) => stableStringify(a.options) === stableStringify(b.options));
31
+ elementsFamilies.set(name, family);
32
+ }
33
+ return elementsFamilies.get(name);
34
+ }
35
+ function getListsFamily(name) {
36
+ if (!listsFamilies.has(name)) {
37
+ const family = atomFamily((args) => atomWithRefresh(async () => {
38
+ const { options, db } = args;
39
+ let count = void 0;
40
+ if (args.offset !== void 0) count = (await db.getFirstAsync(`SELECT COUNT(*) AS count FROM views WHERE view = ?;`, [name]))?.count;
41
+ return {
42
+ count,
43
+ rows: await getRows({
44
+ name,
45
+ options,
46
+ db,
47
+ offset: args.offset,
48
+ count
49
+ })
50
+ };
51
+ }), (a, b) => stableStringify(a.options) === stableStringify(b.options));
52
+ listsFamilies.set(name, family);
53
+ }
54
+ return listsFamilies.get(name);
55
+ }
56
+ function registerView(v) {
57
+ viewRegistry.set(v.name, v);
58
+ }
59
+ function useView(v, options) {
60
+ const scope = options.scope ?? "private";
61
+ useMemo(() => registerView(v), [v]);
62
+ if (scope === "public") return usePublicView(v, options);
63
+ return usePrivateView(v, options);
64
+ }
65
+ function usePrivateView(v, options) {
66
+ const db = useSQLiteContext();
67
+ const { subscribers } = useConfig();
68
+ const instanceId = useRef(nanoid()).current;
69
+ const subscriberKey = `${v.name}:${instanceId}`;
70
+ const elementsFamily = getElementsFamily(v.name);
71
+ const [data, refreshData] = useAtom(useMemo(() => elementsFamily({
72
+ options,
73
+ db
74
+ }), [
75
+ v.name,
76
+ options,
77
+ db
78
+ ]));
79
+ useEffect(() => {
80
+ subscribers.set(subscriberKey, { update: () => refreshData() });
81
+ return () => {
82
+ subscribers.delete(subscriberKey);
83
+ };
84
+ }, [
85
+ subscriberKey,
86
+ subscribers,
87
+ refreshData
88
+ ]);
89
+ const { data: rowData, id, view: view$1, createdAt, updatedAt } = data ?? {};
90
+ return {
91
+ data: rowData,
92
+ id: id ?? null,
93
+ view: view$1 ?? null,
94
+ createdAt: createdAt ?? null,
95
+ updatedAt: updatedAt ?? null,
96
+ refresh: () => refreshData()
97
+ };
98
+ }
99
+ function usePublicView(v, options) {
100
+ const { url, getToken, authReady, authReadyPromise } = useConfig();
101
+ const qs = getQueryStore();
102
+ const key = createCacheKey(v.name, options);
103
+ const fetcher = () => fetchPublicRow(url, v.name, options, getToken);
104
+ if (!authReady) throw authReadyPromise ?? new Promise(() => {});
105
+ qs.ensureFetching(key, fetcher, getToken);
106
+ const { data: rowData, id, view: view$1, createdAt, updatedAt } = useSyncExternalStore((cb) => qs.subscribe(key, cb), () => qs.getSnapshot(key), () => null) ?? {};
107
+ const parsedData = rowData;
108
+ const refresh = () => {
109
+ qs.invalidateKey(key);
110
+ qs.ensureFetching(key, fetcher, getToken);
111
+ };
112
+ return {
113
+ data: parsedData,
114
+ id: id ?? null,
115
+ view: view$1 ?? null,
116
+ createdAt: createdAt ?? null,
117
+ updatedAt: updatedAt ?? null,
118
+ refresh
119
+ };
120
+ }
121
+ function useListView(v, options = {}) {
122
+ const scope = options.scope ?? "private";
123
+ useMemo(() => registerView(v), [v]);
124
+ if (scope === "public") return usePublicListView(v, options);
125
+ return usePrivateListView(v, options);
126
+ }
127
+ function usePrivateListView(v, options) {
128
+ const db = useSQLiteContext();
129
+ const { subscribers } = useConfig();
130
+ const instanceId = useRef(nanoid()).current;
131
+ const subscriberKey = `${v.name}:${instanceId}`;
132
+ const [offset, setOffset] = useState(options.take ? 0 : void 0);
133
+ const listsFamily = getListsFamily(v.name);
134
+ const [data, refreshData] = useAtom(useMemo(() => listsFamily({
135
+ options,
136
+ db,
137
+ offset
138
+ }), [
139
+ v.name,
140
+ options,
141
+ offset,
142
+ db
143
+ ]));
144
+ useEffect(() => {
145
+ subscribers.set(subscriberKey, { update: () => refreshData() });
146
+ return () => {
147
+ subscribers.delete(subscriberKey);
148
+ };
149
+ }, [
150
+ subscriberKey,
151
+ subscribers,
152
+ refreshData
153
+ ]);
154
+ const { rows, count } = data;
155
+ function hasNext() {
156
+ if (count === void 0 || options.take === void 0 || offset === void 0) return false;
157
+ return offset + options.take < count;
158
+ }
159
+ function hasPrev() {
160
+ if (offset === void 0 || options.take === void 0) return false;
161
+ return offset - options.take >= 0;
162
+ }
163
+ const prev = () => {
164
+ if (offset !== void 0 && hasPrev() && options.take !== void 0) setOffset(offset - options.take);
165
+ };
166
+ const next = () => {
167
+ if (hasNext() && offset !== void 0 && options.take !== void 0) setOffset(offset + options.take);
168
+ };
169
+ return {
170
+ list: rows,
171
+ hasPrev,
172
+ hasNext,
173
+ prev,
174
+ next,
175
+ refresh: () => refreshData()
176
+ };
177
+ }
178
+ function usePublicListView(v, options) {
179
+ const { url, getToken, authReady, authReadyPromise } = useConfig();
180
+ const qs = getQueryStore();
181
+ const key = createCacheKey(v.name, options);
182
+ const fetcher = () => fetchPublicList(url, v.name, options, getToken);
183
+ if (!authReady) throw authReadyPromise ?? new Promise(() => {});
184
+ qs.ensureFetching(key, fetcher, getToken);
185
+ const rows = useSyncExternalStore((cb) => qs.subscribe(key, cb), () => qs.getSnapshot(key), () => []);
186
+ const refresh = () => {
187
+ qs.invalidateKey(key);
188
+ qs.ensureFetching(key, fetcher, getToken);
189
+ };
190
+ return {
191
+ list: rows,
192
+ hasPrev: () => false,
193
+ hasNext: () => false,
194
+ prev: () => {},
195
+ next: () => {},
196
+ refresh
197
+ };
198
+ }
199
+ async function fetchPublicRow(baseUrl, viewName, options, getToken) {
200
+ const params = new URLSearchParams({ id: options.id });
201
+ const headers = {};
202
+ let token = null;
203
+ if (getToken) {
204
+ token = await getToken();
205
+ if (token) headers["Authorization"] = `Bearer ${token}`;
206
+ }
207
+ const res = await fetch(`${baseUrl}/public/${viewName}?${params.toString()}`, { headers });
208
+ if (res.status === 401) {
209
+ if (token) await handleUnauthorized(baseUrl);
210
+ throw new Error("Unauthorized");
211
+ }
212
+ if (!res.ok) throw new Error(`Public read failed: ${res.status}`);
213
+ return res.json();
214
+ }
215
+ async function fetchPublicList(baseUrl, viewName, options, getToken) {
216
+ const headers = { "Content-Type": "application/json" };
217
+ let token = null;
218
+ if (getToken) {
219
+ token = await getToken();
220
+ if (token) headers["Authorization"] = `Bearer ${token}`;
221
+ }
222
+ const params = new URLSearchParams();
223
+ if (options.where) params.set("where", JSON.stringify(options.where));
224
+ if (options.order) params.set("order", JSON.stringify(options.order));
225
+ if (options.take !== void 0) params.set("take", String(options.take));
226
+ if ("parent" in options && options.parent) {
227
+ const [parentView, parentId] = options.parent;
228
+ params.set("parentView", parentView.name);
229
+ params.set("parentId", parentId);
230
+ }
231
+ if ("child" in options && options.child) {
232
+ const [childView, childId] = options.child;
233
+ params.set("childView", childView.name);
234
+ params.set("childId", childId);
235
+ }
236
+ const url = params.size ? `${baseUrl}/public/${viewName}?${params.toString()}` : `${baseUrl}/public/${viewName}`;
237
+ const res = await fetch(url, {
238
+ method: "GET",
239
+ headers
240
+ });
241
+ if (res.status === 401) {
242
+ if (token) await handleUnauthorized(baseUrl);
243
+ throw new Error("Unauthorized");
244
+ }
245
+ if (res.status === 403) throw new Error("Forbidden");
246
+ if (!res.ok) throw new Error(`Public list failed: ${res.status}`);
247
+ return res.json();
248
+ }
249
+ function getQueryStoreInstance() {
250
+ return getQueryStore();
251
+ }
252
+
253
+ //#endregion
254
+ export { getQueryStoreInstance, useListView, useView };
@@ -0,0 +1,11 @@
1
+
2
+ //#region package.json
3
+ var name = "silosdk";
4
+
5
+ //#endregion
6
+ Object.defineProperty(exports, 'name', {
7
+ enumerable: true,
8
+ get: function () {
9
+ return name;
10
+ }
11
+ });
@@ -0,0 +1,5 @@
1
+ //#region package.json
2
+ var name = "silosdk";
3
+
4
+ //#endregion
5
+ export { name };