@firtoz/db-helpers 2.1.0 → 2.2.0

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,170 @@
1
+ import { __privateAdd, __privateSet, __privateGet, __privateMethod } from './chunk-HMLY7DHA.js';
2
+
3
+ // src/deferred-write-queue.ts
4
+ function mergeUpdate(m) {
5
+ return { ...m.original, ...m.changes };
6
+ }
7
+ var _backend, _getPersistKey, _flushIntervalMs, _pending, _intervalId, _flushTail, _disposed, _onBeforeUnload, _onVisibilityChange, _DeferredWriteQueue_instances, flushImpl_fn;
8
+ var DeferredWriteQueue = class {
9
+ constructor(options) {
10
+ __privateAdd(this, _DeferredWriteQueue_instances);
11
+ __privateAdd(this, _backend);
12
+ __privateAdd(this, _getPersistKey);
13
+ __privateAdd(this, _flushIntervalMs);
14
+ __privateAdd(this, _pending, /* @__PURE__ */ new Map());
15
+ __privateAdd(this, _intervalId, null);
16
+ __privateAdd(this, _flushTail, Promise.resolve());
17
+ __privateAdd(this, _disposed, false);
18
+ __privateAdd(this, _onBeforeUnload, () => {
19
+ void this.flush();
20
+ });
21
+ __privateAdd(this, _onVisibilityChange, () => {
22
+ const doc = globalThis.document;
23
+ if (doc?.visibilityState === "hidden") {
24
+ void this.flush();
25
+ }
26
+ });
27
+ __privateSet(this, _backend, options.backend);
28
+ __privateSet(this, _getPersistKey, options.getPersistKey);
29
+ __privateSet(this, _flushIntervalMs, options.flushIntervalMs ?? 100);
30
+ if (typeof globalThis !== "undefined") {
31
+ globalThis.addEventListener?.("beforeunload", __privateGet(this, _onBeforeUnload));
32
+ globalThis.addEventListener?.(
33
+ "visibilitychange",
34
+ __privateGet(this, _onVisibilityChange)
35
+ );
36
+ }
37
+ __privateSet(this, _intervalId, setInterval(() => {
38
+ void this.flush();
39
+ }, __privateGet(this, _flushIntervalMs)));
40
+ }
41
+ enqueueInsert(items) {
42
+ if (__privateGet(this, _disposed) || items.length === 0) return;
43
+ for (const item of items) {
44
+ const key = __privateGet(this, _getPersistKey).call(this, item);
45
+ const cur = __privateGet(this, _pending).get(key);
46
+ if (cur?.kind === "delete") {
47
+ __privateGet(this, _pending).set(key, {
48
+ kind: "row",
49
+ value: item,
50
+ insertedOnly: true
51
+ });
52
+ continue;
53
+ }
54
+ if (cur?.kind === "row" && !cur.insertedOnly) {
55
+ __privateGet(this, _pending).set(key, {
56
+ kind: "row",
57
+ value: item,
58
+ insertedOnly: false
59
+ });
60
+ continue;
61
+ }
62
+ __privateGet(this, _pending).set(key, { kind: "row", value: item, insertedOnly: true });
63
+ }
64
+ }
65
+ enqueueUpdate(mutations) {
66
+ if (__privateGet(this, _disposed) || mutations.length === 0) return;
67
+ for (const m of mutations) {
68
+ const key = m.key;
69
+ const value = mergeUpdate(m);
70
+ const cur = __privateGet(this, _pending).get(key);
71
+ if (cur?.kind === "delete") {
72
+ __privateGet(this, _pending).set(key, { kind: "row", value, insertedOnly: false });
73
+ continue;
74
+ }
75
+ if (cur?.kind === "row") {
76
+ __privateGet(this, _pending).set(key, {
77
+ kind: "row",
78
+ value,
79
+ insertedOnly: cur.insertedOnly
80
+ });
81
+ continue;
82
+ }
83
+ __privateGet(this, _pending).set(key, { kind: "row", value, insertedOnly: false });
84
+ }
85
+ }
86
+ enqueueDelete(mutations) {
87
+ if (__privateGet(this, _disposed) || mutations.length === 0) return;
88
+ for (const m of mutations) {
89
+ __privateGet(this, _pending).set(m.key, { kind: "delete" });
90
+ }
91
+ }
92
+ /**
93
+ * Drains pending ops into the backend. Serialized so concurrent flushes chain.
94
+ */
95
+ flush() {
96
+ __privateSet(this, _flushTail, __privateGet(this, _flushTail).catch(() => {
97
+ }).then(() => __privateMethod(this, _DeferredWriteQueue_instances, flushImpl_fn).call(this)));
98
+ return __privateGet(this, _flushTail);
99
+ }
100
+ dispose() {
101
+ if (__privateGet(this, _disposed)) return;
102
+ __privateSet(this, _disposed, true);
103
+ if (__privateGet(this, _intervalId) !== null) {
104
+ clearInterval(__privateGet(this, _intervalId));
105
+ __privateSet(this, _intervalId, null);
106
+ }
107
+ globalThis.removeEventListener?.("beforeunload", __privateGet(this, _onBeforeUnload));
108
+ globalThis.removeEventListener?.(
109
+ "visibilitychange",
110
+ __privateGet(this, _onVisibilityChange)
111
+ );
112
+ void this.flush();
113
+ }
114
+ };
115
+ _backend = new WeakMap();
116
+ _getPersistKey = new WeakMap();
117
+ _flushIntervalMs = new WeakMap();
118
+ _pending = new WeakMap();
119
+ _intervalId = new WeakMap();
120
+ _flushTail = new WeakMap();
121
+ _disposed = new WeakMap();
122
+ _onBeforeUnload = new WeakMap();
123
+ _onVisibilityChange = new WeakMap();
124
+ _DeferredWriteQueue_instances = new WeakSet();
125
+ flushImpl_fn = async function() {
126
+ if (__privateGet(this, _pending).size === 0) return;
127
+ const entries = [...__privateGet(this, _pending).entries()];
128
+ __privateGet(this, _pending).clear();
129
+ const deletePayload = [];
130
+ const toInsert = [];
131
+ const toUpsert = [];
132
+ for (const [key, op] of entries) {
133
+ if (op.kind === "delete") {
134
+ const id = Number.isFinite(Number(key)) && String(Number(key)) === key ? Number(key) : key;
135
+ const stub = { id };
136
+ deletePayload.push({
137
+ key,
138
+ modified: stub,
139
+ original: stub
140
+ });
141
+ } else if (op.insertedOnly) {
142
+ toInsert.push(op.value);
143
+ } else {
144
+ toUpsert.push(op.value);
145
+ }
146
+ }
147
+ if (deletePayload.length > 0) {
148
+ await __privateGet(this, _backend).handleDelete(deletePayload);
149
+ }
150
+ if (toInsert.length > 0) {
151
+ await __privateGet(this, _backend).handleInsert(toInsert);
152
+ }
153
+ if (toUpsert.length > 0) {
154
+ if (__privateGet(this, _backend).handleBatchPut !== void 0) {
155
+ await __privateGet(this, _backend).handleBatchPut(toUpsert);
156
+ } else {
157
+ await __privateGet(this, _backend).handleUpdate(
158
+ toUpsert.map((value) => ({
159
+ key: __privateGet(this, _getPersistKey).call(this, value),
160
+ changes: value,
161
+ original: value
162
+ }))
163
+ );
164
+ }
165
+ }
166
+ };
167
+
168
+ export { DeferredWriteQueue };
169
+ //# sourceMappingURL=chunk-E6ZONR5D.js.map
170
+ //# sourceMappingURL=chunk-E6ZONR5D.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/deferred-write-queue.ts"],"names":[],"mappings":";;;AAkBA,SAAS,YACR,CAAA,EACQ;AACR,EAAA,OAAO,EAAE,GAAG,CAAA,CAAE,QAAA,EAAU,GAAG,EAAE,OAAA,EAAQ;AACtC;AAtBA,IAAA,QAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,WAAA,EAAA,UAAA,EAAA,SAAA,EAAA,eAAA,EAAA,mBAAA,EAAA,6BAAA,EAAA,YAAA;AA4BO,IAAM,qBAAN,MAA+C;AAAA,EASrD,YAAY,OAAA,EAIT;AAbG,IAAA,YAAA,CAAA,IAAA,EAAA,6BAAA,CAAA;AACN,IAAA,YAAA,CAAA,IAAA,EAAS,QAAA,CAAA;AACT,IAAA,YAAA,CAAA,IAAA,EAAS,cAAA,CAAA;AACT,IAAA,YAAA,CAAA,IAAA,EAAS,gBAAA,CAAA;AACT,IAAA,YAAA,CAAA,IAAA,EAAA,QAAA,sBAAe,GAAA,EAA+B,CAAA;AAC9C,IAAA,YAAA,CAAA,IAAA,EAAA,WAAA,EAAqD,IAAA,CAAA;AACrD,IAAA,YAAA,CAAA,IAAA,EAAA,UAAA,EAA4B,QAAQ,OAAA,EAAQ,CAAA;AAC5C,IAAA,YAAA,CAAA,IAAA,EAAA,SAAA,EAAY,KAAA,CAAA;AAwBZ,IAAA,YAAA,CAAA,IAAA,EAAA,eAAA,EAAkB,MAAY;AAC7B,MAAA,KAAK,KAAK,KAAA,EAAM;AAAA,IACjB,CAAA,CAAA;AAEA,IAAA,YAAA,CAAA,IAAA,EAAA,mBAAA,EAAsB,MAAY;AACjC,MAAA,MAAM,MACL,UAAA,CAGC,QAAA;AACF,MAAA,IAAI,GAAA,EAAK,oBAAoB,QAAA,EAAU;AACtC,QAAA,KAAK,KAAK,KAAA,EAAM;AAAA,MACjB;AAAA,IACD,CAAA,CAAA;AA9BC,IAAA,YAAA,CAAA,IAAA,EAAK,UAAW,OAAA,CAAQ,OAAA,CAAA;AACxB,IAAA,YAAA,CAAA,IAAA,EAAK,gBAAiB,OAAA,CAAQ,aAAA,CAAA;AAC9B,IAAA,YAAA,CAAA,IAAA,EAAK,gBAAA,EAAmB,QAAQ,eAAA,IAAmB,GAAA,CAAA;AAEnD,IAAA,IAAI,OAAO,eAAe,WAAA,EAAa;AACtC,MAAA,UAAA,CAAW,gBAAA,GAAmB,cAAA,EAAgB,YAAA,CAAA,IAAA,EAAK,eAAA,CAAe,CAAA;AAClE,MAAA,UAAA,CAAW,gBAAA;AAAA,QACV,kBAAA;AAAA,QACA,YAAA,CAAA,IAAA,EAAK,mBAAA;AAAA,OACN;AAAA,IACD;AAEA,IAAA,YAAA,CAAA,IAAA,EAAK,WAAA,EAAc,YAAY,MAAM;AACpC,MAAA,KAAK,KAAK,KAAA,EAAM;AAAA,IACjB,CAAA,EAAG,mBAAK,gBAAA,CAAgB,CAAA,CAAA;AAAA,EACzB;AAAA,EAiBA,cAAc,KAAA,EAAsB;AACnC,IAAA,IAAI,YAAA,CAAA,IAAA,EAAK,SAAA,CAAA,IAAa,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG;AAC1C,IAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACzB,MAAA,MAAM,GAAA,GAAM,YAAA,CAAA,IAAA,EAAK,cAAA,CAAA,CAAL,IAAA,CAAA,IAAA,EAAoB,IAAA,CAAA;AAChC,MAAA,MAAM,GAAA,GAAM,YAAA,CAAA,IAAA,EAAK,QAAA,CAAA,CAAS,GAAA,CAAI,GAAG,CAAA;AACjC,MAAA,IAAI,GAAA,EAAK,SAAS,QAAA,EAAU;AAC3B,QAAA,YAAA,CAAA,IAAA,EAAK,QAAA,CAAA,CAAS,IAAI,GAAA,EAAK;AAAA,UACtB,IAAA,EAAM,KAAA;AAAA,UACN,KAAA,EAAO,IAAA;AAAA,UACP,YAAA,EAAc;AAAA,SACd,CAAA;AACD,QAAA;AAAA,MACD;AACA,MAAA,IAAI,GAAA,EAAK,IAAA,KAAS,KAAA,IAAS,CAAC,IAAI,YAAA,EAAc;AAC7C,QAAA,YAAA,CAAA,IAAA,EAAK,QAAA,CAAA,CAAS,IAAI,GAAA,EAAK;AAAA,UACtB,IAAA,EAAM,KAAA;AAAA,UACN,KAAA,EAAO,IAAA;AAAA,UACP,YAAA,EAAc;AAAA,SACd,CAAA;AACD,QAAA;AAAA,MACD;AACA,MAAA,YAAA,CAAA,IAAA,EAAK,QAAA,CAAA,CAAS,GAAA,CAAI,GAAA,EAAK,EAAE,IAAA,EAAM,OAAO,KAAA,EAAO,IAAA,EAAM,YAAA,EAAc,IAAA,EAAM,CAAA;AAAA,IACxE;AAAA,EACD;AAAA,EAEA,cAAc,SAAA,EAAkD;AAC/D,IAAA,IAAI,YAAA,CAAA,IAAA,EAAK,SAAA,CAAA,IAAa,SAAA,CAAU,MAAA,KAAW,CAAA,EAAG;AAC9C,IAAA,KAAA,MAAW,KAAK,SAAA,EAAW;AAC1B,MAAA,MAAM,MAAM,CAAA,CAAE,GAAA;AACd,MAAA,MAAM,KAAA,GAAQ,YAAY,CAAC,CAAA;AAC3B,MAAA,MAAM,GAAA,GAAM,YAAA,CAAA,IAAA,EAAK,QAAA,CAAA,CAAS,GAAA,CAAI,GAAG,CAAA;AACjC,MAAA,IAAI,GAAA,EAAK,SAAS,QAAA,EAAU;AAC3B,QAAA,YAAA,CAAA,IAAA,EAAK,QAAA,CAAA,CAAS,IAAI,GAAA,EAAK,EAAE,MAAM,KAAA,EAAO,KAAA,EAAO,YAAA,EAAc,KAAA,EAAO,CAAA;AAClE,QAAA;AAAA,MACD;AACA,MAAA,IAAI,GAAA,EAAK,SAAS,KAAA,EAAO;AACxB,QAAA,YAAA,CAAA,IAAA,EAAK,QAAA,CAAA,CAAS,IAAI,GAAA,EAAK;AAAA,UACtB,IAAA,EAAM,KAAA;AAAA,UACN,KAAA;AAAA,UACA,cAAc,GAAA,CAAI;AAAA,SAClB,CAAA;AACD,QAAA;AAAA,MACD;AACA,MAAA,YAAA,CAAA,IAAA,EAAK,QAAA,CAAA,CAAS,IAAI,GAAA,EAAK,EAAE,MAAM,KAAA,EAAO,KAAA,EAAO,YAAA,EAAc,KAAA,EAAO,CAAA;AAAA,IACnE;AAAA,EACD;AAAA,EAEA,cAAc,SAAA,EAAkD;AAC/D,IAAA,IAAI,YAAA,CAAA,IAAA,EAAK,SAAA,CAAA,IAAa,SAAA,CAAU,MAAA,KAAW,CAAA,EAAG;AAC9C,IAAA,KAAA,MAAW,KAAK,SAAA,EAAW;AAC1B,MAAA,YAAA,CAAA,IAAA,EAAK,UAAS,GAAA,CAAI,CAAA,CAAE,KAAK,EAAE,IAAA,EAAM,UAAU,CAAA;AAAA,IAC5C;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,KAAA,GAAuB;AACtB,IAAA,YAAA,CAAA,IAAA,EAAK,UAAA,EAAa,YAAA,CAAA,IAAA,EAAK,UAAA,CAAA,CACrB,KAAA,CAAM,MAAM;AAAA,IAAC,CAAC,CAAA,CACd,IAAA,CAAK,MAAM,eAAA,CAAA,IAAA,EAAK,6CAAL,IAAA,CAAA,IAAA,CAAiB,CAAA,CAAA;AAC9B,IAAA,OAAO,YAAA,CAAA,IAAA,EAAK,UAAA,CAAA;AAAA,EACb;AAAA,EAmDA,OAAA,GAAgB;AACf,IAAA,IAAI,mBAAK,SAAA,CAAA,EAAW;AACpB,IAAA,YAAA,CAAA,IAAA,EAAK,SAAA,EAAY,IAAA,CAAA;AACjB,IAAA,IAAI,YAAA,CAAA,IAAA,EAAK,iBAAgB,IAAA,EAAM;AAC9B,MAAA,aAAA,CAAc,mBAAK,WAAA,CAAW,CAAA;AAC9B,MAAA,YAAA,CAAA,IAAA,EAAK,WAAA,EAAc,IAAA,CAAA;AAAA,IACpB;AACA,IAAA,UAAA,CAAW,mBAAA,GAAsB,cAAA,EAAgB,YAAA,CAAA,IAAA,EAAK,eAAA,CAAe,CAAA;AACrE,IAAA,UAAA,CAAW,mBAAA;AAAA,MACV,kBAAA;AAAA,MACA,YAAA,CAAA,IAAA,EAAK,mBAAA;AAAA,KACN;AACA,IAAA,KAAK,KAAK,KAAA,EAAM;AAAA,EACjB;AACD;AA5KU,QAAA,GAAA,IAAA,OAAA,EAAA;AACA,cAAA,GAAA,IAAA,OAAA,EAAA;AACA,gBAAA,GAAA,IAAA,OAAA,EAAA;AACT,QAAA,GAAA,IAAA,OAAA,EAAA;AACA,WAAA,GAAA,IAAA,OAAA,EAAA;AACA,UAAA,GAAA,IAAA,OAAA,EAAA;AACA,SAAA,GAAA,IAAA,OAAA,EAAA;AAwBA,eAAA,GAAA,IAAA,OAAA,EAAA;AAIA,mBAAA,GAAA,IAAA,OAAA,EAAA;AAnCM,6BAAA,GAAA,IAAA,OAAA,EAAA;AA8GA,YAAA,GAAU,iBAAkB;AACjC,EAAA,IAAI,YAAA,CAAA,IAAA,EAAK,QAAA,CAAA,CAAS,IAAA,KAAS,CAAA,EAAG;AAC9B,EAAA,MAAM,UAAU,CAAC,GAAG,YAAA,CAAA,IAAA,EAAK,QAAA,CAAA,CAAS,SAAS,CAAA;AAC3C,EAAA,YAAA,CAAA,IAAA,EAAK,UAAS,KAAA,EAAM;AAEpB,EAAA,MAAM,gBAAiD,EAAC;AACxD,EAAA,MAAM,WAAoB,EAAC;AAC3B,EAAA,MAAM,WAAoB,EAAC;AAE3B,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,EAAE,CAAA,IAAK,OAAA,EAAS;AAChC,IAAA,IAAI,EAAA,CAAG,SAAS,QAAA,EAAU;AACzB,MAAA,MAAM,EAAA,GACL,MAAA,CAAO,QAAA,CAAS,MAAA,CAAO,GAAG,CAAC,CAAA,IAAK,MAAA,CAAO,MAAA,CAAO,GAAG,CAAC,CAAA,KAAM,GAAA,GACrD,MAAA,CAAO,GAAG,CAAA,GACV,GAAA;AACJ,MAAA,MAAM,IAAA,GAAO,EAAE,EAAA,EAAG;AAClB,MAAA,aAAA,CAAc,IAAA,CAAK;AAAA,QAClB,GAAA;AAAA,QACA,QAAA,EAAU,IAAA;AAAA,QACV,QAAA,EAAU;AAAA,OACV,CAAA;AAAA,IACF,CAAA,MAAA,IAAW,GAAG,YAAA,EAAc;AAC3B,MAAA,QAAA,CAAS,IAAA,CAAK,GAAG,KAAK,CAAA;AAAA,IACvB,CAAA,MAAO;AACN,MAAA,QAAA,CAAS,IAAA,CAAK,GAAG,KAAK,CAAA;AAAA,IACvB;AAAA,EACD;AAEA,EAAA,IAAI,aAAA,CAAc,SAAS,CAAA,EAAG;AAC7B,IAAA,MAAM,YAAA,CAAA,IAAA,EAAK,QAAA,CAAA,CAAS,YAAA,CAAa,aAAa,CAAA;AAAA,EAC/C;AACA,EAAA,IAAI,QAAA,CAAS,SAAS,CAAA,EAAG;AACxB,IAAA,MAAM,YAAA,CAAA,IAAA,EAAK,QAAA,CAAA,CAAS,YAAA,CAAa,QAAQ,CAAA;AAAA,EAC1C;AACA,EAAA,IAAI,QAAA,CAAS,SAAS,CAAA,EAAG;AACxB,IAAA,IAAI,YAAA,CAAA,IAAA,EAAK,QAAA,CAAA,CAAS,cAAA,KAAmB,MAAA,EAAW;AAC/C,MAAA,MAAM,YAAA,CAAA,IAAA,EAAK,QAAA,CAAA,CAAS,cAAA,CAAe,QAAQ,CAAA;AAAA,IAC5C,CAAA,MAAO;AACN,MAAA,MAAM,mBAAK,QAAA,CAAA,CAAS,YAAA;AAAA,QACnB,QAAA,CAAS,GAAA,CAAI,CAAC,KAAA,MAAW;AAAA,UACxB,GAAA,EAAK,YAAA,CAAA,IAAA,EAAK,cAAA,CAAA,CAAL,IAAA,CAAA,IAAA,EAAoB,KAAA,CAAA;AAAA,UACzB,OAAA,EAAS,KAAA;AAAA,UACT,QAAA,EAAU;AAAA,SACX,CAAE;AAAA,OACH;AAAA,IACD;AAAA,EACD;AACD,CAAA","file":"chunk-E6ZONR5D.js","sourcesContent":["import type { GenericSyncBackend } from \"./generic-sync\";\n\nexport type DeferredUpdateMutation<TItem extends object> = {\n\tkey: string;\n\tchanges: Partial<TItem>;\n\toriginal: TItem;\n};\n\nexport type DeferredDeleteMutation<TItem extends object> = {\n\tkey: string;\n\tmodified: TItem;\n\toriginal: TItem;\n};\n\ntype PendingRow<TItem extends object> =\n\t| { kind: \"row\"; value: TItem; insertedOnly: boolean }\n\t| { kind: \"delete\" };\n\nfunction mergeUpdate<TItem extends object>(\n\tm: DeferredUpdateMutation<TItem>,\n): TItem {\n\treturn { ...m.original, ...m.changes } as TItem;\n}\n\n/**\n * Write-behind queue for local mutations: coalesces by persist key and flushes to a\n * {@link GenericSyncBackend} on an interval or when {@link flush} is called explicitly.\n */\nexport class DeferredWriteQueue<TItem extends object> {\n\treadonly #backend: GenericSyncBackend<TItem>;\n\treadonly #getPersistKey: (item: TItem) => string;\n\treadonly #flushIntervalMs: number;\n\t#pending = new Map<string, PendingRow<TItem>>();\n\t#intervalId: ReturnType<typeof setInterval> | null = null;\n\t#flushTail: Promise<void> = Promise.resolve();\n\t#disposed = false;\n\n\tconstructor(options: {\n\t\tbackend: GenericSyncBackend<TItem>;\n\t\tgetPersistKey: (item: TItem) => string;\n\t\tflushIntervalMs?: number;\n\t}) {\n\t\tthis.#backend = options.backend;\n\t\tthis.#getPersistKey = options.getPersistKey;\n\t\tthis.#flushIntervalMs = options.flushIntervalMs ?? 100;\n\n\t\tif (typeof globalThis !== \"undefined\") {\n\t\t\tglobalThis.addEventListener?.(\"beforeunload\", this.#onBeforeUnload);\n\t\t\tglobalThis.addEventListener?.(\n\t\t\t\t\"visibilitychange\",\n\t\t\t\tthis.#onVisibilityChange,\n\t\t\t);\n\t\t}\n\n\t\tthis.#intervalId = setInterval(() => {\n\t\t\tvoid this.flush();\n\t\t}, this.#flushIntervalMs);\n\t}\n\n\t#onBeforeUnload = (): void => {\n\t\tvoid this.flush();\n\t};\n\n\t#onVisibilityChange = (): void => {\n\t\tconst doc = (\n\t\t\tglobalThis as typeof globalThis & {\n\t\t\t\tdocument?: { visibilityState?: string };\n\t\t\t}\n\t\t).document;\n\t\tif (doc?.visibilityState === \"hidden\") {\n\t\t\tvoid this.flush();\n\t\t}\n\t};\n\n\tenqueueInsert(items: TItem[]): void {\n\t\tif (this.#disposed || items.length === 0) return;\n\t\tfor (const item of items) {\n\t\t\tconst key = this.#getPersistKey(item);\n\t\t\tconst cur = this.#pending.get(key);\n\t\t\tif (cur?.kind === \"delete\") {\n\t\t\t\tthis.#pending.set(key, {\n\t\t\t\t\tkind: \"row\",\n\t\t\t\t\tvalue: item,\n\t\t\t\t\tinsertedOnly: true,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (cur?.kind === \"row\" && !cur.insertedOnly) {\n\t\t\t\tthis.#pending.set(key, {\n\t\t\t\t\tkind: \"row\",\n\t\t\t\t\tvalue: item,\n\t\t\t\t\tinsertedOnly: false,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.#pending.set(key, { kind: \"row\", value: item, insertedOnly: true });\n\t\t}\n\t}\n\n\tenqueueUpdate(mutations: DeferredUpdateMutation<TItem>[]): void {\n\t\tif (this.#disposed || mutations.length === 0) return;\n\t\tfor (const m of mutations) {\n\t\t\tconst key = m.key;\n\t\t\tconst value = mergeUpdate(m);\n\t\t\tconst cur = this.#pending.get(key);\n\t\t\tif (cur?.kind === \"delete\") {\n\t\t\t\tthis.#pending.set(key, { kind: \"row\", value, insertedOnly: false });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (cur?.kind === \"row\") {\n\t\t\t\tthis.#pending.set(key, {\n\t\t\t\t\tkind: \"row\",\n\t\t\t\t\tvalue,\n\t\t\t\t\tinsertedOnly: cur.insertedOnly,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.#pending.set(key, { kind: \"row\", value, insertedOnly: false });\n\t\t}\n\t}\n\n\tenqueueDelete(mutations: DeferredDeleteMutation<TItem>[]): void {\n\t\tif (this.#disposed || mutations.length === 0) return;\n\t\tfor (const m of mutations) {\n\t\t\tthis.#pending.set(m.key, { kind: \"delete\" });\n\t\t}\n\t}\n\n\t/**\n\t * Drains pending ops into the backend. Serialized so concurrent flushes chain.\n\t */\n\tflush(): Promise<void> {\n\t\tthis.#flushTail = this.#flushTail\n\t\t\t.catch(() => {})\n\t\t\t.then(() => this.#flushImpl());\n\t\treturn this.#flushTail;\n\t}\n\n\tasync #flushImpl(): Promise<void> {\n\t\tif (this.#pending.size === 0) return;\n\t\tconst entries = [...this.#pending.entries()];\n\t\tthis.#pending.clear();\n\n\t\tconst deletePayload: DeferredDeleteMutation<TItem>[] = [];\n\t\tconst toInsert: TItem[] = [];\n\t\tconst toUpsert: TItem[] = [];\n\n\t\tfor (const [key, op] of entries) {\n\t\t\tif (op.kind === \"delete\") {\n\t\t\t\tconst id =\n\t\t\t\t\tNumber.isFinite(Number(key)) && String(Number(key)) === key\n\t\t\t\t\t\t? Number(key)\n\t\t\t\t\t\t: key;\n\t\t\t\tconst stub = { id } as TItem;\n\t\t\t\tdeletePayload.push({\n\t\t\t\t\tkey,\n\t\t\t\t\tmodified: stub,\n\t\t\t\t\toriginal: stub,\n\t\t\t\t});\n\t\t\t} else if (op.insertedOnly) {\n\t\t\t\ttoInsert.push(op.value);\n\t\t\t} else {\n\t\t\t\ttoUpsert.push(op.value);\n\t\t\t}\n\t\t}\n\n\t\tif (deletePayload.length > 0) {\n\t\t\tawait this.#backend.handleDelete(deletePayload);\n\t\t}\n\t\tif (toInsert.length > 0) {\n\t\t\tawait this.#backend.handleInsert(toInsert);\n\t\t}\n\t\tif (toUpsert.length > 0) {\n\t\t\tif (this.#backend.handleBatchPut !== undefined) {\n\t\t\t\tawait this.#backend.handleBatchPut(toUpsert);\n\t\t\t} else {\n\t\t\t\tawait this.#backend.handleUpdate(\n\t\t\t\t\ttoUpsert.map((value) => ({\n\t\t\t\t\t\tkey: this.#getPersistKey(value),\n\t\t\t\t\t\tchanges: value as Partial<TItem>,\n\t\t\t\t\t\toriginal: value,\n\t\t\t\t\t})),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tif (this.#disposed) return;\n\t\tthis.#disposed = true;\n\t\tif (this.#intervalId !== null) {\n\t\t\tclearInterval(this.#intervalId);\n\t\t\tthis.#intervalId = null;\n\t\t}\n\t\tglobalThis.removeEventListener?.(\"beforeunload\", this.#onBeforeUnload);\n\t\tglobalThis.removeEventListener?.(\n\t\t\t\"visibilitychange\",\n\t\t\tthis.#onVisibilityChange,\n\t\t);\n\t\tvoid this.flush();\n\t}\n}\n"]}
@@ -0,0 +1,133 @@
1
+ import { exhaustiveGuard } from '@firtoz/maybe-error';
2
+ import { createCollection } from '@tanstack/db';
3
+
4
+ // src/memoryCollection.ts
5
+ function memoryCollectionOptions(config) {
6
+ let syncParams = null;
7
+ const pendingReceiveSyncBatches = [];
8
+ let syncWriteChain = Promise.resolve();
9
+ const enqueueSyncWrite = async (fn) => {
10
+ const next = syncWriteChain.catch(() => {
11
+ }).then(fn);
12
+ syncWriteChain = next;
13
+ await next;
14
+ };
15
+ const sync = (params) => {
16
+ syncParams = params;
17
+ params.markReady();
18
+ for (const batch of pendingReceiveSyncBatches) {
19
+ writeChanges(batch);
20
+ }
21
+ pendingReceiveSyncBatches.length = 0;
22
+ return () => {
23
+ };
24
+ };
25
+ const writeChanges = (writes) => {
26
+ if (!syncParams) {
27
+ throw new Error("Sync parameters not initialized");
28
+ }
29
+ syncParams.begin();
30
+ for (const msg of writes) {
31
+ switch (msg.type) {
32
+ case "insert":
33
+ syncParams.write({ type: "insert", value: msg.value });
34
+ break;
35
+ case "update":
36
+ syncParams.write({
37
+ type: "update",
38
+ value: msg.value,
39
+ previousValue: msg.previousValue
40
+ });
41
+ break;
42
+ case "delete":
43
+ syncParams.write({ type: "delete", key: msg.key });
44
+ break;
45
+ case "truncate":
46
+ syncParams.truncate();
47
+ break;
48
+ default:
49
+ exhaustiveGuard(msg);
50
+ }
51
+ }
52
+ syncParams.commit();
53
+ };
54
+ const onInsert = async (params) => {
55
+ const writes = [];
56
+ for (const mutation of params.transaction.mutations) {
57
+ writes.push({ type: "insert", value: mutation.modified });
58
+ }
59
+ await enqueueSyncWrite(() => {
60
+ writeChanges(writes);
61
+ });
62
+ config.onBroadcast?.(writes);
63
+ };
64
+ const onUpdate = async (params) => {
65
+ const writes = [];
66
+ for (const mutation of params.transaction.mutations) {
67
+ writes.push({
68
+ type: "update",
69
+ value: mutation.modified,
70
+ previousValue: mutation.original
71
+ });
72
+ }
73
+ await enqueueSyncWrite(() => {
74
+ writeChanges(writes);
75
+ });
76
+ config.onBroadcast?.(writes);
77
+ };
78
+ const onDelete = async (params) => {
79
+ const writes = [];
80
+ for (const mutation of params.transaction.mutations) {
81
+ writes.push({ type: "delete", key: mutation.key });
82
+ }
83
+ await enqueueSyncWrite(() => {
84
+ writeChanges(writes);
85
+ });
86
+ config.onBroadcast?.(writes);
87
+ };
88
+ const truncate = async () => {
89
+ if (!syncParams) {
90
+ pendingReceiveSyncBatches.length = 0;
91
+ return;
92
+ }
93
+ await enqueueSyncWrite(() => {
94
+ const p = syncParams;
95
+ if (!p) return;
96
+ p.begin();
97
+ p.truncate();
98
+ p.commit();
99
+ });
100
+ };
101
+ const receiveSync = async (messages) => {
102
+ if (messages.length === 0) return;
103
+ if (!syncParams) {
104
+ pendingReceiveSyncBatches.push(messages);
105
+ return;
106
+ }
107
+ await enqueueSyncWrite(() => {
108
+ writeChanges(messages);
109
+ });
110
+ };
111
+ return {
112
+ id: config.id,
113
+ schema: config.schema,
114
+ getKey: config.getKey,
115
+ sync: { sync },
116
+ onInsert,
117
+ onUpdate,
118
+ onDelete,
119
+ utils: {
120
+ truncate,
121
+ receiveSync
122
+ }
123
+ };
124
+ }
125
+ function createMemoryCollection(config) {
126
+ return createCollection(
127
+ memoryCollectionOptions(config)
128
+ );
129
+ }
130
+
131
+ export { createMemoryCollection, memoryCollectionOptions };
132
+ //# sourceMappingURL=chunk-EIDXVFD3.js.map
133
+ //# sourceMappingURL=chunk-EIDXVFD3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/memoryCollection.ts"],"names":[],"mappings":"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","file":"chunk-EIDXVFD3.js","sourcesContent":["import type { SyncMessage } from \"./sync-types\";\nimport { exhaustiveGuard } from \"@firtoz/maybe-error\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport {\n\ttype Collection,\n\ttype CollectionConfig,\n\tcreateCollection,\n\ttype DeleteMutationFnParams,\n\ttype InferSchemaInput,\n\ttype InferSchemaOutput,\n\ttype InsertMutationFnParams,\n\ttype SyncConfig,\n\ttype UpdateMutationFnParams,\n} from \"@tanstack/db\";\n\ntype MemoryCollectionConfig<TSchema extends StandardSchemaV1> = Omit<\n\tCollectionConfig<InferSchemaOutput<TSchema>, string | number, TSchema>,\n\t\"onInsert\" | \"onUpdate\" | \"onDelete\" | \"sync\" | \"schema\"\n> & {\n\tschema: TSchema;\n\t/** Called when a local mutation is written to the sync layer; use to broadcast to other peers. */\n\tonBroadcast?: (\n\t\tchanges: SyncMessage<InferSchemaOutput<TSchema>, string | number>[],\n\t) => void;\n};\n\ntype MemoryUtils<\n\tTItem = unknown,\n\tTKey extends string | number = string | number,\n> = {\n\ttruncate: () => Promise<void>;\n\t/**\n\t * Apply incoming sync messages without triggering onInsert/onUpdate/onDelete.\n\t * Uses the sync layer (begin/write/commit) so state updates and subscribeChanges fire,\n\t * but no rebroadcast occurs.\n\t */\n\treceiveSync: (messages: SyncMessage<TItem, TKey>[]) => Promise<void>;\n};\n\nexport function memoryCollectionOptions<TSchema extends StandardSchemaV1>(\n\tconfig: MemoryCollectionConfig<TSchema>,\n): CollectionConfig<InferSchemaOutput<TSchema>, string | number, TSchema> & {\n\tutils: MemoryUtils<InferSchemaOutput<TSchema>, string | number>;\n\tschema: TSchema;\n} {\n\ttype TItem = InferSchemaOutput<TSchema>;\n\ttype TKey = string | number;\n\tlet syncParams: Parameters<SyncConfig<TItem>[\"sync\"]>[0] | null = null;\n\t/** Batches from `receiveSync` that arrived before TanStack called `sync`. */\n\tconst pendingReceiveSyncBatches: SyncMessage<TItem, TKey>[][] = [];\n\t/**\n\t * One TanStack sync transaction at a time: `receiveSync`, local mutations, and `truncate` all\n\t * call `begin`/`commit` — overlapping calls cause SyncTransactionAlreadyCommittedWriteError.\n\t */\n\tlet syncWriteChain: Promise<void> = Promise.resolve();\n\n\tconst enqueueSyncWrite = async (fn: () => void): Promise<void> => {\n\t\tconst next = syncWriteChain.catch(() => {}).then(fn);\n\t\tsyncWriteChain = next;\n\t\tawait next;\n\t};\n\n\tconst sync: SyncConfig<TItem>[\"sync\"] = (params) => {\n\t\tsyncParams = params;\n\t\tparams.markReady();\n\t\tfor (const batch of pendingReceiveSyncBatches) {\n\t\t\twriteChanges(batch);\n\t\t}\n\t\tpendingReceiveSyncBatches.length = 0;\n\t\treturn () => {};\n\t};\n\n\tconst writeChanges = (writes: SyncMessage<TItem, TKey>[]) => {\n\t\tif (!syncParams) {\n\t\t\tthrow new Error(\"Sync parameters not initialized\");\n\t\t}\n\t\tsyncParams.begin();\n\t\tfor (const msg of writes) {\n\t\t\tswitch (msg.type) {\n\t\t\t\tcase \"insert\":\n\t\t\t\t\tsyncParams.write({ type: \"insert\", value: msg.value });\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"update\":\n\t\t\t\t\tsyncParams.write({\n\t\t\t\t\t\ttype: \"update\",\n\t\t\t\t\t\tvalue: msg.value,\n\t\t\t\t\t\tpreviousValue: msg.previousValue,\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"delete\":\n\t\t\t\t\tsyncParams.write({ type: \"delete\", key: msg.key });\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"truncate\":\n\t\t\t\t\tsyncParams.truncate();\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\texhaustiveGuard(msg);\n\t\t\t}\n\t\t}\n\t\tsyncParams.commit();\n\t};\n\n\tconst onInsert = async (params: InsertMutationFnParams<TItem>) => {\n\t\tconst writes: SyncMessage<TItem, TKey>[] = [];\n\t\tfor (const mutation of params.transaction.mutations) {\n\t\t\twrites.push({ type: \"insert\", value: mutation.modified });\n\t\t}\n\t\tawait enqueueSyncWrite(() => {\n\t\t\twriteChanges(writes);\n\t\t});\n\t\tconfig.onBroadcast?.(writes);\n\t};\n\n\tconst onUpdate = async (params: UpdateMutationFnParams<TItem>) => {\n\t\tconst writes: SyncMessage<TItem, TKey>[] = [];\n\t\tfor (const mutation of params.transaction.mutations) {\n\t\t\twrites.push({\n\t\t\t\ttype: \"update\",\n\t\t\t\tvalue: mutation.modified,\n\t\t\t\tpreviousValue: mutation.original,\n\t\t\t});\n\t\t}\n\t\tawait enqueueSyncWrite(() => {\n\t\t\twriteChanges(writes);\n\t\t});\n\t\tconfig.onBroadcast?.(writes);\n\t};\n\n\tconst onDelete = async (params: DeleteMutationFnParams<TItem>) => {\n\t\tconst writes: SyncMessage<TItem, TKey>[] = [];\n\t\tfor (const mutation of params.transaction.mutations) {\n\t\t\twrites.push({ type: \"delete\", key: mutation.key as TKey });\n\t\t}\n\t\tawait enqueueSyncWrite(() => {\n\t\t\twriteChanges(writes);\n\t\t});\n\t\tconfig.onBroadcast?.(writes);\n\t};\n\n\tconst truncate = async () => {\n\t\tif (!syncParams) {\n\t\t\t// TanStack may not have invoked `sync` yet (e.g. first paint / effect). Nothing to clear.\n\t\t\tpendingReceiveSyncBatches.length = 0;\n\t\t\treturn;\n\t\t}\n\t\tawait enqueueSyncWrite(() => {\n\t\t\tconst p = syncParams;\n\t\t\tif (!p) return;\n\t\t\tp.begin();\n\t\t\tp.truncate();\n\t\t\tp.commit();\n\t\t});\n\t};\n\n\tconst receiveSync = async (messages: SyncMessage<TItem, TKey>[]) => {\n\t\tif (messages.length === 0) return;\n\t\tif (!syncParams) {\n\t\t\tpendingReceiveSyncBatches.push(messages);\n\t\t\treturn;\n\t\t}\n\t\tawait enqueueSyncWrite(() => {\n\t\t\twriteChanges(messages);\n\t\t});\n\t};\n\n\treturn {\n\t\tid: config.id,\n\t\tschema: config.schema,\n\t\tgetKey: config.getKey,\n\t\tsync: { sync },\n\t\tonInsert,\n\t\tonUpdate,\n\t\tonDelete,\n\t\tutils: {\n\t\t\ttruncate,\n\t\t\treceiveSync,\n\t\t},\n\t};\n}\n\nexport type MemoryCollection<TSchema extends StandardSchemaV1> = Collection<\n\tInferSchemaOutput<TSchema>,\n\tstring | number,\n\tMemoryUtils<InferSchemaOutput<TSchema>, string | number>,\n\tTSchema,\n\tInferSchemaInput<TSchema>\n>;\n\nexport function createMemoryCollection<TSchema extends StandardSchemaV1>(\n\tconfig: MemoryCollectionConfig<TSchema>,\n): MemoryCollection<TSchema> {\n\treturn createCollection(\n\t\tmemoryCollectionOptions(config),\n\t) as MemoryCollection<TSchema>;\n}\n"]}
@@ -0,0 +1,12 @@
1
+ var __typeError = (msg) => {
2
+ throw TypeError(msg);
3
+ };
4
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
5
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
6
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
7
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
8
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
9
+
10
+ export { __privateAdd, __privateGet, __privateMethod, __privateSet };
11
+ //# sourceMappingURL=chunk-HMLY7DHA.js.map
12
+ //# sourceMappingURL=chunk-HMLY7DHA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-HMLY7DHA.js"}
@@ -0,0 +1,118 @@
1
+ // src/ir-evaluator.ts
2
+ function evaluateExpression(expression, item) {
3
+ switch (expression.type) {
4
+ case "ref": {
5
+ const propRef = expression;
6
+ const columnName = propRef.path[propRef.path.length - 1];
7
+ return item[columnName] !== void 0;
8
+ }
9
+ case "val": {
10
+ const value = expression;
11
+ return !!value.value;
12
+ }
13
+ case "func": {
14
+ const func = expression;
15
+ switch (func.name) {
16
+ case "eq": {
17
+ const left = getExpressionValue(func.args[0], item);
18
+ const right = getExpressionValue(func.args[1], item);
19
+ return left === right;
20
+ }
21
+ case "ne": {
22
+ const left = getExpressionValue(func.args[0], item);
23
+ const right = getExpressionValue(func.args[1], item);
24
+ return left !== right;
25
+ }
26
+ case "gt": {
27
+ const left = getExpressionValue(func.args[0], item);
28
+ const right = getExpressionValue(func.args[1], item);
29
+ return left > right;
30
+ }
31
+ case "gte": {
32
+ const left = getExpressionValue(func.args[0], item);
33
+ const right = getExpressionValue(func.args[1], item);
34
+ return left >= right;
35
+ }
36
+ case "lt": {
37
+ const left = getExpressionValue(func.args[0], item);
38
+ const right = getExpressionValue(func.args[1], item);
39
+ return left < right;
40
+ }
41
+ case "lte": {
42
+ const left = getExpressionValue(func.args[0], item);
43
+ const right = getExpressionValue(func.args[1], item);
44
+ return left <= right;
45
+ }
46
+ case "and": {
47
+ return func.args.every((arg) => evaluateExpression(arg, item));
48
+ }
49
+ case "or": {
50
+ return func.args.some((arg) => evaluateExpression(arg, item));
51
+ }
52
+ case "not": {
53
+ return !evaluateExpression(func.args[0], item);
54
+ }
55
+ case "isNull": {
56
+ const value = getExpressionValue(func.args[0], item);
57
+ return value === null || value === void 0;
58
+ }
59
+ case "isNotNull": {
60
+ const value = getExpressionValue(func.args[0], item);
61
+ return value !== null && value !== void 0;
62
+ }
63
+ case "like": {
64
+ const left = String(getExpressionValue(func.args[0], item));
65
+ const right = String(getExpressionValue(func.args[1], item));
66
+ const pattern = right.replace(/%/g, ".*").replace(/_/g, ".");
67
+ return new RegExp(`^${pattern}$`).test(left);
68
+ }
69
+ case "ilike": {
70
+ const left = String(getExpressionValue(func.args[0], item));
71
+ const right = String(getExpressionValue(func.args[1], item));
72
+ const pattern = right.replace(/%/g, ".*").replace(/_/g, ".");
73
+ return new RegExp(`^${pattern}$`, "i").test(left);
74
+ }
75
+ case "in": {
76
+ const left = getExpressionValue(func.args[0], item);
77
+ const right = getExpressionValue(func.args[1], item);
78
+ return Array.isArray(right) && right.includes(left);
79
+ }
80
+ case "isUndefined": {
81
+ const value = getExpressionValue(func.args[0], item);
82
+ return value === null || value === void 0;
83
+ }
84
+ default:
85
+ throw new Error(`Unsupported function: ${func.name}`);
86
+ }
87
+ }
88
+ default: {
89
+ throw new Error(
90
+ `Unsupported expression type: ${expression.type}`
91
+ );
92
+ }
93
+ }
94
+ }
95
+ function getExpressionValue(expression, item) {
96
+ switch (expression.type) {
97
+ case "ref": {
98
+ const propRef = expression;
99
+ const columnName = propRef.path[propRef.path.length - 1];
100
+ return item[columnName];
101
+ }
102
+ case "val": {
103
+ const value = expression;
104
+ return value.value;
105
+ }
106
+ case "func":
107
+ throw new Error("Cannot get value from func expression");
108
+ default: {
109
+ throw new Error(
110
+ `Cannot get value from expression type: ${expression.type}`
111
+ );
112
+ }
113
+ }
114
+ }
115
+
116
+ export { evaluateExpression, getExpressionValue };
117
+ //# sourceMappingURL=chunk-Y64WBRON.js.map
118
+ //# sourceMappingURL=chunk-Y64WBRON.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ir-evaluator.ts"],"names":[],"mappings":"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","file":"chunk-Y64WBRON.js","sourcesContent":["import type { IR } from \"@tanstack/db\";\n\n/**\n * Evaluates a TanStack DB IR expression against a plain object item.\n * @internal Exported for testing and reuse by collection backends\n */\nexport function evaluateExpression(\n\texpression: IR.BasicExpression,\n\titem: Record<string, unknown>,\n): boolean {\n\tswitch (expression.type) {\n\t\tcase \"ref\": {\n\t\t\tconst propRef = expression;\n\t\t\tconst columnName = propRef.path[propRef.path.length - 1];\n\t\t\treturn item[columnName as string] !== undefined;\n\t\t}\n\t\tcase \"val\": {\n\t\t\tconst value = expression;\n\t\t\treturn !!value.value;\n\t\t}\n\t\tcase \"func\": {\n\t\t\tconst func = expression;\n\n\t\t\tswitch (func.name) {\n\t\t\t\tcase \"eq\": {\n\t\t\t\t\tconst left = getExpressionValue(func.args[0], item);\n\t\t\t\t\tconst right = getExpressionValue(func.args[1], item);\n\t\t\t\t\treturn left === right;\n\t\t\t\t}\n\t\t\t\tcase \"ne\": {\n\t\t\t\t\tconst left = getExpressionValue(func.args[0], item);\n\t\t\t\t\tconst right = getExpressionValue(func.args[1], item);\n\t\t\t\t\treturn left !== right;\n\t\t\t\t}\n\t\t\t\tcase \"gt\": {\n\t\t\t\t\tconst left = getExpressionValue(func.args[0], item);\n\t\t\t\t\tconst right = getExpressionValue(func.args[1], item);\n\t\t\t\t\treturn left > right;\n\t\t\t\t}\n\t\t\t\tcase \"gte\": {\n\t\t\t\t\tconst left = getExpressionValue(func.args[0], item);\n\t\t\t\t\tconst right = getExpressionValue(func.args[1], item);\n\t\t\t\t\treturn left >= right;\n\t\t\t\t}\n\t\t\t\tcase \"lt\": {\n\t\t\t\t\tconst left = getExpressionValue(func.args[0], item);\n\t\t\t\t\tconst right = getExpressionValue(func.args[1], item);\n\t\t\t\t\treturn left < right;\n\t\t\t\t}\n\t\t\t\tcase \"lte\": {\n\t\t\t\t\tconst left = getExpressionValue(func.args[0], item);\n\t\t\t\t\tconst right = getExpressionValue(func.args[1], item);\n\t\t\t\t\treturn left <= right;\n\t\t\t\t}\n\t\t\t\tcase \"and\": {\n\t\t\t\t\treturn func.args.every((arg) => evaluateExpression(arg, item));\n\t\t\t\t}\n\t\t\t\tcase \"or\": {\n\t\t\t\t\treturn func.args.some((arg) => evaluateExpression(arg, item));\n\t\t\t\t}\n\t\t\t\tcase \"not\": {\n\t\t\t\t\treturn !evaluateExpression(func.args[0], item);\n\t\t\t\t}\n\t\t\t\tcase \"isNull\": {\n\t\t\t\t\tconst value = getExpressionValue(func.args[0], item);\n\t\t\t\t\treturn value === null || value === undefined;\n\t\t\t\t}\n\t\t\t\tcase \"isNotNull\": {\n\t\t\t\t\tconst value = getExpressionValue(func.args[0], item);\n\t\t\t\t\treturn value !== null && value !== undefined;\n\t\t\t\t}\n\t\t\t\tcase \"like\": {\n\t\t\t\t\tconst left = String(getExpressionValue(func.args[0], item));\n\t\t\t\t\tconst right = String(getExpressionValue(func.args[1], item));\n\t\t\t\t\tconst pattern = right.replace(/%/g, \".*\").replace(/_/g, \".\");\n\t\t\t\t\treturn new RegExp(`^${pattern}$`).test(left);\n\t\t\t\t}\n\t\t\t\tcase \"ilike\": {\n\t\t\t\t\tconst left = String(getExpressionValue(func.args[0], item));\n\t\t\t\t\tconst right = String(getExpressionValue(func.args[1], item));\n\t\t\t\t\tconst pattern = right.replace(/%/g, \".*\").replace(/_/g, \".\");\n\t\t\t\t\treturn new RegExp(`^${pattern}$`, \"i\").test(left);\n\t\t\t\t}\n\t\t\t\tcase \"in\": {\n\t\t\t\t\tconst left = getExpressionValue(func.args[0], item);\n\t\t\t\t\tconst right = getExpressionValue(func.args[1], item);\n\t\t\t\t\treturn Array.isArray(right) && right.includes(left);\n\t\t\t\t}\n\t\t\t\tcase \"isUndefined\": {\n\t\t\t\t\tconst value = getExpressionValue(func.args[0], item);\n\t\t\t\t\treturn value === null || value === undefined;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`Unsupported function: ${func.name}`);\n\t\t\t}\n\t\t}\n\t\tdefault: {\n\t\t\tconst _ex: never = expression;\n\t\t\tvoid _ex;\n\t\t\tthrow new Error(\n\t\t\t\t`Unsupported expression type: ${(expression as { type: string }).type}`,\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * Gets the value from an IR expression by resolving refs and vals.\n * @internal Exported for testing and reuse by collection backends\n */\nexport function getExpressionValue(\n\texpression: IR.BasicExpression,\n\titem: Record<string, unknown>,\n\t// biome-ignore lint/suspicious/noExplicitAny: We need any here for dynamic values\n): any {\n\tswitch (expression.type) {\n\t\tcase \"ref\": {\n\t\t\tconst propRef = expression;\n\t\t\tconst columnName = propRef.path[propRef.path.length - 1];\n\t\t\treturn item[columnName as string];\n\t\t}\n\t\tcase \"val\": {\n\t\t\tconst value = expression;\n\t\t\treturn value.value;\n\t\t}\n\t\tcase \"func\":\n\t\t\tthrow new Error(\"Cannot get value from func expression\");\n\t\tdefault: {\n\t\t\tconst _ex: never = expression;\n\t\t\tvoid _ex;\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot get value from expression type: ${(expression as { type: string }).type}`,\n\t\t\t);\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,37 @@
1
+ import { GenericSyncBackend } from './generic-sync.js';
2
+ import './sync-types.js';
3
+ import '@standard-schema/spec';
4
+ import '@tanstack/db';
5
+
6
+ type DeferredUpdateMutation<TItem extends object> = {
7
+ key: string;
8
+ changes: Partial<TItem>;
9
+ original: TItem;
10
+ };
11
+ type DeferredDeleteMutation<TItem extends object> = {
12
+ key: string;
13
+ modified: TItem;
14
+ original: TItem;
15
+ };
16
+ /**
17
+ * Write-behind queue for local mutations: coalesces by persist key and flushes to a
18
+ * {@link GenericSyncBackend} on an interval or when {@link flush} is called explicitly.
19
+ */
20
+ declare class DeferredWriteQueue<TItem extends object> {
21
+ #private;
22
+ constructor(options: {
23
+ backend: GenericSyncBackend<TItem>;
24
+ getPersistKey: (item: TItem) => string;
25
+ flushIntervalMs?: number;
26
+ });
27
+ enqueueInsert(items: TItem[]): void;
28
+ enqueueUpdate(mutations: DeferredUpdateMutation<TItem>[]): void;
29
+ enqueueDelete(mutations: DeferredDeleteMutation<TItem>[]): void;
30
+ /**
31
+ * Drains pending ops into the backend. Serialized so concurrent flushes chain.
32
+ */
33
+ flush(): Promise<void>;
34
+ dispose(): void;
35
+ }
36
+
37
+ export { type DeferredDeleteMutation, type DeferredUpdateMutation, DeferredWriteQueue };
@@ -0,0 +1,4 @@
1
+ export { DeferredWriteQueue } from './chunk-E6ZONR5D.js';
2
+ import './chunk-HMLY7DHA.js';
3
+ //# sourceMappingURL=deferred-write-queue.js.map
4
+ //# sourceMappingURL=deferred-write-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"deferred-write-queue.js"}
@@ -0,0 +1,89 @@
1
+ import { ReceiveSyncDurableOp, CollectionUtils } from './sync-types.js';
2
+ import { StandardSchemaV1 } from '@standard-schema/spec';
3
+ import { LoadSubsetOptions, SyncMode, SyncConfig, CollectionConfig, InferSchemaOutput } from '@tanstack/db';
4
+
5
+ declare const USE_DEDUPE: boolean;
6
+ /**
7
+ * Base configuration for sync lifecycle management (generic, no Drizzle dependency).
8
+ */
9
+ interface GenericBaseSyncConfig<TItem extends object = object> {
10
+ readyPromise: Promise<void>;
11
+ syncMode?: SyncMode;
12
+ debug?: boolean;
13
+ /**
14
+ * Row key for durable storage when applying {@link CollectionUtils.receiveSync} updates.
15
+ * If omitted, `id` on the item (string or number) is used.
16
+ */
17
+ getSyncPersistKey?: (item: TItem) => string;
18
+ /**
19
+ * When set, local `onInsert` / `onUpdate` / `onDelete` confirm TanStack sync state immediately
20
+ * and enqueue durable backend writes (coalesced, flushed on an interval). `receiveSync`,
21
+ * `loadSubset`, and `truncate` flush the queue first so reads stay consistent.
22
+ */
23
+ deferLocalPersistence?: boolean | {
24
+ flushIntervalMs?: number;
25
+ };
26
+ }
27
+ /**
28
+ * Backend-specific implementations required for sync (generic, no Drizzle dependency).
29
+ */
30
+ interface GenericSyncBackend<TItem extends object> {
31
+ initialLoad: () => Promise<Array<TItem>>;
32
+ loadSubset: (options: LoadSubsetOptions) => Promise<Array<TItem>>;
33
+ handleInsert: (items: Array<TItem>) => Promise<Array<TItem>>;
34
+ handleUpdate: (mutations: Array<{
35
+ key: string;
36
+ changes: Partial<TItem>;
37
+ original: TItem;
38
+ }>) => Promise<Array<TItem>>;
39
+ handleDelete: (mutations: Array<{
40
+ key: string;
41
+ modified: TItem;
42
+ original: TItem;
43
+ }>) => Promise<void>;
44
+ handleTruncate?: () => Promise<void>;
45
+ /**
46
+ * When set, {@link CollectionUtils.receiveSync} persists an entire message batch with one call
47
+ * (e.g. one SQLite transaction) instead of awaiting {@link handleInsert}/handleUpdate per
48
+ * message. TanStack `syncWrite`/`syncTruncate` still run once per message in order.
49
+ */
50
+ applyReceiveSyncDurableWrites?: (ops: ReceiveSyncDurableOp<TItem>[]) => Promise<void>;
51
+ /**
52
+ * Optional batch upsert for deferred local persistence flushes (e.g. IndexedDB `put` in one tx).
53
+ */
54
+ handleBatchPut?: (items: Array<TItem>) => Promise<void>;
55
+ }
56
+ /**
57
+ * Return type for createGenericSyncFunction.
58
+ */
59
+ type GenericSyncFunctionResult<TItem extends object> = {
60
+ sync: SyncConfig<TItem, string>["sync"];
61
+ onInsert: CollectionConfig<TItem, string, any>["onInsert"];
62
+ onUpdate: CollectionConfig<TItem, string, any>["onUpdate"];
63
+ onDelete: CollectionConfig<TItem, string, any>["onDelete"];
64
+ utils: CollectionUtils<TItem>;
65
+ };
66
+ /**
67
+ * Creates the sync function with common lifecycle management.
68
+ * Generic version -- no Drizzle dependency.
69
+ */
70
+ declare function createGenericSyncFunction<TItem extends object>(config: GenericBaseSyncConfig<TItem>, backend: GenericSyncBackend<TItem>): GenericSyncFunctionResult<TItem>;
71
+ /**
72
+ * Generic collection config factory.
73
+ * Combines schema, sync, and event handlers into a collection config.
74
+ * No Drizzle dependency -- uses StandardSchemaV1 directly.
75
+ */
76
+ declare function createGenericCollectionConfig<TItem extends object, TSchema extends StandardSchemaV1>(config: {
77
+ schema: TSchema;
78
+ getKey: (item: TItem) => string;
79
+ syncResult: GenericSyncFunctionResult<TItem>;
80
+ onInsert?: CollectionConfig<TItem, string, any>["onInsert"];
81
+ onUpdate?: CollectionConfig<TItem, string, any>["onUpdate"];
82
+ onDelete?: CollectionConfig<TItem, string, any>["onDelete"];
83
+ syncMode?: SyncMode;
84
+ }): Omit<CollectionConfig<TItem, string, TSchema, CollectionUtils<InferSchemaOutput<TSchema>>>, "utils"> & {
85
+ schema: TSchema;
86
+ utils: CollectionUtils<InferSchemaOutput<TSchema>>;
87
+ };
88
+
89
+ export { type GenericBaseSyncConfig, type GenericSyncBackend, type GenericSyncFunctionResult, USE_DEDUPE, createGenericCollectionConfig, createGenericSyncFunction };
@@ -0,0 +1,5 @@
1
+ export { USE_DEDUPE, createGenericCollectionConfig, createGenericSyncFunction } from './chunk-72YXZ3BK.js';
2
+ import './chunk-E6ZONR5D.js';
3
+ import './chunk-HMLY7DHA.js';
4
+ //# sourceMappingURL=generic-sync.js.map
5
+ //# sourceMappingURL=generic-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"generic-sync.js"}