@gonvex/client 0.1.30 → 0.1.32

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.
@@ -0,0 +1,447 @@
1
+ import { defaultQueryCacheMaxAgeMs, defaultQueryCacheMaxBytes, defaultQueryCacheMaxBytesPerScope, defaultQueryCacheMaxEntriesPerScope, defaultQueryCacheMaxEntryBytes, } from "./query-cache.js";
2
+ import { defaultSyncStoreMaxBytes, } from "./sync-store.js";
3
+ export const kvQueryCacheTable = "query_cache";
4
+ export const kvSyncCollectionTable = "sync_collections";
5
+ export const kvSyncDirectiveTable = "sync_directives";
6
+ export const kvMutationOutboxTable = "mutation_outbox";
7
+ /** An in-memory {@link GonvexKv} for tests and ephemeral sessions. */
8
+ export function createMemoryGonvexKv() {
9
+ const tables = new Map();
10
+ const table = (name) => {
11
+ let rows = tables.get(name);
12
+ if (!rows) {
13
+ rows = new Map();
14
+ tables.set(name, rows);
15
+ }
16
+ return rows;
17
+ };
18
+ return {
19
+ async get(name, key) {
20
+ return table(name).get(key);
21
+ },
22
+ async set(name, key, value) {
23
+ table(name).set(key, value);
24
+ },
25
+ async delete(name, key) {
26
+ table(name).delete(key);
27
+ },
28
+ async list(name) {
29
+ return [...table(name).entries()].map(([key, value]) => ({ key, value }));
30
+ },
31
+ async clear(name, keyPrefix) {
32
+ const rows = table(name);
33
+ if (!keyPrefix) {
34
+ rows.clear();
35
+ return;
36
+ }
37
+ for (const key of [...rows.keys()]) {
38
+ if (key.startsWith(keyPrefix))
39
+ rows.delete(key);
40
+ }
41
+ },
42
+ };
43
+ }
44
+ /**
45
+ * A {@link QueryCacheStore} over an injected {@link GonvexKv}. Records are
46
+ * keyed by `scope\u0000path\u0000stableArgs`, revision-guarded like the Dexie
47
+ * store, and LRU-evicted by `lastAccessedAt` against per-scope and global
48
+ * caps. A failing backend permanently disables the cache for the session;
49
+ * server data remains authoritative.
50
+ */
51
+ export function createKvQueryCacheStore(kv, options = {}) {
52
+ const maxAgeMs = positive(options.maxAgeMs, defaultQueryCacheMaxAgeMs);
53
+ const maxEntryBytes = positive(options.maxEntryBytes, defaultQueryCacheMaxEntryBytes);
54
+ const limits = {
55
+ maxEntriesPerScope: positive(options.maxEntriesPerScope, defaultQueryCacheMaxEntriesPerScope),
56
+ maxBytesPerScope: positive(options.maxBytesPerScope, defaultQueryCacheMaxBytesPerScope),
57
+ maxBytes: positive(options.maxBytes, defaultQueryCacheMaxBytes),
58
+ };
59
+ const onScope = options.onScope;
60
+ let lastEmittedScope;
61
+ let readsEnabled = true;
62
+ let writesEnabled = true;
63
+ let disabledReason;
64
+ const disable = (reason) => {
65
+ readsEnabled = false;
66
+ writesEnabled = false;
67
+ disabledReason = reason;
68
+ };
69
+ return {
70
+ async read(scope, path, args, ageMs = maxAgeMs) {
71
+ if (!readsEnabled || !scope)
72
+ return undefined;
73
+ try {
74
+ const key = storageKey(scope, path, args);
75
+ const record = parseJson(await kv.get(kvQueryCacheTable, key));
76
+ if (!record)
77
+ return undefined;
78
+ const now = Date.now();
79
+ if (now - record.writtenAt > Math.min(ageMs, maxAgeMs)) {
80
+ await kv.delete(kvQueryCacheTable, key);
81
+ return undefined;
82
+ }
83
+ record.lastAccessedAt = now;
84
+ await kv.set(kvQueryCacheTable, key, JSON.stringify(record));
85
+ return {
86
+ result: record.result,
87
+ revision: record.revision,
88
+ writtenAt: record.writtenAt,
89
+ ageMs: now - record.writtenAt,
90
+ };
91
+ }
92
+ catch (error) {
93
+ disable(errorReason(error, "kv-query-cache-read-failed"));
94
+ return undefined;
95
+ }
96
+ },
97
+ async write(value) {
98
+ if (!writesEnabled || !value.scope || !value.revision)
99
+ return "disabled";
100
+ try {
101
+ const sizeBytes = jsonSize(value.result);
102
+ if (sizeBytes > maxEntryBytes)
103
+ return "oversize";
104
+ const key = storageKey(value.scope, value.path, value.args);
105
+ const existing = parseJson(await kv.get(kvQueryCacheTable, key));
106
+ if (existing && existing.revision >= value.revision)
107
+ return "older";
108
+ const now = Date.now();
109
+ const record = {
110
+ scope: value.scope,
111
+ path: value.path,
112
+ result: value.result,
113
+ revision: value.revision,
114
+ writtenAt: now,
115
+ lastAccessedAt: now,
116
+ sizeBytes,
117
+ };
118
+ await kv.set(kvQueryCacheTable, key, JSON.stringify(record));
119
+ await evictQueryCache(kv, limits);
120
+ if (onScope && lastEmittedScope !== value.scope) {
121
+ lastEmittedScope = value.scope;
122
+ await onScope(value.scope);
123
+ }
124
+ return "written";
125
+ }
126
+ catch (error) {
127
+ disable(errorReason(error, "kv-query-cache-write-failed"));
128
+ return "error";
129
+ }
130
+ },
131
+ async delete(scope, path, args) {
132
+ try {
133
+ await kv.delete(kvQueryCacheTable, storageKey(scope, path, args));
134
+ }
135
+ catch {
136
+ // Cache deletion is best-effort; server data remains authoritative.
137
+ }
138
+ },
139
+ async clear(scope) {
140
+ try {
141
+ await kv.clear(kvQueryCacheTable, scope ? `${scope}\u0000` : undefined);
142
+ }
143
+ catch {
144
+ // Clearing a disposable cache must not affect the application.
145
+ }
146
+ },
147
+ status() {
148
+ return {
149
+ enabled: readsEnabled || writesEnabled,
150
+ readsEnabled,
151
+ writesEnabled,
152
+ reason: disabledReason,
153
+ };
154
+ },
155
+ close() {
156
+ // The KV connection belongs to the host and outlives this store.
157
+ },
158
+ };
159
+ }
160
+ async function evictQueryCache(kv, limits) {
161
+ const rows = [];
162
+ const corrupt = [];
163
+ for (const { key, value } of await kv.list(kvQueryCacheTable)) {
164
+ const record = parseJson(value);
165
+ if (record)
166
+ rows.push({ key, record });
167
+ else
168
+ corrupt.push(key);
169
+ }
170
+ rows.sort((left, right) => left.record.lastAccessedAt - right.record.lastAccessedAt);
171
+ const byScope = new Map();
172
+ for (const row of rows) {
173
+ const list = byScope.get(row.record.scope) ?? [];
174
+ list.push(row);
175
+ byScope.set(row.record.scope, list);
176
+ }
177
+ const evict = new Set(corrupt);
178
+ let totalBytes = 0;
179
+ for (const list of byScope.values()) {
180
+ let scopeBytes = 0;
181
+ let scopeCount = 0;
182
+ // Newest first: eviction always drops the least recently used entries.
183
+ for (let index = list.length - 1; index >= 0; index -= 1) {
184
+ const row = list[index];
185
+ if (scopeCount >= limits.maxEntriesPerScope
186
+ || scopeBytes + row.record.sizeBytes > limits.maxBytesPerScope) {
187
+ evict.add(row.key);
188
+ continue;
189
+ }
190
+ scopeCount += 1;
191
+ scopeBytes += row.record.sizeBytes;
192
+ totalBytes += row.record.sizeBytes;
193
+ }
194
+ }
195
+ for (const row of rows) {
196
+ if (totalBytes <= limits.maxBytes)
197
+ break;
198
+ if (evict.has(row.key))
199
+ continue;
200
+ evict.add(row.key);
201
+ totalBytes -= row.record.sizeBytes;
202
+ }
203
+ for (const key of evict)
204
+ await kv.delete(kvQueryCacheTable, key);
205
+ }
206
+ /**
207
+ * A {@link SyncStore} over an injected {@link GonvexKv}. Each collection is
208
+ * one record holding its rows, cursor, and metadata; deltas are applied by
209
+ * key against the stored rows. Collections are LRU-evicted by
210
+ * `lastAccessedAt` once the table exceeds `maxBytes`. A failing backend
211
+ * permanently disables the store for the session.
212
+ */
213
+ export function createKvSyncStore(kv, options = {}) {
214
+ const maxBytes = positive(options.maxBytes, defaultSyncStoreMaxBytes);
215
+ let disabled = false;
216
+ const loadRecord = async (key) => parseJson(await kv.get(kvSyncCollectionTable, key));
217
+ const persist = async (key, value) => {
218
+ const record = {
219
+ ...value,
220
+ rowsUnchanged: undefined,
221
+ lastAccessedAt: Date.now(),
222
+ sizeBytes: jsonSize(value.rows),
223
+ };
224
+ await kv.set(kvSyncCollectionTable, key, JSON.stringify(record));
225
+ await evictSyncCollections(kv, maxBytes);
226
+ };
227
+ return {
228
+ async load(scope, path, args) {
229
+ if (disabled || !scope)
230
+ return undefined;
231
+ try {
232
+ const key = storageKey(scope, path, args);
233
+ const record = await loadRecord(key);
234
+ if (!record)
235
+ return undefined;
236
+ record.lastAccessedAt = Date.now();
237
+ await kv.set(kvSyncCollectionTable, key, JSON.stringify(record));
238
+ const { lastAccessedAt: _lastAccessedAt, sizeBytes: _sizeBytes, ...collection } = record;
239
+ return collection;
240
+ }
241
+ catch {
242
+ disabled = true;
243
+ return undefined;
244
+ }
245
+ },
246
+ async replace(scope, path, args, value) {
247
+ if (disabled || !scope)
248
+ return;
249
+ try {
250
+ const key = storageKey(scope, path, args);
251
+ if (value.rowsUnchanged) {
252
+ const existing = await loadRecord(key);
253
+ // The caller proved the rows are byte-identical, so only advance
254
+ // the cursor/metadata. A missing record falls through to a full
255
+ // write.
256
+ if (existing) {
257
+ await persist(key, {
258
+ ...existing,
259
+ cursor: value.cursor,
260
+ keyField: value.keyField,
261
+ mode: value.mode,
262
+ truncated: value.truncated,
263
+ orderBy: value.orderBy,
264
+ orderDirection: value.orderDirection,
265
+ maxRows: value.maxRows,
266
+ maxBytes: value.maxBytes,
267
+ hashes: value.hashes,
268
+ });
269
+ return;
270
+ }
271
+ }
272
+ await persist(key, value);
273
+ }
274
+ catch {
275
+ disabled = true;
276
+ }
277
+ },
278
+ async applyDelta(scope, path, args, value) {
279
+ if (disabled || !scope)
280
+ return;
281
+ try {
282
+ const key = storageKey(scope, path, args);
283
+ const existing = await loadRecord(key);
284
+ const keyField = value.keyField || existing?.keyField || "_id";
285
+ const deleted = new Set(value.deleted.map(String));
286
+ const kept = (existing?.rows ?? []).filter((row) => !deleted.has(rowKey(row, keyField)));
287
+ const byKey = new Map(kept.map((row) => [rowKey(row, keyField), row]));
288
+ for (const upsert of value.upserts) {
289
+ const id = rowKey(upsert, keyField);
290
+ if (!id)
291
+ continue;
292
+ byKey.set(id, upsert);
293
+ }
294
+ await persist(key, {
295
+ rows: [...byKey.values()],
296
+ cursor: value.cursor,
297
+ keyField,
298
+ mode: value.mode ?? existing?.mode,
299
+ truncated: value.truncated,
300
+ orderBy: value.orderBy ?? existing?.orderBy,
301
+ orderDirection: value.orderDirection ?? existing?.orderDirection,
302
+ maxRows: value.maxRows ?? existing?.maxRows,
303
+ maxBytes: value.maxBytes ?? existing?.maxBytes,
304
+ hashes: value.hashes ?? existing?.hashes,
305
+ });
306
+ }
307
+ catch {
308
+ disabled = true;
309
+ }
310
+ },
311
+ async delete(scope, path, args) {
312
+ try {
313
+ await kv.delete(kvSyncCollectionTable, storageKey(scope, path, args));
314
+ }
315
+ catch {
316
+ // Disposable local data must never break the application.
317
+ }
318
+ },
319
+ async loadDirective(identity) {
320
+ if (!identity)
321
+ return undefined;
322
+ try {
323
+ return parseJson(await kv.get(kvSyncDirectiveTable, identity));
324
+ }
325
+ catch {
326
+ return undefined;
327
+ }
328
+ },
329
+ async saveDirective(identity, directive) {
330
+ if (!identity)
331
+ return;
332
+ try {
333
+ await kv.set(kvSyncDirectiveTable, identity, JSON.stringify(directive));
334
+ }
335
+ catch {
336
+ // Warm-start metadata is an optimization, never a request prerequisite.
337
+ }
338
+ },
339
+ async clear(scope) {
340
+ try {
341
+ await kv.clear(kvSyncCollectionTable, scope ? `${scope}\u0000` : undefined);
342
+ if (!scope)
343
+ await kv.clear(kvSyncDirectiveTable);
344
+ }
345
+ catch {
346
+ // Disposable local data must never break the application.
347
+ }
348
+ },
349
+ close() {
350
+ // The KV connection belongs to the host and outlives this store.
351
+ },
352
+ };
353
+ }
354
+ async function evictSyncCollections(kv, maxBytes) {
355
+ const rows = [];
356
+ for (const { key, value } of await kv.list(kvSyncCollectionTable)) {
357
+ const record = parseJson(value);
358
+ if (record)
359
+ rows.push({ key, record });
360
+ else
361
+ await kv.delete(kvSyncCollectionTable, key);
362
+ }
363
+ rows.sort((left, right) => left.record.lastAccessedAt - right.record.lastAccessedAt);
364
+ let total = rows.reduce((sum, row) => sum + (row.record.sizeBytes || 0), 0);
365
+ for (const row of rows) {
366
+ if (total <= maxBytes)
367
+ break;
368
+ await kv.delete(kvSyncCollectionTable, row.key);
369
+ total -= row.record.sizeBytes || 0;
370
+ }
371
+ }
372
+ /**
373
+ * An {@link OutboxStore} over an injected {@link GonvexKv}. Entries are
374
+ * whole JSON records keyed by their queue id; ordering, causal barriers, and
375
+ * inflight recovery stay in {@link StoreMutationOutbox}.
376
+ */
377
+ export function createKvOutboxStore(kv) {
378
+ return {
379
+ async load() {
380
+ const entries = [];
381
+ for (const { value } of await kv.list(kvMutationOutboxTable)) {
382
+ // A corrupt row must not strand every other queued mutation.
383
+ const entry = parseJson(value);
384
+ if (entry && typeof entry.id === "number")
385
+ entries.push(entry);
386
+ }
387
+ return entries.sort((left, right) => left.id - right.id);
388
+ },
389
+ async put(entry) {
390
+ await kv.set(kvMutationOutboxTable, String(entry.id), JSON.stringify(entry));
391
+ },
392
+ async delete(id) {
393
+ await kv.delete(kvMutationOutboxTable, String(id));
394
+ },
395
+ async clear(scope) {
396
+ if (scope === undefined) {
397
+ await kv.clear(kvMutationOutboxTable);
398
+ return;
399
+ }
400
+ for (const { key, value } of await kv.list(kvMutationOutboxTable)) {
401
+ if (parseJson(value)?.scope === scope) {
402
+ await kv.delete(kvMutationOutboxTable, key);
403
+ }
404
+ }
405
+ },
406
+ };
407
+ }
408
+ function storageKey(scope, path, args) {
409
+ return `${scope}\u0000${path}\u0000${stableStringify(args ?? {})}`;
410
+ }
411
+ function stableStringify(value) {
412
+ if (value === null || typeof value !== "object")
413
+ return JSON.stringify(value);
414
+ if (Array.isArray(value))
415
+ return `[${value.map(stableStringify).join(",")}]`;
416
+ const record = value;
417
+ return `{${Object.keys(record)
418
+ .sort()
419
+ .map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`)
420
+ .join(",")}}`;
421
+ }
422
+ function parseJson(value) {
423
+ if (value === undefined)
424
+ return undefined;
425
+ try {
426
+ return JSON.parse(value);
427
+ }
428
+ catch {
429
+ return undefined;
430
+ }
431
+ }
432
+ function rowKey(row, keyField) {
433
+ if (!row || Array.isArray(row) || typeof row !== "object")
434
+ return "";
435
+ const candidate = row[keyField];
436
+ return typeof candidate === "string" || typeof candidate === "number" ? String(candidate) : "";
437
+ }
438
+ function jsonSize(value) {
439
+ return new TextEncoder().encode(JSON.stringify(value ?? null)).byteLength;
440
+ }
441
+ function errorReason(error, fallback) {
442
+ return error instanceof Error ? error.message || error.name : fallback;
443
+ }
444
+ function positive(value, fallback) {
445
+ return value !== undefined && Number.isFinite(value) && value > 0 ? value : fallback;
446
+ }
447
+ //# sourceMappingURL=kv-stores.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kv-stores.js","sourceRoot":"","sources":["../src/kv-stores.ts"],"names":[],"mappings":"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"}
@@ -1,41 +1,73 @@
1
1
  export type Row = Record<string, unknown>;
2
+ export type OptimisticProjection = {
3
+ entity: string;
4
+ key: string;
5
+ resultPath: readonly string[];
6
+ };
7
+ export type OptimisticMutationDefinition = {
8
+ entity: string;
9
+ rowIdPath: readonly string[];
10
+ fieldsPath: readonly string[];
11
+ };
2
12
  type OptimisticRowPatch = {
3
- collection: string;
13
+ /** Canonical entity/table name. `collection` remains a compatibility alias. */
14
+ entity?: string;
15
+ collection?: string;
4
16
  rowId: string;
5
17
  op: "patch" | "insert";
6
18
  fields: Record<string, unknown>;
7
19
  };
8
20
  type OptimisticDeletePatch = {
9
- collection: string;
21
+ entity?: string;
22
+ collection?: string;
10
23
  rowId: string;
11
24
  op: "delete";
12
25
  fields?: never;
13
26
  };
14
27
  export type OptimisticPatch = OptimisticRowPatch | OptimisticDeletePatch;
15
28
  /**
16
- * An ordered, in-memory view of mutations that have not settled yet.
29
+ * Ordered pending entity mutations layered over immutable authoritative data.
17
30
  *
18
- * Authoritative sync rows remain untouched. Consumers materialize this overlay
19
- * at read time, so rejecting an entry simply reveals the current server state.
31
+ * A source is one concrete sync/query subscription (including its arguments).
32
+ * Successful mutations remain pending until every source that exposed the
33
+ * optimistic row reports that mutation id in an authoritative update. This
34
+ * prevents a fast RPC acknowledgement from revealing an older subscription
35
+ * snapshot while its invalidation is still in flight.
20
36
  */
21
37
  export declare class OptimisticOverlay {
22
38
  private readonly entries;
23
39
  private readonly listeners;
24
40
  private readonly cache;
25
41
  private version;
26
- /** Append a mutation's patches after every currently pending mutation. */
27
- add(mutationId: string, patches: OptimisticPatch[]): void;
28
- /** Remove patches after a successful authoritative server result. */
42
+ private settling;
43
+ add(mutationId: string, patches: OptimisticPatch[], options?: {
44
+ accepted?: boolean;
45
+ }): void;
46
+ /** Reserve a live projection even when its first snapshot is still pending. */
47
+ expectSource(source: string, entity: string): void;
48
+ /** Mark the transport result successful without dropping visible optimism. */
49
+ accept(mutationId: string): string[];
50
+ /** Compatibility alias. Prefer accept followed by authoritative acknowledge. */
29
51
  settle(mutationId: string): void;
30
52
  /** Remove patches after a deterministic server rejection. */
31
53
  reject(mutationId: string): void;
32
- /** Materialize one collection without mutating its authoritative rows. */
33
- apply(collection: string, rows: readonly Row[], keyField: string): Row[];
34
- /** Subscribe to collections whose materialized rows may have changed. */
35
- subscribe(listener: (collection: string) => void): () => void;
36
- /** Whether any pending mutation touches this collection row. */
37
- pendingFor(collection: string, rowId: string): boolean;
54
+ /**
55
+ * Materialize entity rows for a concrete source. The three-argument overload
56
+ * preserves the original collection-path API by using the entity as source.
57
+ */
58
+ apply(entity: string, rows: readonly Row[], keyField: string): Row[];
59
+ apply(source: string, entity: string, rows: readonly Row[], keyField: string): Row[];
60
+ /** Record authoritative delivery for a source; returns fully reconciled ids. */
61
+ acknowledge(source: string, mutationIds: readonly string[] | undefined): string[];
62
+ /** Reconcile restored committed entries against an authoritative snapshot. */
63
+ acknowledgeMatching(source: string, entity: string, rows: readonly Row[], keyField: string): string[];
64
+ /** Stop waiting for a subscription that no longer exists. */
65
+ removeSource(source: string): string[];
66
+ subscribe(listener: (entity: string) => void): () => void;
67
+ pendingFor(entity: string, rowId: string): boolean;
68
+ private settleReadyEntries;
38
69
  private remove;
39
70
  private changed;
40
71
  }
72
+ export declare function optimisticPatchesFromReference(definition: OptimisticMutationDefinition | undefined, args: unknown): OptimisticPatch[];
41
73
  export {};