@lunora/client 1.0.0-alpha.28 → 1.0.0-alpha.29

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 (77) hide show
  1. package/dist/auth/index.d.mts +1 -1
  2. package/dist/auth/index.d.ts +1 -1
  3. package/dist/auth/index.mjs +1 -60
  4. package/dist/index.d.mts +3 -3
  5. package/dist/index.d.ts +3 -3
  6. package/dist/index.mjs +1 -21
  7. package/dist/packem_shared/CONFLICT_ERROR_CODE-B2SU0CaJ.mjs +1 -0
  8. package/dist/packem_shared/ClientServiceWorker-CRQ5yl7-.mjs +1 -0
  9. package/dist/packem_shared/DEFAULT_MAX_BUFFER-TBn2s7Rz.mjs +1 -0
  10. package/dist/packem_shared/LunoraClient-DDEoZdgP.mjs +1 -0
  11. package/dist/packem_shared/OfflineQueue-B603_q8m.mjs +1 -0
  12. package/dist/packem_shared/SKIP-CArzT3Vl.mjs +1 -0
  13. package/dist/packem_shared/SubscriptionRegistry-CdrOD7sZ.mjs +1 -0
  14. package/dist/packem_shared/TabCoordinator-ijLic02x.mjs +1 -0
  15. package/dist/packem_shared/applyDelta-DXqQORbM.mjs +1 -0
  16. package/dist/packem_shared/createAsyncStoragePersistence-BRLqeXsC.mjs +1 -0
  17. package/dist/packem_shared/createClientQuery-CrdRoicO.mjs +1 -0
  18. package/dist/packem_shared/createInMemoryBookmarkStorage-DCd5Ej-t.mjs +1 -0
  19. package/dist/packem_shared/createInMemoryPersistence-CQYXy8UP.mjs +1 -0
  20. package/dist/packem_shared/createInMemoryQueryCache-DjCKrLjk.mjs +1 -0
  21. package/dist/packem_shared/createLocalStore-B3Tw_Tw1.mjs +1 -0
  22. package/dist/packem_shared/createMutationRunner-lQXH8Amk.mjs +1 -0
  23. package/dist/packem_shared/createMutatorRunner-BVzo0FBZ.mjs +1 -0
  24. package/dist/packem_shared/createReconnect-CFT7YRSR.mjs +1 -0
  25. package/dist/packem_shared/createReply-DF0jRsv-.mjs +1 -0
  26. package/dist/packem_shared/createServerClient-B7KqO8tv.mjs +1 -0
  27. package/dist/packem_shared/createSnapshotPrecondition-DOKRAJ4b.mjs +1 -0
  28. package/dist/packem_shared/deserializePreloaded-CHfOFpka.mjs +1 -0
  29. package/dist/packem_shared/getServerSession-CGjgRBAE.mjs +1 -0
  30. package/dist/packem_shared/httpStream-Cz4_QyjV.mjs +11 -0
  31. package/dist/packem_shared/idb-utility-C-DR8nG1.mjs +1 -0
  32. package/dist/packem_shared/local-store-C53xDvEr.mjs +1 -0
  33. package/dist/packem_shared/{lunora-client.d-B1iZb2Ph.d.mts → lunora-client.d-Bt65hm_E.d.mts} +135 -1
  34. package/dist/packem_shared/{lunora-client.d-B1iZb2Ph.d.ts → lunora-client.d-Bt65hm_E.d.ts} +135 -1
  35. package/dist/packem_shared/offline-queue-D73Dq95V.mjs +1 -0
  36. package/dist/packem_shared/{preload.d-CLwoXl3R.d.mts → preload.d-BmztUzzG.d.mts} +1 -1
  37. package/dist/packem_shared/{preload.d-Cqb4Kh2I.d.ts → preload.d-DGGRMWB5.d.ts} +1 -1
  38. package/dist/packem_shared/preloadQuery-DjwSjFwt.mjs +1 -0
  39. package/dist/packem_shared/wire-key-D_zOxXK4.mjs +1 -0
  40. package/dist/pagination/index.mjs +1 -61
  41. package/dist/query/index.d.mts +2 -2
  42. package/dist/query/index.d.ts +2 -2
  43. package/dist/query/index.mjs +1 -1
  44. package/dist/ssr/index.d.mts +3 -3
  45. package/dist/ssr/index.d.ts +3 -3
  46. package/dist/ssr/index.mjs +1 -4
  47. package/dist/upload.mjs +1 -24
  48. package/package.json +1 -1
  49. package/dist/packem_shared/CONFLICT_ERROR_CODE-B8gQ8tyU.mjs +0 -33
  50. package/dist/packem_shared/ClientServiceWorker-C3PAFwy0.mjs +0 -100
  51. package/dist/packem_shared/DEFAULT_MAX_BUFFER-7hFnzNk9.mjs +0 -110
  52. package/dist/packem_shared/LunoraClient-DKATLGHY.mjs +0 -3631
  53. package/dist/packem_shared/OfflineQueue-BgarnAub.mjs +0 -1
  54. package/dist/packem_shared/SKIP-vItZChkw.mjs +0 -50
  55. package/dist/packem_shared/SubscriptionRegistry-CxS_Inha.mjs +0 -31
  56. package/dist/packem_shared/TabCoordinator-D_5oNTTt.mjs +0 -258
  57. package/dist/packem_shared/applyDelta-CRKZ1PBt.mjs +0 -81
  58. package/dist/packem_shared/createAsyncStoragePersistence-1Z5BZ8RC.mjs +0 -45
  59. package/dist/packem_shared/createClientQuery-dJZg1ohm.mjs +0 -80
  60. package/dist/packem_shared/createInMemoryBookmarkStorage-BoN7a7TH.mjs +0 -11
  61. package/dist/packem_shared/createInMemoryPersistence-DZ2VHWgm.mjs +0 -79
  62. package/dist/packem_shared/createInMemoryQueryCache-DiaGZkA2.mjs +0 -112
  63. package/dist/packem_shared/createLocalStore-BtqUmOQA.mjs +0 -2
  64. package/dist/packem_shared/createMutationRunner-BqsavzvG.mjs +0 -21
  65. package/dist/packem_shared/createMutatorRunner-BETvCd0p.mjs +0 -31
  66. package/dist/packem_shared/createReconnect-Di_-oHH7.mjs +0 -22
  67. package/dist/packem_shared/createReply-lI4tVS2w.mjs +0 -36
  68. package/dist/packem_shared/createServerClient-Bp2r9tcB.mjs +0 -11
  69. package/dist/packem_shared/createSnapshotPrecondition-CxQ1T4ZP.mjs +0 -18
  70. package/dist/packem_shared/deserializePreloaded-C0eJTY_W.mjs +0 -4
  71. package/dist/packem_shared/getServerSession-8jXewqxd.mjs +0 -13
  72. package/dist/packem_shared/httpStream-DIdL8NEw.mjs +0 -168
  73. package/dist/packem_shared/idb-utility-DrSVX43Q.mjs +0 -48
  74. package/dist/packem_shared/local-store-DIq-UWfD.mjs +0 -106
  75. package/dist/packem_shared/offline-queue-N-1JvYb4.mjs +0 -211
  76. package/dist/packem_shared/preloadQuery-lobFkD2Z.mjs +0 -13
  77. package/dist/packem_shared/wire-key-Djie6aaR.mjs +0 -266
@@ -1 +0,0 @@
1
- export { O as OfflineQueue, n as nextId, r as reportPersistenceError } from './offline-queue-N-1JvYb4.mjs';
@@ -1,50 +0,0 @@
1
- const SKIP = "skip";
2
- const toSubscriptionError = (error) => {
3
- if (error instanceof Error) {
4
- return { message: error.message };
5
- }
6
- return { message: String(error) };
7
- };
8
- const createQuerySubscription = (client, function_, args, sinks, options = {}) => {
9
- if (args === SKIP) {
10
- sinks.onReset?.();
11
- return () => {
12
- };
13
- }
14
- let cancelled = false;
15
- const handleError = (error) => {
16
- if (cancelled) {
17
- return;
18
- }
19
- sinks.onError?.(error);
20
- };
21
- const onError = sinks.onError ? handleError : void 0;
22
- let unsubscribe;
23
- try {
24
- unsubscribe = client.subscribe(
25
- function_,
26
- args,
27
- (value) => {
28
- if (cancelled) {
29
- return;
30
- }
31
- sinks.onData(value);
32
- },
33
- { onError, shardKey: options.shardKey }
34
- );
35
- } catch (error) {
36
- if (!sinks.onError) {
37
- throw error;
38
- }
39
- handleError(toSubscriptionError(error));
40
- return () => {
41
- cancelled = true;
42
- };
43
- }
44
- return () => {
45
- cancelled = true;
46
- unsubscribe();
47
- };
48
- };
49
-
50
- export { SKIP, createQuerySubscription, toSubscriptionError };
@@ -1,31 +0,0 @@
1
- import { s as stableWireKey } from './wire-key-Djie6aaR.mjs';
2
-
3
- class SubscriptionRegistry {
4
- static key(functionPath, args, shardKey) {
5
- return `${functionPath}::${stableWireKey(args)}::${shardKey ?? ""}`;
6
- }
7
- byKey = /* @__PURE__ */ new Map();
8
- byId = /* @__PURE__ */ new Map();
9
- get(key) {
10
- return this.byKey.get(key);
11
- }
12
- getById(id) {
13
- return this.byId.get(id);
14
- }
15
- add(state) {
16
- this.byKey.set(SubscriptionRegistry.key(state.fn.__lunoraRef, state.args, state.shardKey), state);
17
- this.byId.set(state.id, state);
18
- }
19
- remove(state) {
20
- const key = SubscriptionRegistry.key(state.fn.__lunoraRef, state.args, state.shardKey);
21
- if (this.byKey.get(key) === state) {
22
- this.byKey.delete(key);
23
- }
24
- this.byId.delete(state.id);
25
- }
26
- all() {
27
- return [...this.byKey.values()];
28
- }
29
- }
30
-
31
- export { SubscriptionRegistry };
@@ -1,258 +0,0 @@
1
- let nextTabId = 0;
2
- const DEFAULT_CHANNEL = "lunora-bridge";
3
- const DEFAULT_HEARTBEAT_MS = 1e3;
4
- const DEFAULT_LEADER_TIMEOUT_MS = 3e3;
5
- class TabCoordinator {
6
- bc;
7
- tabId;
8
- heartbeatInterval;
9
- leaderTimeout;
10
- /** The tab id of the current known leader, or `undefined` if no leader. */
11
- knownLeader = void 0;
12
- /** `true` when this tab believes it is the leader. */
13
- leader = false;
14
- /** `true` once `start()` has been called. */
15
- running = false;
16
- /** Timestamp of the most recent leader heartbeat. */
17
- lastHeartbeat = 0;
18
- heartbeatTimer = void 0;
19
- leaderCheckTimer = void 0;
20
- /** Callbacks set via constructor options. */
21
- onBecomeLeader;
22
- onStopBeingLeader;
23
- onSubscriptionData;
24
- onSubscriptionError;
25
- constructor(options = {}) {
26
- nextTabId += 1;
27
- this.tabId = `tab_${String(nextTabId)}_${crypto.randomUUID()}`;
28
- this.heartbeatInterval = options.heartbeatInterval ?? DEFAULT_HEARTBEAT_MS;
29
- this.leaderTimeout = options.leaderTimeout ?? DEFAULT_LEADER_TIMEOUT_MS;
30
- this.onBecomeLeader = options.onBecomeLeader;
31
- this.onStopBeingLeader = options.onStopBeingLeader;
32
- this.onSubscriptionData = options.onSubscriptionData;
33
- this.onSubscriptionError = options.onSubscriptionError;
34
- if (typeof BroadcastChannel === "undefined") {
35
- this.bc = void 0;
36
- return;
37
- }
38
- this.bc = new BroadcastChannel(options.channelName ?? DEFAULT_CHANNEL);
39
- this.bc.addEventListener("message", (event) => {
40
- this.handleMessage(event.data);
41
- });
42
- }
43
- // -----------------------------------------------------------------------
44
- // Public API
45
- // -----------------------------------------------------------------------
46
- /**
47
- * Start the coordinator: attempt to claim leadership and begin the
48
- * heartbeat/leader-check cycle. Safe to call multiple times.
49
- */
50
- start() {
51
- if (this.running) {
52
- return;
53
- }
54
- this.running = true;
55
- if (this.bc === void 0) {
56
- this.becomeLeader();
57
- return;
58
- }
59
- this.broadcast({ type: "claim-leadership", tabId: this.tabId, ts: Date.now() });
60
- setTimeout(() => {
61
- if (!this.running) {
62
- return;
63
- }
64
- if (this.knownLeader === void 0) {
65
- this.becomeLeader();
66
- }
67
- }, this.leaderTimeout);
68
- this.leaderCheckTimer = setInterval(() => {
69
- this.checkLeaderHealth();
70
- }, this.leaderTimeout);
71
- this.heartbeatTimer = setInterval(() => {
72
- this.sendHeartbeat();
73
- }, this.heartbeatInterval);
74
- }
75
- /**
76
- * Stop the coordinator: yield leadership (if held), close the channel, and
77
- * clear all timers. Safe to call multiple times.
78
- */
79
- stop() {
80
- this.running = false;
81
- if (this.leader) {
82
- this.broadcast({ type: "yield-leadership", tabId: this.tabId });
83
- this.leader = false;
84
- this.knownLeader = void 0;
85
- this.onStopBeingLeader?.();
86
- }
87
- if (this.heartbeatTimer !== void 0) {
88
- clearInterval(this.heartbeatTimer);
89
- this.heartbeatTimer = void 0;
90
- }
91
- if (this.leaderCheckTimer !== void 0) {
92
- clearInterval(this.leaderCheckTimer);
93
- this.leaderCheckTimer = void 0;
94
- }
95
- this.bc?.close();
96
- }
97
- /** `true` when this tab is the current WebSocket leader. */
98
- isLeader() {
99
- return this.leader;
100
- }
101
- /** The tab id of the current leader, or `undefined` if unknown / no leader. */
102
- get leaderTabId() {
103
- return this.knownLeader;
104
- }
105
- /** The id of this tab. */
106
- get id() {
107
- return this.tabId;
108
- }
109
- /** `true` when the coordinator has been started and is not yet stopped. */
110
- get isRunning() {
111
- return this.running;
112
- }
113
- // -----------------------------------------------------------------------
114
- // Broadcasting
115
- // -----------------------------------------------------------------------
116
- /**
117
- * Broadcast subscription data to all follower tabs. Only the leader should
118
- * call this.
119
- */
120
- broadcastSubscriptionData(key, data) {
121
- if (!this.leader) {
122
- return;
123
- }
124
- this.broadcast({ type: "subscription-data", tabId: this.tabId, key, data });
125
- }
126
- /**
127
- * Broadcast a subscription error to all follower tabs. Only the leader
128
- * should call this.
129
- */
130
- broadcastSubscriptionError(key, error) {
131
- if (!this.leader) {
132
- return;
133
- }
134
- this.broadcast({ type: "subscription-error", tabId: this.tabId, key, error });
135
- }
136
- // -----------------------------------------------------------------------
137
- // Internal
138
- // -----------------------------------------------------------------------
139
- broadcast(message) {
140
- this.bc?.postMessage(message);
141
- }
142
- handleMessage(message) {
143
- switch (message.type) {
144
- case "claim-leadership": {
145
- this.handleClaimLeadership(message);
146
- break;
147
- }
148
- case "heartbeat": {
149
- this.handleHeartbeat(message);
150
- break;
151
- }
152
- case "subscription-data": {
153
- if (this.leader || message.tabId === this.tabId) {
154
- break;
155
- }
156
- this.onSubscriptionData?.(message.key, message.data);
157
- break;
158
- }
159
- case "subscription-error": {
160
- if (this.leader || message.tabId === this.tabId) {
161
- break;
162
- }
163
- this.onSubscriptionError?.(message.key, message.error);
164
- break;
165
- }
166
- case "yield-leadership": {
167
- if (this.knownLeader === message.tabId) {
168
- this.knownLeader = void 0;
169
- }
170
- break;
171
- }
172
- }
173
- }
174
- handleClaimLeadership(message) {
175
- if (message.tabId === this.tabId) {
176
- return;
177
- }
178
- if (this.leader) {
179
- this.broadcast({ type: "heartbeat", tabId: this.tabId, ts: Date.now() });
180
- return;
181
- }
182
- if (this.knownLeader === void 0 && message.tabId < this.tabId) {
183
- this.knownLeader = message.tabId;
184
- this.lastHeartbeat = message.ts;
185
- }
186
- }
187
- handleHeartbeat(message) {
188
- if (message.tabId === this.tabId) {
189
- return;
190
- }
191
- if (this.leader) {
192
- this.resolveLeaderVsLeaderTieBreak(message);
193
- return;
194
- }
195
- this.lastHeartbeat = message.ts;
196
- this.knownLeader = message.tabId;
197
- }
198
- /**
199
- * Resolve two leaders existing at once — e.g. this tab was backgrounded
200
- * and its heartbeat/health timers were throttled while a foreground
201
- * follower's were not, so the follower's `checkLeaderHealth` timed out
202
- * the (still-alive) leader and self-promoted. `BroadcastChannel` message
203
- * delivery isn't subject to the same timer-throttling clamp, so even a
204
- * backgrounded leader eventually observes the pretender's heartbeat here
205
- * — resolve the split-brain deterministically with the same
206
- * lexicographically-smaller-tabId rule used at claim-adoption. If the
207
- * other tab wins, step down; if we win, reassert immediately so the
208
- * pretender demotes itself the moment it processes our heartbeat.
209
- */
210
- resolveLeaderVsLeaderTieBreak(message) {
211
- if (message.tabId < this.tabId) {
212
- this.leader = false;
213
- this.knownLeader = message.tabId;
214
- this.lastHeartbeat = message.ts;
215
- this.onStopBeingLeader?.();
216
- } else {
217
- this.broadcast({ type: "heartbeat", tabId: this.tabId, ts: Date.now() });
218
- }
219
- }
220
- becomeLeader() {
221
- if (this.leader) {
222
- return;
223
- }
224
- this.leader = true;
225
- this.knownLeader = this.tabId;
226
- this.lastHeartbeat = Date.now();
227
- this.onBecomeLeader?.();
228
- this.broadcast({ type: "heartbeat", tabId: this.tabId, ts: Date.now() });
229
- }
230
- sendHeartbeat() {
231
- if (!this.leader) {
232
- return;
233
- }
234
- this.broadcast({ type: "heartbeat", tabId: this.tabId, ts: Date.now() });
235
- }
236
- checkLeaderHealth() {
237
- if (!this.running) {
238
- return;
239
- }
240
- if (this.leader) {
241
- return;
242
- }
243
- if (this.knownLeader !== void 0) {
244
- const elapsed = Date.now() - this.lastHeartbeat;
245
- if (elapsed > this.leaderTimeout) {
246
- this.knownLeader = void 0;
247
- this.broadcast({ type: "claim-leadership", tabId: this.tabId, ts: Date.now() });
248
- setTimeout(() => {
249
- if (this.running && this.knownLeader === void 0) {
250
- this.becomeLeader();
251
- }
252
- }, this.leaderTimeout);
253
- }
254
- }
255
- }
256
- }
257
-
258
- export { TabCoordinator };
@@ -1,81 +0,0 @@
1
- const ID_FIELD = "_id";
2
- const CREATION_FIELD = "_creationTime";
3
- const rowId = (row) => {
4
- if (typeof row !== "object" || row === null) {
5
- return void 0;
6
- }
7
- const id = row[ID_FIELD];
8
- return typeof id === "string" ? id : void 0;
9
- };
10
- const isDescending = (list) => {
11
- let previous;
12
- for (const existingRow of list) {
13
- const existing = existingRow[CREATION_FIELD];
14
- if (typeof existing !== "number") {
15
- continue;
16
- }
17
- if (previous !== void 0) {
18
- if (existing < previous) {
19
- return true;
20
- }
21
- if (existing > previous) {
22
- return false;
23
- }
24
- }
25
- previous = existing;
26
- }
27
- return false;
28
- };
29
- const insertionIndex = (list, row) => {
30
- const creation = row[CREATION_FIELD];
31
- if (typeof creation !== "number") {
32
- return list.length;
33
- }
34
- const descending = isDescending(list);
35
- for (const [index, existingRow] of list.entries()) {
36
- const existing = existingRow[CREATION_FIELD];
37
- if (typeof existing === "number" && (descending ? existing < creation : existing > creation)) {
38
- return index;
39
- }
40
- }
41
- return list.length;
42
- };
43
- const isMutationDelta = (value) => {
44
- if (typeof value !== "object" || value === null) {
45
- return false;
46
- }
47
- const candidate = value;
48
- return typeof candidate["key"] === "string" && typeof candidate["table"] === "string" && (candidate["op"] === "insert" || candidate["op"] === "update" || candidate["op"] === "delete");
49
- };
50
- const applyDelta = (current, delta) => {
51
- if (!Array.isArray(current)) {
52
- return void 0;
53
- }
54
- const rows = [];
55
- for (const element of current) {
56
- const id = rowId(element);
57
- if (id === void 0) {
58
- return void 0;
59
- }
60
- rows.push(element);
61
- }
62
- const { key, op, row } = delta;
63
- if (op === "delete") {
64
- const next2 = rows.filter((existing) => existing[ID_FIELD] !== key);
65
- return next2.length === rows.length ? [...rows] : next2;
66
- }
67
- if (row === void 0) {
68
- return void 0;
69
- }
70
- const existingIndex = rows.findIndex((existing) => existing[ID_FIELD] === key);
71
- if (existingIndex === -1) {
72
- const next2 = [...rows];
73
- next2.splice(insertionIndex(rows, row), 0, row);
74
- return next2;
75
- }
76
- const next = [...rows];
77
- next[existingIndex] = row;
78
- return next;
79
- };
80
-
81
- export { applyDelta, isMutationDelta };
@@ -1,45 +0,0 @@
1
- const DEFAULT_KEY = "lunora:offline-mutations";
2
- const createAsyncStoragePersistence = (options) => {
3
- const { storage } = options;
4
- const key = options.key ?? DEFAULT_KEY;
5
- let chain = Promise.resolve();
6
- const serialize = (run) => {
7
- const next = chain.then(run, run);
8
- chain = next.then(
9
- () => void 0,
10
- () => void 0
11
- );
12
- return next;
13
- };
14
- const readAll = async () => {
15
- const raw = await storage.getItem(key);
16
- if (raw === null) {
17
- return [];
18
- }
19
- try {
20
- const parsed = JSON.parse(raw);
21
- return Array.isArray(parsed) ? parsed : [];
22
- } catch {
23
- return [];
24
- }
25
- };
26
- const writeAll = (mutations) => storage.setItem(key, JSON.stringify(mutations));
27
- return {
28
- append: (mutation) => serialize(async () => {
29
- const mutations = await readAll();
30
- mutations.push(mutation);
31
- await writeAll(mutations);
32
- }),
33
- clear: () => serialize(() => storage.removeItem(key)),
34
- load: () => serialize(readAll),
35
- remove: (id) => serialize(async () => {
36
- const mutations = await readAll();
37
- const remaining = mutations.filter((mutation) => mutation.id !== id);
38
- if (remaining.length !== mutations.length) {
39
- await writeAll(remaining);
40
- }
41
- })
42
- };
43
- };
44
-
45
- export { createAsyncStoragePersistence };
@@ -1,80 +0,0 @@
1
- class ClientQueryStore {
2
- /** Current values, keyed by the ref's stable key. Absent = never set. */
3
- values = /* @__PURE__ */ new Map();
4
- /** Subscribers keyed by ref key — notified on every set. */
5
- subscribers = /* @__PURE__ */ new Map();
6
- /**
7
- * Return the current value for `ref`, or `ref.defaultValue` if none has
8
- * been set explicitly. Returns `ref.defaultValue` when the slot has been
9
- * set to `undefined` (which is distinct from "never set").
10
- */
11
- get(ref) {
12
- if (this.values.has(ref.key)) {
13
- return this.values.get(ref.key);
14
- }
15
- return ref.defaultValue;
16
- }
17
- /**
18
- * Set a new value for `ref` and notify every subscriber. Pass `undefined`
19
- * to reset the slot to `ref.defaultValue` — delegates to {@link reset} so
20
- * `get` reports the default rather than a stored `undefined`.
21
- */
22
- set(ref, value) {
23
- if (value === void 0) {
24
- this.reset(ref);
25
- return;
26
- }
27
- this.values.set(ref.key, value);
28
- this.notify(ref.key, value);
29
- }
30
- /**
31
- * Delete the stored value for `ref`, resetting to `ref.defaultValue` and
32
- * notifying subscribers.
33
- */
34
- reset(ref) {
35
- this.values.delete(ref.key);
36
- this.notify(ref.key, ref.defaultValue);
37
- }
38
- /**
39
- * Subscribe to changes for `ref`. The callback is NOT invoked on
40
- * registration — callers should read the current value via
41
- * {@link get} first. Returns an unsubscribe function.
42
- */
43
- subscribe(ref, callback) {
44
- let subs = this.subscribers.get(ref.key);
45
- if (!subs) {
46
- subs = /* @__PURE__ */ new Set();
47
- this.subscribers.set(ref.key, subs);
48
- }
49
- subs.add(callback);
50
- return () => {
51
- subs.delete(callback);
52
- if (subs.size === 0) {
53
- this.subscribers.delete(ref.key);
54
- }
55
- };
56
- }
57
- /**
58
- * Notify every subscriber of a value change for the given key with the
59
- * resolved value — the caller passes the just-stored value on `set` or
60
- * `ref.defaultValue` on `reset`, so a subscriber always sees the same value
61
- * {@link get} would return (never a stale re-read after the store mutation).
62
- */
63
- notify(key, value) {
64
- const subs = this.subscribers.get(key);
65
- if (!subs) {
66
- return;
67
- }
68
- for (const callback of subs) {
69
- try {
70
- callback(value);
71
- } catch {
72
- }
73
- }
74
- }
75
- }
76
- const createClientQuery = (key, defaultValue) => {
77
- return { defaultValue, key };
78
- };
79
-
80
- export { ClientQueryStore, createClientQuery };
@@ -1,11 +0,0 @@
1
- const createInMemoryBookmarkStorage = () => {
2
- let value = null;
3
- return {
4
- get: () => value,
5
- set: (next) => {
6
- value = next;
7
- }
8
- };
9
- };
10
-
11
- export { createInMemoryBookmarkStorage as default };
@@ -1,79 +0,0 @@
1
- import { LunoraError } from '@lunora/errors';
2
- import { p as promisifyRequest, c as createWithStore, a as createDatabaseOpener } from './idb-utility-DrSVX43Q.mjs';
3
-
4
- const createInMemoryPersistence = () => {
5
- const entries = /* @__PURE__ */ new Map();
6
- const clone = (mutation) => {
7
- return {
8
- args: { ...mutation.args },
9
- functionPath: mutation.functionPath,
10
- id: mutation.id,
11
- identity: mutation.identity,
12
- shardKey: mutation.shardKey
13
- };
14
- };
15
- return {
16
- append: (mutation) => {
17
- entries.set(mutation.id, clone(mutation));
18
- return Promise.resolve();
19
- },
20
- clear: () => {
21
- entries.clear();
22
- return Promise.resolve();
23
- },
24
- load: () => Promise.resolve([...entries.values()].map((mutation) => clone(mutation))),
25
- remove: (id) => {
26
- entries.delete(id);
27
- return Promise.resolve();
28
- }
29
- };
30
- };
31
- const DEFAULT_DATABASE = "lunora-outbox";
32
- const DEFAULT_STORE = "offline-mutations";
33
- const ID_INDEX = "by_id";
34
- const createIndexedDbPersistence = (options = {}) => {
35
- const factory = options.indexedDB ?? (typeof indexedDB === "undefined" ? void 0 : indexedDB);
36
- if (!factory) {
37
- throw new LunoraError("INTERNAL", "createIndexedDbPersistence: no IndexedDB available — pass `indexedDB` or use createInMemoryPersistence()");
38
- }
39
- const databaseName = options.databaseName ?? DEFAULT_DATABASE;
40
- const storeName = options.storeName ?? DEFAULT_STORE;
41
- const openDatabase = createDatabaseOpener(factory, databaseName, 1, (database) => {
42
- if (!database.objectStoreNames.contains(storeName)) {
43
- const store = database.createObjectStore(storeName, { autoIncrement: true });
44
- store.createIndex(ID_INDEX, "id", { unique: true });
45
- }
46
- });
47
- const withStore = createWithStore(openDatabase, storeName);
48
- return {
49
- append: async (mutation) => {
50
- await withStore("readwrite", (store) => promisifyRequest(store.add(mutation)));
51
- },
52
- clear: async () => {
53
- await withStore("readwrite", (store) => promisifyRequest(store.clear()));
54
- },
55
- load: async () => withStore("readonly", (store) => promisifyRequest(store.getAll())),
56
- remove: async (id) => {
57
- await withStore("readwrite", async (store) => {
58
- const key = await promisifyRequest(store.index(ID_INDEX).getKey(id));
59
- if (key !== void 0) {
60
- await promisifyRequest(store.delete(key));
61
- }
62
- });
63
- }
64
- };
65
- };
66
- const resolvePersistenceAdapter = (option, autoProbe = true) => {
67
- if (option === false) {
68
- return void 0;
69
- }
70
- if (option) {
71
- return option;
72
- }
73
- if (!autoProbe || typeof indexedDB === "undefined") {
74
- return void 0;
75
- }
76
- return createIndexedDbPersistence();
77
- };
78
-
79
- export { createInMemoryPersistence, createIndexedDbPersistence, resolvePersistenceAdapter };