@signaldb/generic-fs 2.0.0-beta.2 → 2.0.0-beta.20

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.
package/dist/index.d.ts CHANGED
@@ -28,4 +28,4 @@ export interface Driver<T extends {
28
28
  */
29
29
  export default function createGenericFSAdapter<T extends {
30
30
  id: I;
31
- } & Record<string, unknown>, I>(driver: Driver<T, I>, folderName: string): import("@signaldb/core").StorageAdapter<T, I>;
31
+ } & Record<string, unknown>, I>(driver: Driver<T, I>, folderName: string): import('@signaldb/core').StorageAdapter<T, I>;
package/dist/index.mjs CHANGED
@@ -1,224 +1,199 @@
1
- import { get as j, createStorageAdapter as N } from "@signaldb/core";
2
- function M(e, d, p, f, l) {
3
- e.has(d) || e.set(d, { adds: /* @__PURE__ */ new Map(), removes: /* @__PURE__ */ new Map() });
4
- const x = e.get(d);
5
- if (!x)
6
- return;
7
- const I = p === "add" ? x.adds : x.removes;
8
- I.has(f) || I.set(f, /* @__PURE__ */ new Set()), I.get(f)?.add(l);
1
+ import { createStorageAdapter as e, get as t } from "@signaldb/core";
2
+ //#region src/deltaHelpers.ts
3
+ function n(e, t, n, r, i) {
4
+ e.has(t) || e.set(t, {
5
+ adds: /* @__PURE__ */ new Map(),
6
+ removes: /* @__PURE__ */ new Map()
7
+ });
8
+ let a = e.get(t);
9
+ if (!a) return;
10
+ let o = n === "add" ? a.adds : a.removes;
11
+ o.has(r) || o.set(r, /* @__PURE__ */ new Set()), o.get(r)?.add(i);
9
12
  }
10
- const V = (e, d, p, f) => {
11
- for (const l of d) {
12
- const x = j(f, l);
13
- x != null && M(e, l, "add", String(x), f.id);
14
- }
13
+ function r(e, t, r, i, a) {
14
+ let o = r == null ? void 0 : String(r), s = i == null ? void 0 : String(i);
15
+ o !== s && (o != null && n(e, t, "remove", o, a), s != null && n(e, t, "add", s, a));
16
+ }
17
+ var i = (e, i, a, o) => {
18
+ if (a) for (let n of i) r(e, n, t(a, n), t(o, n), o.id);
19
+ else for (let r of i) {
20
+ let i = t(o, r);
21
+ i != null && n(e, r, "add", String(i), o.id);
22
+ }
15
23
  };
16
- function C(e, d, p) {
17
- for (const f of d) {
18
- const l = j(p, f);
19
- l != null && M(e, f, "remove", String(l), p.id);
20
- }
24
+ function a(e, r, i) {
25
+ for (let a of r) {
26
+ let r = t(i, a);
27
+ r != null && n(e, a, "remove", String(r), i.id);
28
+ }
21
29
  }
22
- function U(e, d) {
23
- const p = e.joinPath(d, "items"), f = e.joinPath(d, "index"), l = async (t) => e.fileExists(t).catch(() => !1), x = async (t, n) => e.removeEntry(t, n).catch(() => {
24
- }), I = async (t) => e.joinPath(await p, await e.fileNameForId(t)), g = async (t) => e.joinPath(await f, await e.fileNameForIndexKey(t)), R = async (t, n) => {
25
- const a = await e.fileNameForIndexKey(n);
26
- return e.joinPath(t, a);
27
- }, S = async (t) => {
28
- if (!await l(t))
29
- return [];
30
- const a = await e.readObject(t).catch(() => []);
31
- return Array.isArray(a) ? a : [];
32
- }, K = (t) => {
33
- const n = /* @__PURE__ */ new Map();
34
- if (!Array.isArray(t))
35
- return n;
36
- for (const a of t)
37
- for (const [s, i] of Object.entries(a))
38
- n.set(s, new Set(i));
39
- return n;
40
- }, A = async (t, n) => {
41
- if (n.size === 0) {
42
- await l(t) && await x(t);
43
- return;
44
- }
45
- const a = [];
46
- n.forEach((s, i) => {
47
- a.push({ [i]: [...s] });
48
- }), await e.writeIndexObject(t, a);
49
- }, b = async (t) => {
50
- const n = await e.readIndexObject(t).catch(() => null);
51
- return K(n);
52
- }, O = async () => {
53
- const t = await p;
54
- if (!await l(t))
55
- return [];
56
- const a = await e.listFilesRecursive(t), s = [];
57
- return await Promise.all(a.map(async (i) => {
58
- const w = await e.joinPath(t, i), o = await e.readObject(w).catch(() => null);
59
- Array.isArray(o) && s.push(...o);
60
- })), s;
61
- }, z = async (t, n = O()) => {
62
- const a = await n, s = await g(t);
63
- await x(s, { recursive: !0 }), await e.ensureDir(s);
64
- const i = /* @__PURE__ */ new Map();
65
- for (const o of a) {
66
- const c = j(o, t);
67
- if (c == null)
68
- continue;
69
- const r = String(c);
70
- i.has(r) || i.set(r, /* @__PURE__ */ new Set()), i.get(r)?.add(o.id);
71
- }
72
- const w = {};
73
- for (const [o, c] of i) {
74
- const r = await e.fileNameForIndexKey(o);
75
- w[r] || (w[r] = []), w[r].push({ [o]: [...c] });
76
- }
77
- await Promise.all(Object.entries(w).map(async ([o, c]) => {
78
- const r = await e.joinPath(s, o);
79
- await e.writeIndexObject(r, c);
80
- }));
81
- }, B = async (t) => {
82
- const n = await g(t);
83
- if (!await l(n))
84
- throw new Error(`Index on field "${t}" does not exist`);
85
- const s = await e.listFilesRecursive(n), i = /* @__PURE__ */ new Map();
86
- return await Promise.all(s.map(async (w) => {
87
- const o = await e.joinPath(n, w), c = await e.readIndexObject(o).catch(() => null);
88
- if (Array.isArray(c))
89
- for (const r of c)
90
- for (const [h, m] of Object.entries(r)) {
91
- i.has(h) || i.set(h, /* @__PURE__ */ new Set());
92
- const P = i.get(h);
93
- for (const y of m)
94
- P?.add(y);
95
- }
96
- })), i;
97
- }, F = [], k = async (t) => {
98
- await Promise.all([...t.entries()].map(async ([n, a]) => {
99
- const s = await g(n);
100
- if (!await l(s))
101
- return;
102
- await e.ensureDir(s);
103
- const w = /* @__PURE__ */ new Set([
104
- ...a.adds.keys(),
105
- ...a.removes.keys()
106
- ]), o = /* @__PURE__ */ new Map();
107
- await Promise.all([...w].map(async (r) => {
108
- o.set(r, await e.fileNameForIndexKey(r));
109
- }));
110
- const c = new Set(o.values());
111
- await Promise.all([...c].map(async (r) => {
112
- const h = await e.joinPath(s, r), m = await b(h);
113
- a.removes.forEach((P, y) => {
114
- if (o.get(y) !== r)
115
- return;
116
- const u = m.get(y);
117
- u && (P.forEach((E) => u.delete(E)), u.size === 0 && m.delete(y));
118
- }), a.adds.forEach((P, y) => {
119
- if (o.get(y) !== r)
120
- return;
121
- const u = m.get(y) ?? /* @__PURE__ */ new Set();
122
- P.forEach((E) => u.add(E)), m.set(y, u);
123
- }), await A(h, m);
124
- }));
125
- }));
126
- }, T = async (t, n) => {
127
- const a = await g(t);
128
- if (!await l(a))
129
- return;
130
- const i = await e.listFilesRecursive(a);
131
- await Promise.all(i.map(async (w) => {
132
- const o = await e.joinPath(a, w), c = await e.readIndexObject(o).catch(() => null);
133
- if (!Array.isArray(c))
134
- return;
135
- let r = !1;
136
- const h = /* @__PURE__ */ new Map();
137
- for (const m of c)
138
- for (const [P, y] of Object.entries(m)) {
139
- const u = new Set(y), E = u.size;
140
- u.delete(n), u.size !== E && (r = !0), u.size > 0 && h.set(P, u);
141
- }
142
- r && await A(o, h);
143
- }));
144
- }, $ = async (t, n, a) => {
145
- if (n == null)
146
- return;
147
- const s = String(n), i = await g(t);
148
- if (!await l(i))
149
- return;
150
- await e.ensureDir(i);
151
- const o = await R(i, s), c = await b(o), r = c.get(s) ?? /* @__PURE__ */ new Set();
152
- r.add(a), c.set(s, r), await A(o, c);
153
- }, L = async (t, n) => {
154
- await Promise.all(F.map(async (a) => {
155
- await T(a, t.id);
156
- const s = j(n, a);
157
- await $(a, s, n.id);
158
- }));
159
- }, D = async (t, n) => {
160
- const a = /* @__PURE__ */ new Map();
161
- await Promise.all(t.map(async (s) => {
162
- const i = await I(s.id), w = await S(i), o = w.findIndex((c) => c.id === s.id);
163
- if (n === "insert") {
164
- if (o !== -1)
165
- throw new Error(`Item with id "${String(s.id)}" already exists`);
166
- V(a, F, void 0, s), await e.writeObject(i, [...w, s]);
167
- } else {
168
- if (o === -1)
169
- throw new Error(`Item with id "${String(s.id)}" does not exist`);
170
- const c = [...w], r = c[o];
171
- c[o] = s, await e.writeObject(i, c), await L(r, s);
172
- }
173
- })), a.size > 0 && await k(a);
174
- };
175
- return N({
176
- setup: async () => {
177
- await e.ensureDir(d);
178
- },
179
- teardown: async () => {
180
- },
181
- readAll: O,
182
- readIds: async (t) => (await Promise.all(t.map(async (a) => {
183
- const s = await I(a), i = await e.readObject(s).catch(() => []) ?? [];
184
- return Array.isArray(i) ? i.find((w) => w.id === a) ?? null : null;
185
- }))).filter((a) => a != null),
186
- createIndex: async (t) => {
187
- if (t === "id")
188
- throw new Error("Cannot create index on id field");
189
- F.push(t), await z(t);
190
- },
191
- dropIndex: async (t) => {
192
- const n = await g(t);
193
- if (!await l(n))
194
- throw new Error(`Index on field "${t}" does not exist`);
195
- await e.removeEntry(n, { recursive: !0 });
196
- },
197
- readIndex: B,
198
- insert: async (t) => {
199
- await D(t, "insert");
200
- },
201
- replace: async (t) => {
202
- await D(t, "replace");
203
- },
204
- remove: async (t) => {
205
- const n = /* @__PURE__ */ new Map();
206
- await Promise.all(t.map(async (a) => {
207
- const s = await I(a.id), i = await S(s), w = i.findIndex((c) => c.id === a.id);
208
- if (w === -1)
209
- throw new Error(`Item with id "${String(a.id)}" does not exist`);
210
- C(n, F, i[w]);
211
- const o = [...i];
212
- o.splice(w, 1), await (o.length === 0 ? e.removeEntry(s).catch(() => {
213
- }) : e.writeObject(s, o));
214
- })), await k(n);
215
- },
216
- removeAll: async () => {
217
- await l(d) && await e.removeEntry(d, { recursive: !0 });
218
- }
219
- });
30
+ //#endregion
31
+ //#region src/index.ts
32
+ function o(n, r) {
33
+ let o = n.joinPath(r, "items"), s = n.joinPath(r, "index"), c = async (e) => n.fileExists(e).catch(() => !1), l = async (e, t) => n.removeEntry(e, t).catch(() => {}), u = async (e) => n.joinPath(await o, await n.fileNameForId(e)), d = async (e) => n.joinPath(await s, await n.fileNameForIndexKey(e)), f = async (e, t) => {
34
+ let r = await n.fileNameForIndexKey(t);
35
+ return n.joinPath(e, r);
36
+ }, p = async (e) => {
37
+ if (!await c(e)) return [];
38
+ let t = await n.readObject(e).catch(() => []);
39
+ return Array.isArray(t) ? t : [];
40
+ }, m = (e) => {
41
+ let t = /* @__PURE__ */ new Map();
42
+ if (!Array.isArray(e)) return t;
43
+ for (let n of e) for (let [e, r] of Object.entries(n)) t.set(e, new Set(r));
44
+ return t;
45
+ }, h = async (e, t) => {
46
+ if (t.size === 0) {
47
+ await c(e) && await l(e);
48
+ return;
49
+ }
50
+ let r = [];
51
+ t.forEach((e, t) => {
52
+ r.push({ [t]: [...e] });
53
+ }), await n.writeIndexObject(e, r);
54
+ }, g = async (e) => m(await n.readIndexObject(e).catch(() => null)), _ = async () => {
55
+ let e = await o;
56
+ if (!await c(e)) return [];
57
+ let t = await n.listFilesRecursive(e), r = [];
58
+ return await Promise.all(t.map(async (t) => {
59
+ let i = await n.joinPath(e, t), a = await n.readObject(i).catch(() => null);
60
+ Array.isArray(a) && r.push(...a);
61
+ })), r;
62
+ }, v = async (e, r = _()) => {
63
+ let i = await r, a = await d(e);
64
+ await l(a, { recursive: !0 }), await n.ensureDir(a);
65
+ let o = /* @__PURE__ */ new Map();
66
+ for (let n of i) {
67
+ let r = t(n, e);
68
+ if (r == null) continue;
69
+ let i = String(r);
70
+ o.has(i) || o.set(i, /* @__PURE__ */ new Set()), o.get(i)?.add(n.id);
71
+ }
72
+ let s = {};
73
+ for (let [e, t] of o) {
74
+ let r = await n.fileNameForIndexKey(e);
75
+ s[r] || (s[r] = []), s[r].push({ [e]: [...t] });
76
+ }
77
+ await Promise.all(Object.entries(s).map(async ([e, t]) => {
78
+ let r = await n.joinPath(a, e);
79
+ await n.writeIndexObject(r, t);
80
+ }));
81
+ }, y = async (e) => {
82
+ let t = await d(e);
83
+ if (!await c(t)) throw Error(`Index on field "${e}" does not exist`);
84
+ let r = await n.listFilesRecursive(t), i = /* @__PURE__ */ new Map();
85
+ return await Promise.all(r.map(async (e) => {
86
+ let r = await n.joinPath(t, e), a = await n.readIndexObject(r).catch(() => null);
87
+ if (Array.isArray(a)) for (let e of a) for (let [t, n] of Object.entries(e)) {
88
+ i.has(t) || i.set(t, /* @__PURE__ */ new Set());
89
+ let e = i.get(t);
90
+ for (let t of n) e?.add(t);
91
+ }
92
+ })), i;
93
+ }, b = [], x = async (e) => {
94
+ await Promise.all([...e.entries()].map(async ([e, t]) => {
95
+ let r = await d(e);
96
+ if (!await c(r)) return;
97
+ await n.ensureDir(r);
98
+ let i = new Set([...t.adds.keys(), ...t.removes.keys()]), a = /* @__PURE__ */ new Map();
99
+ await Promise.all([...i].map(async (e) => {
100
+ a.set(e, await n.fileNameForIndexKey(e));
101
+ }));
102
+ let o = new Set(a.values());
103
+ await Promise.all([...o].map(async (e) => {
104
+ let i = await n.joinPath(r, e), o = await g(i);
105
+ t.removes.forEach((t, n) => {
106
+ if (a.get(n) !== e) return;
107
+ let r = o.get(n);
108
+ r && (t.forEach((e) => r.delete(e)), r.size === 0 && o.delete(n));
109
+ }), t.adds.forEach((t, n) => {
110
+ if (a.get(n) !== e) return;
111
+ let r = o.get(n) ?? /* @__PURE__ */ new Set();
112
+ t.forEach((e) => r.add(e)), o.set(n, r);
113
+ }), await h(i, o);
114
+ }));
115
+ }));
116
+ }, S = async (e, t) => {
117
+ let r = await d(e);
118
+ if (!await c(r)) return;
119
+ let i = await n.listFilesRecursive(r);
120
+ await Promise.all(i.map(async (e) => {
121
+ let i = await n.joinPath(r, e), a = await n.readIndexObject(i).catch(() => null);
122
+ if (!Array.isArray(a)) return;
123
+ let o = !1, s = /* @__PURE__ */ new Map();
124
+ for (let e of a) for (let [n, r] of Object.entries(e)) {
125
+ let e = new Set(r), i = e.size;
126
+ e.delete(t), e.size !== i && (o = !0), e.size > 0 && s.set(n, e);
127
+ }
128
+ o && await h(i, s);
129
+ }));
130
+ }, C = async (e, t, r) => {
131
+ if (t == null) return;
132
+ let i = String(t), a = await d(e);
133
+ if (!await c(a)) return;
134
+ await n.ensureDir(a);
135
+ let o = await f(a, i), s = await g(o), l = s.get(i) ?? /* @__PURE__ */ new Set();
136
+ l.add(r), s.set(i, l), await h(o, s);
137
+ }, w = async (e, n) => {
138
+ await Promise.all(b.map(async (r) => {
139
+ await S(r, e.id), await C(r, t(n, r), n.id);
140
+ }));
141
+ }, T = async (e, t) => {
142
+ let r = /* @__PURE__ */ new Map();
143
+ await Promise.all(e.map(async (e) => {
144
+ let a = await u(e.id), o = await p(a), s = o.findIndex((t) => t.id === e.id);
145
+ if (t === "insert") {
146
+ if (s !== -1) throw Error(`Item with id "${String(e.id)}" already exists`);
147
+ i(r, b, void 0, e), await n.writeObject(a, [...o, e]);
148
+ } else {
149
+ if (s === -1) throw Error(`Item with id "${String(e.id)}" does not exist`);
150
+ let t = [...o], r = t[s];
151
+ t[s] = e, await n.writeObject(a, t), await w(r, e);
152
+ }
153
+ })), r.size > 0 && await x(r);
154
+ };
155
+ return e({
156
+ setup: async () => {
157
+ await n.ensureDir(r);
158
+ },
159
+ teardown: async () => {},
160
+ readAll: _,
161
+ readIds: async (e) => (await Promise.all(e.map(async (e) => {
162
+ let t = await u(e), r = await n.readObject(t).catch(() => []) ?? [];
163
+ return Array.isArray(r) ? r.find((t) => t.id === e) ?? null : null;
164
+ }))).filter((e) => e != null),
165
+ createIndex: async (e) => {
166
+ if (e === "id") throw Error("Cannot create index on id field");
167
+ b.push(e), await v(e);
168
+ },
169
+ dropIndex: async (e) => {
170
+ let t = await d(e);
171
+ if (!await c(t)) throw Error(`Index on field "${e}" does not exist`);
172
+ await n.removeEntry(t, { recursive: !0 });
173
+ },
174
+ readIndex: y,
175
+ insert: async (e) => {
176
+ await T(e, "insert");
177
+ },
178
+ replace: async (e) => {
179
+ await T(e, "replace");
180
+ },
181
+ remove: async (e) => {
182
+ let t = /* @__PURE__ */ new Map();
183
+ await Promise.all(e.map(async (e) => {
184
+ let r = await u(e.id), i = await p(r), o = i.findIndex((t) => t.id === e.id);
185
+ if (o === -1) throw Error(`Item with id "${String(e.id)}" does not exist`);
186
+ a(t, b, i[o]);
187
+ let s = [...i];
188
+ s.splice(o, 1), await (s.length === 0 ? n.removeEntry(r).catch(() => {}) : n.writeObject(r, s));
189
+ })), await x(t);
190
+ },
191
+ removeAll: async () => {
192
+ await c(r) && await n.removeEntry(r, { recursive: !0 });
193
+ }
194
+ });
220
195
  }
221
- export {
222
- U as default
223
- };
224
- //# sourceMappingURL=index.mjs.map
196
+ //#endregion
197
+ export { o as default };
198
+
199
+ //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/deltaHelpers.ts","../src/index.ts"],"sourcesContent":["import { get } from '@signaldb/core';\n/**\n * Records a single index mutation into the delta map for a given indexed field.\n *\n * The delta map is grouped by `fieldPath`, and then by stringified key (`rawKey`).\n * Each key maps to a set of identifiers to add/remove for that key.\n * @param deltas - Accumulator of per-field index deltas.\n * @param fieldPath - Dot-path of the indexed field (used as the delta bucket key).\n * @param changeKind - Whether this identifier should be added to or removed from the index key.\n * @param rawKey - The stringified index key value.\n * @param identifier - The item identifier to add/remove for `rawKey`.\n */\nexport function addToDelta(deltas, fieldPath, changeKind, rawKey, identifier) {\n if (!deltas.has(fieldPath))\n deltas.set(fieldPath, { adds: new Map(), removes: new Map() });\n const delta = deltas.get(fieldPath);\n if (!delta)\n return;\n const target = changeKind === 'add' ? delta.adds : delta.removes;\n if (!target.has(rawKey))\n target.set(rawKey, new Set());\n target.get(rawKey)?.add(identifier);\n}\n/**\n * Computes the delta for a change in a single indexed field.\n *\n * Values are coerced to string keys (with `null`/`undefined` treated as \"no key\").\n * If the derived keys are equal, no delta is recorded.\n * @param deltas - Accumulator of per-field index deltas.\n * @param fieldPath - Dot-path of the indexed field being tracked.\n * @param oldValue - Previous value of the field.\n * @param newValue - Next value of the field.\n * @param identifier - The item identifier affected by the change.\n */\nexport function addDeltaForChange(deltas, fieldPath, oldValue, newValue, identifier) {\n const oldKey = oldValue == null ? undefined : String(oldValue);\n const newKey = newValue == null ? undefined : String(newValue);\n if (oldKey === newKey)\n return;\n if (oldKey != null)\n addToDelta(deltas, fieldPath, 'remove', oldKey, identifier);\n if (newKey != null)\n addToDelta(deltas, fieldPath, 'add', newKey, identifier);\n}\n/**\n * Accumulates index deltas for an upsert operation.\n *\n * - If `existingItem` is present, compares each maintained index field between the old and new item,\n * recording removes/adds for key changes.\n * - If `existingItem` is absent, treats the operation as an insert and records adds for each\n * maintained index field that has a non-null value.\n * @param deltas - Accumulator of per-field index deltas.\n * @param indicesToMaintain - List of dot-paths for fields that are indexed.\n * @param existingItem - Previous stored item (if any).\n * @param nextItem - Incoming item to upsert.\n */\nexport const accumulateUpsertDelta = (deltas, indicesToMaintain, existingItem, nextItem) => {\n if (existingItem) {\n for (const fieldPath of indicesToMaintain) {\n addDeltaForChange(deltas, fieldPath, get(existingItem, fieldPath), get(nextItem, fieldPath), nextItem.id);\n }\n }\n else {\n for (const fieldPath of indicesToMaintain) {\n const value = get(nextItem, fieldPath);\n if (value == null)\n continue;\n addToDelta(deltas, fieldPath, 'add', String(value), nextItem.id);\n }\n }\n};\n/**\n * Accumulates index deltas for a remove/delete operation.\n *\n * For each maintained index field, records a removal of the item's identifier from the\n * corresponding stringified key (skipping `null`/`undefined` values).\n * @param deltas - Accumulator of per-field index deltas.\n * @param indicesToMaintain - List of dot-paths for fields that are indexed.\n * @param existingItem - The item being removed.\n */\nexport function accumulateRemoveDelta(deltas, indicesToMaintain, existingItem) {\n for (const fieldPath of indicesToMaintain) {\n const value = get(existingItem, fieldPath);\n if (value == null)\n continue;\n addToDelta(deltas, fieldPath, 'remove', String(value), existingItem.id);\n }\n}\n","import { createStorageAdapter, get } from '@signaldb/core';\nimport { accumulateUpsertDelta, accumulateRemoveDelta, } from './deltaHelpers';\n/**\n * Creates a storage adapter for managing a SignalDB collection using a generic filesystem-like driver.\n * Data is sharded into subdirectories based on item identifiers, and indices are maintained as files.\n * @param driver - The driver that handles low-level file operations.\n * @param folderName - The root folder path for storing the collection data.\n * @returns A SignalDB storage adapter for managing data in a filesystem-like storage.\n */\nexport default function createGenericFSAdapter(driver, folderName) {\n const itemsDirectoryPathPromise = driver.joinPath(folderName, 'items');\n const indexRootPathPromise = driver.joinPath(folderName, 'index');\n const safeFileExists = async (path) => driver.fileExists(path).catch(() => false);\n const safeRemoveEntry = async (path, options) => driver.removeEntry(path, options).catch(() => { });\n const toItemsFilePath = async (identifier) => driver.joinPath(await itemsDirectoryPathPromise, await driver.fileNameForId(identifier));\n const toIndexPathForField = async (fieldPath) => driver.joinPath(await indexRootPathPromise, await driver.fileNameForIndexKey(fieldPath));\n const toIndexBucketFilePath = async (indexPath, rawKey) => {\n const bucketFileName = await driver.fileNameForIndexKey(rawKey);\n return driver.joinPath(indexPath, bucketFileName);\n };\n const readItemsArrayOrEmpty = async (filePath) => {\n const exists = await safeFileExists(filePath);\n if (!exists)\n return [];\n const data = await driver.readObject(filePath).catch(() => []);\n return Array.isArray(data) ? data : [];\n };\n const loadBucketIndexFromData = (data) => {\n const bucketIndex = new Map();\n if (!Array.isArray(data))\n return bucketIndex;\n for (const entry of data) {\n for (const [rawKey, identifierList] of Object.entries(entry)) {\n bucketIndex.set(rawKey, new Set(identifierList));\n }\n }\n return bucketIndex;\n };\n const writeBucketIndex = async (filePath, bucketIndex) => {\n if (bucketIndex.size === 0) {\n const exists = await safeFileExists(filePath);\n if (exists)\n await safeRemoveEntry(filePath);\n return;\n }\n const output = [];\n bucketIndex.forEach((identifierSet, rawKey) => {\n output.push({ [rawKey]: [...identifierSet] });\n });\n await driver.writeIndexObject(filePath, output);\n };\n const readBucketIndex = async (filePath) => {\n const data = await driver.readIndexObject(filePath).catch(() => null);\n return loadBucketIndexFromData(data);\n };\n const readAll = async () => {\n const itemsDirectoryPath = await itemsDirectoryPathPromise;\n const directoryExists = await safeFileExists(itemsDirectoryPath);\n if (!directoryExists)\n return [];\n const relativeFiles = await driver.listFilesRecursive(itemsDirectoryPath);\n const aggregatedItems = [];\n await Promise.all(relativeFiles.map(async (relativePath) => {\n const fullPath = await driver.joinPath(itemsDirectoryPath, relativePath);\n const itemsInFile = await driver.readObject(fullPath).catch(() => null);\n if (Array.isArray(itemsInFile))\n aggregatedItems.push(...itemsInFile);\n }));\n return aggregatedItems;\n };\n const ensureIndex = async (fieldPath, itemsPromise = readAll()) => {\n const allItems = await itemsPromise;\n const indexPath = await toIndexPathForField(fieldPath);\n await safeRemoveEntry(indexPath, { recursive: true });\n await driver.ensureDir(indexPath);\n // Build value -> Set<identifier>\n const indexMap = new Map();\n for (const item of allItems) {\n const fieldValue = get(item, fieldPath);\n if (fieldValue == null)\n continue;\n const keyString = String(fieldValue);\n if (!indexMap.has(keyString))\n indexMap.set(keyString, new Set());\n indexMap.get(keyString)?.add(item.id);\n }\n // Group entries by bucket file name, then persist each bucket\n const buckets = {};\n for (const [rawKeyString, identifierSet] of indexMap) {\n const bucketFileName = await driver.fileNameForIndexKey(rawKeyString);\n if (!buckets[bucketFileName])\n buckets[bucketFileName] = [];\n buckets[bucketFileName].push({ [rawKeyString]: [...identifierSet] });\n }\n await Promise.all(Object.entries(buckets).map(async ([bucketFileName, records]) => {\n const filePath = await driver.joinPath(indexPath, bucketFileName);\n await driver.writeIndexObject(filePath, records);\n }));\n };\n const readIndex = async (fieldPath) => {\n const indexPath = await toIndexPathForField(fieldPath);\n const indexExists = await safeFileExists(indexPath);\n if (!indexExists)\n throw new Error(`Index on field \"${fieldPath}\" does not exist`);\n const relativeFiles = await driver.listFilesRecursive(indexPath);\n const resultIndex = new Map();\n await Promise.all(relativeFiles.map(async (relativePath) => {\n const fullPath = await driver.joinPath(indexPath, relativePath);\n const maps = await driver.readIndexObject(fullPath).catch(() => null);\n if (!Array.isArray(maps))\n return;\n for (const entry of maps) {\n for (const [rawKey, identifierList] of Object.entries(entry)) {\n if (!resultIndex.has(rawKey))\n resultIndex.set(rawKey, new Set());\n const target = resultIndex.get(rawKey);\n for (const identifier of identifierList)\n target?.add(identifier);\n }\n }\n }));\n return resultIndex;\n };\n // Track which field paths should be kept up-to-date incrementally.\n const indicesToMaintain = [];\n const applyIndexDeltas = async (deltas) => {\n // For each indexed field with changes, touch only the affected bucket files\n await Promise.all([...deltas.entries()].map(async ([fieldPath, delta]) => {\n const indexPath = await toIndexPathForField(fieldPath);\n const indexExists = await safeFileExists(indexPath);\n if (!indexExists)\n return; // Only update indices that exist\n await driver.ensureDir(indexPath);\n // Compute impacted bucket filenames\n const touchedRawKeys = new Set([\n ...delta.adds.keys(),\n ...delta.removes.keys(),\n ]);\n const rawKeyToBucketFileName = new Map();\n await Promise.all([...touchedRawKeys].map(async (rawKey) => {\n rawKeyToBucketFileName.set(rawKey, await driver.fileNameForIndexKey(rawKey));\n }));\n const touchedBucketFileNames = new Set(rawKeyToBucketFileName.values());\n await Promise.all([...touchedBucketFileNames].map(async (bucketFileName) => {\n const filePath = await driver.joinPath(indexPath, bucketFileName);\n const bucketIndex = await readBucketIndex(filePath);\n // Apply removals for keys that map to this bucket\n delta.removes.forEach((identifierSet, rawKey) => {\n if (rawKeyToBucketFileName.get(rawKey) !== bucketFileName)\n return;\n const setForKey = bucketIndex.get(rawKey);\n if (!setForKey)\n return;\n identifierSet.forEach(identifier => setForKey.delete(identifier));\n if (setForKey.size === 0)\n bucketIndex.delete(rawKey);\n });\n // Apply additions\n delta.adds.forEach((identifierSet, rawKey) => {\n if (rawKeyToBucketFileName.get(rawKey) !== bucketFileName)\n return;\n const setForKey = bucketIndex.get(rawKey) ?? new Set();\n identifierSet.forEach(identifier => setForKey.add(identifier));\n bucketIndex.set(rawKey, setForKey);\n });\n await writeBucketIndex(filePath, bucketIndex);\n }));\n }));\n };\n const removeIdFromIndex = async (fieldPath, identifier) => {\n const indexPath = await toIndexPathForField(fieldPath);\n const indexExists = await safeFileExists(indexPath);\n if (!indexExists)\n return;\n const relativeFiles = await driver.listFilesRecursive(indexPath);\n await Promise.all(relativeFiles.map(async (relativePath) => {\n const filePath = await driver.joinPath(indexPath, relativePath);\n const data = await driver.readIndexObject(filePath).catch(() => null);\n if (!Array.isArray(data))\n return;\n let changed = false;\n const bucketIndex = new Map();\n for (const entry of data) {\n for (const [rawKey, identifierList] of Object.entries(entry)) {\n const set = new Set(identifierList);\n const before = set.size;\n set.delete(identifier);\n if (set.size !== before)\n changed = true;\n if (set.size > 0)\n bucketIndex.set(rawKey, set);\n }\n }\n if (!changed)\n return;\n await writeBucketIndex(filePath, bucketIndex);\n }));\n };\n const addIdToIndex = async (fieldPath, value, identifier) => {\n if (value == null)\n return;\n const rawKey = String(value);\n const indexPath = await toIndexPathForField(fieldPath);\n const indexExists = await safeFileExists(indexPath);\n if (!indexExists)\n return;\n await driver.ensureDir(indexPath);\n const filePath = await toIndexBucketFilePath(indexPath, rawKey);\n const bucketIndex = await readBucketIndex(filePath);\n const setForKey = bucketIndex.get(rawKey) ?? new Set();\n setForKey.add(identifier);\n bucketIndex.set(rawKey, setForKey);\n await writeBucketIndex(filePath, bucketIndex);\n };\n const updateIndexForReplace = async (oldItem, nextItem) => {\n await Promise.all(indicesToMaintain.map(async (fieldPath) => {\n await removeIdFromIndex(fieldPath, oldItem.id);\n const newValue = get(nextItem, fieldPath);\n await addIdToIndex(fieldPath, newValue, nextItem.id);\n }));\n };\n const upsertItems = async (items, mode) => {\n const deltas = new Map();\n await Promise.all(items.map(async (item) => {\n const filePath = await toItemsFilePath(item.id);\n const existingArray = await readItemsArrayOrEmpty(filePath);\n const indexOfItem = existingArray.findIndex(existing => existing.id === item.id);\n if (mode === 'insert') {\n if (indexOfItem !== -1)\n throw new Error(`Item with id \"${String(item.id)}\" already exists`);\n accumulateUpsertDelta(deltas, indicesToMaintain, undefined, item);\n await driver.writeObject(filePath, [...existingArray, item]);\n }\n else {\n if (indexOfItem === -1)\n throw new Error(`Item with id \"${String(item.id)}\" does not exist`);\n const updatedArray = [...existingArray];\n const oldItem = updatedArray[indexOfItem];\n updatedArray[indexOfItem] = item;\n await driver.writeObject(filePath, updatedArray);\n await updateIndexForReplace(oldItem, item);\n }\n }));\n // Only apply deltas for inserts (replace handled by direct purge+add)\n if (deltas.size > 0) {\n await applyIndexDeltas(deltas);\n }\n };\n return createStorageAdapter({\n setup: async () => {\n await driver.ensureDir(folderName);\n },\n teardown: async () => {\n // no-op\n },\n readAll,\n readIds: async (identifiers) => {\n const results = await Promise.all(identifiers.map(async (identifier) => {\n const filePath = await toItemsFilePath(identifier);\n const itemsInFile = await driver.readObject(filePath).catch(() => []) ?? [];\n if (!Array.isArray(itemsInFile))\n return null;\n return itemsInFile.find(item => item.id === identifier) ?? null;\n }));\n return results.filter((value) => value != null);\n },\n createIndex: async (fieldPath) => {\n if (fieldPath === 'id')\n throw new Error('Cannot create index on id field');\n indicesToMaintain.push(fieldPath);\n await ensureIndex(fieldPath);\n },\n dropIndex: async (fieldPath) => {\n const pathToDrop = await toIndexPathForField(fieldPath);\n const exists = await safeFileExists(pathToDrop);\n if (!exists)\n throw new Error(`Index on field \"${fieldPath}\" does not exist`);\n await driver.removeEntry(pathToDrop, { recursive: true });\n },\n readIndex,\n insert: async (itemsToInsert) => {\n await upsertItems(itemsToInsert, 'insert');\n },\n replace: async (itemsToReplace) => {\n await upsertItems(itemsToReplace, 'replace');\n },\n remove: async (itemsToRemove) => {\n const deltas = new Map();\n await Promise.all(itemsToRemove.map(async (item) => {\n const filePath = await toItemsFilePath(item.id);\n const existingArray = await readItemsArrayOrEmpty(filePath);\n const indexOfItem = existingArray.findIndex(existing => existing.id === item.id);\n if (indexOfItem === -1)\n throw new Error(`Item with id \"${String(item.id)}\" does not exist`);\n accumulateRemoveDelta(deltas, indicesToMaintain, existingArray[indexOfItem]);\n const updatedArray = [...existingArray];\n updatedArray.splice(indexOfItem, 1);\n await (updatedArray.length === 0\n ? driver.removeEntry(filePath).catch(() => { })\n : driver.writeObject(filePath, updatedArray));\n }));\n await applyIndexDeltas(deltas);\n },\n removeAll: async () => {\n const exists = await safeFileExists(folderName);\n if (!exists)\n return;\n await driver.removeEntry(folderName, { recursive: true });\n },\n });\n}\n"],"names":["addToDelta","deltas","fieldPath","changeKind","rawKey","identifier","delta","target","accumulateUpsertDelta","indicesToMaintain","existingItem","nextItem","value","get","accumulateRemoveDelta","createGenericFSAdapter","driver","folderName","itemsDirectoryPathPromise","indexRootPathPromise","safeFileExists","path","safeRemoveEntry","options","toItemsFilePath","toIndexPathForField","toIndexBucketFilePath","indexPath","bucketFileName","readItemsArrayOrEmpty","filePath","data","loadBucketIndexFromData","bucketIndex","entry","identifierList","writeBucketIndex","output","identifierSet","readBucketIndex","readAll","itemsDirectoryPath","relativeFiles","aggregatedItems","relativePath","fullPath","itemsInFile","ensureIndex","itemsPromise","allItems","indexMap","item","fieldValue","keyString","buckets","rawKeyString","records","readIndex","resultIndex","maps","applyIndexDeltas","touchedRawKeys","rawKeyToBucketFileName","touchedBucketFileNames","setForKey","removeIdFromIndex","changed","set","before","addIdToIndex","updateIndexForReplace","oldItem","newValue","upsertItems","items","mode","existingArray","indexOfItem","existing","updatedArray","createStorageAdapter","identifiers","pathToDrop","itemsToInsert","itemsToReplace","itemsToRemove"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/deltaHelpers.ts","../src/index.ts"],"sourcesContent":["import { get } from '@signaldb/core'\n\nexport type IndexDelta<I> = {\n adds: Map<string, Set<I>>,\n removes: Map<string, Set<I>>,\n}\n\n/**\n * Records a single index mutation into the delta map for a given indexed field.\n *\n * The delta map is grouped by `fieldPath`, and then by stringified key (`rawKey`).\n * Each key maps to a set of identifiers to add/remove for that key.\n * @param deltas - Accumulator of per-field index deltas.\n * @param fieldPath - Dot-path of the indexed field (used as the delta bucket key).\n * @param changeKind - Whether this identifier should be added to or removed from the index key.\n * @param rawKey - The stringified index key value.\n * @param identifier - The item identifier to add/remove for `rawKey`.\n */\nexport function addToDelta<I>(\n deltas: Map<string, IndexDelta<I>>,\n fieldPath: string,\n changeKind: 'add' | 'remove',\n rawKey: string,\n identifier: I,\n) {\n if (!deltas.has(fieldPath)) deltas.set(fieldPath, { adds: new Map(), removes: new Map() })\n const delta = deltas.get(fieldPath)\n if (!delta) return\n const target = changeKind === 'add' ? delta.adds : delta.removes\n if (!target.has(rawKey)) target.set(rawKey, new Set<I>())\n target.get(rawKey)?.add(identifier)\n}\n\n/**\n * Computes the delta for a change in a single indexed field.\n *\n * Values are coerced to string keys (with `null`/`undefined` treated as \"no key\").\n * If the derived keys are equal, no delta is recorded.\n * @param deltas - Accumulator of per-field index deltas.\n * @param fieldPath - Dot-path of the indexed field being tracked.\n * @param oldValue - Previous value of the field.\n * @param newValue - Next value of the field.\n * @param identifier - The item identifier affected by the change.\n */\nexport function addDeltaForChange<I>(\n deltas: Map<string, IndexDelta<I>>,\n fieldPath: string,\n oldValue: any,\n newValue: any,\n identifier: I,\n) {\n const oldKey = oldValue == null ? undefined : String(oldValue)\n const newKey = newValue == null ? undefined : String(newValue)\n if (oldKey === newKey) return\n if (oldKey != null) addToDelta(deltas, fieldPath, 'remove', oldKey, identifier)\n if (newKey != null) addToDelta(deltas, fieldPath, 'add', newKey, identifier)\n}\n\n/**\n * Accumulates index deltas for an upsert operation.\n *\n * - If `existingItem` is present, compares each maintained index field between the old and new item,\n * recording removes/adds for key changes.\n * - If `existingItem` is absent, treats the operation as an insert and records adds for each\n * maintained index field that has a non-null value.\n * @param deltas - Accumulator of per-field index deltas.\n * @param indicesToMaintain - List of dot-paths for fields that are indexed.\n * @param existingItem - Previous stored item (if any).\n * @param nextItem - Incoming item to upsert.\n */\nexport const accumulateUpsertDelta = <T extends { id: I }, I>(\n deltas: Map<string, IndexDelta<I>>,\n indicesToMaintain: string[],\n existingItem: T | undefined,\n nextItem: T,\n) => {\n if (existingItem) {\n for (const fieldPath of indicesToMaintain) {\n addDeltaForChange(\n deltas,\n fieldPath,\n get(existingItem, fieldPath),\n get(nextItem, fieldPath),\n nextItem.id,\n )\n }\n } else {\n for (const fieldPath of indicesToMaintain) {\n const value = get(nextItem, fieldPath)\n if (value == null) continue\n addToDelta(deltas, fieldPath, 'add', String(value), nextItem.id)\n }\n }\n}\n\n/**\n * Accumulates index deltas for a remove/delete operation.\n *\n * For each maintained index field, records a removal of the item's identifier from the\n * corresponding stringified key (skipping `null`/`undefined` values).\n * @param deltas - Accumulator of per-field index deltas.\n * @param indicesToMaintain - List of dot-paths for fields that are indexed.\n * @param existingItem - The item being removed.\n */\nexport function accumulateRemoveDelta<T extends { id: I }, I>(\n deltas: Map<string, IndexDelta<I>>,\n indicesToMaintain: string[],\n existingItem: T,\n) {\n for (const fieldPath of indicesToMaintain) {\n const value = get(existingItem, fieldPath)\n if (value == null) continue\n addToDelta(deltas, fieldPath, 'remove', String(value), existingItem.id)\n }\n}\n","import { createStorageAdapter, get } from '@signaldb/core'\nimport {\n accumulateUpsertDelta,\n accumulateRemoveDelta,\n type IndexDelta,\n} from './deltaHelpers'\n\n/**\n * A driver interface that abstracts low-level filesystem operations.\n * Implementations can back this with Node.js fs/promises, browser FS APIs, or other storage mechanisms.\n */\nexport interface Driver<\n T extends { id: I } & Record<string, unknown>,\n I,\n> {\n fileNameForId(id: I): Promise<string>,\n fileNameForIndexKey(key: string): Promise<string>,\n joinPath(...parts: string[]): Promise<string>,\n ensureDir(path: string): Promise<void>,\n fileExists(path: string): Promise<boolean>,\n readObject(path: string): Promise<T[] | null>,\n writeObject(path: string, value: T[]): Promise<void>,\n readIndexObject(path: string): Promise<Record<string, I[]>[] | null>,\n writeIndexObject(path: string, value: Record<string, I[]>[]): Promise<void>,\n listFilesRecursive(directoryPath: string): Promise<string[]>,\n removeEntry(path: string, options?: { recursive?: boolean }): Promise<void>,\n}\n\n/**\n * Creates a storage adapter for managing a SignalDB collection using a generic filesystem-like driver.\n * Data is sharded into subdirectories based on item identifiers, and indices are maintained as files.\n * @param driver - The driver that handles low-level file operations.\n * @param folderName - The root folder path for storing the collection data.\n * @returns A SignalDB storage adapter for managing data in a filesystem-like storage.\n */\nexport default function createGenericFSAdapter<\n T extends { id: I } & Record<string, unknown>,\n I,\n>(\n driver: Driver<T, I>,\n folderName: string,\n) {\n const itemsDirectoryPathPromise = driver.joinPath(folderName, 'items')\n const indexRootPathPromise = driver.joinPath(folderName, 'index')\n\n const safeFileExists = async (path: string): Promise<boolean> =>\n driver.fileExists(path).catch(() => false)\n\n const safeRemoveEntry = async (path: string, options?: { recursive?: boolean }) =>\n driver.removeEntry(path, options).catch(() => { /* ignore */ })\n\n const toItemsFilePath = async (identifier: I): Promise<string> =>\n driver.joinPath(await itemsDirectoryPathPromise, await driver.fileNameForId(identifier))\n\n const toIndexPathForField = async (fieldPath: string): Promise<string> =>\n driver.joinPath(await indexRootPathPromise, await driver.fileNameForIndexKey(fieldPath))\n\n const toIndexBucketFilePath = async (indexPath: string, rawKey: string): Promise<string> => {\n const bucketFileName = await driver.fileNameForIndexKey(rawKey)\n return driver.joinPath(indexPath, bucketFileName)\n }\n\n const readItemsArrayOrEmpty = async (filePath: string): Promise<T[]> => {\n const exists = await safeFileExists(filePath)\n if (!exists) return []\n const data = await driver.readObject(filePath).catch(() => [])\n return Array.isArray(data) ? data : []\n }\n\n const loadBucketIndexFromData = <K extends string>(\n data: Record<K, I[]>[] | null,\n ): Map<string, Set<I>> => {\n const bucketIndex = new Map<string, Set<I>>()\n if (!Array.isArray(data)) return bucketIndex\n for (const entry of data) {\n for (const [rawKey, identifierList] of Object.entries(entry)) {\n bucketIndex.set(rawKey, new Set(identifierList as I[]))\n }\n }\n return bucketIndex\n }\n\n const writeBucketIndex = async (\n filePath: string,\n bucketIndex: Map<string, Set<I>>,\n ) => {\n if (bucketIndex.size === 0) {\n const exists = await safeFileExists(filePath)\n if (exists) await safeRemoveEntry(filePath)\n return\n }\n const output: Record<string, I[]>[] = []\n bucketIndex.forEach((identifierSet, rawKey) => {\n output.push({ [rawKey]: [...identifierSet] as I[] })\n })\n await driver.writeIndexObject(filePath, output)\n }\n\n const readBucketIndex = async (filePath: string): Promise<Map<string, Set<I>>> => {\n const data = await driver.readIndexObject(filePath).catch(() => null)\n return loadBucketIndexFromData(data)\n }\n\n const readAll = async (): Promise<T[]> => {\n const itemsDirectoryPath = await itemsDirectoryPathPromise\n const directoryExists = await safeFileExists(itemsDirectoryPath)\n if (!directoryExists) return []\n\n const relativeFiles = await driver.listFilesRecursive(itemsDirectoryPath)\n const aggregatedItems: T[] = []\n\n await Promise.all(\n relativeFiles.map(async (relativePath) => {\n const fullPath = await driver.joinPath(itemsDirectoryPath, relativePath)\n const itemsInFile = await driver.readObject(fullPath).catch(() => null)\n if (Array.isArray(itemsInFile)) aggregatedItems.push(...itemsInFile)\n }),\n )\n\n return aggregatedItems\n }\n\n const ensureIndex = async (\n fieldPath: string,\n itemsPromise: Promise<T[]> = readAll(),\n ): Promise<void> => {\n const allItems = await itemsPromise\n const indexPath = await toIndexPathForField(fieldPath)\n\n await safeRemoveEntry(indexPath, { recursive: true })\n await driver.ensureDir(indexPath)\n\n // Build value -> Set<identifier>\n const indexMap = new Map<string, Set<I>>()\n for (const item of allItems) {\n const fieldValue = get(item, fieldPath)\n if (fieldValue == null) continue\n const keyString = String(fieldValue)\n if (!indexMap.has(keyString)) indexMap.set(keyString, new Set<I>())\n indexMap.get(keyString)?.add(item.id)\n }\n\n // Group entries by bucket file name, then persist each bucket\n const buckets: Record<string, Record<string, I[]>[]> = {}\n for (const [rawKeyString, identifierSet] of indexMap) {\n const bucketFileName = await driver.fileNameForIndexKey(rawKeyString)\n if (!buckets[bucketFileName]) buckets[bucketFileName] = []\n buckets[bucketFileName].push({ [rawKeyString]: [...identifierSet] })\n }\n\n await Promise.all(\n Object.entries(buckets).map(async ([bucketFileName, records]) => {\n const filePath = await driver.joinPath(indexPath, bucketFileName)\n await driver.writeIndexObject(filePath, records)\n }),\n )\n }\n\n const readIndex = async (fieldPath: string) => {\n const indexPath = await toIndexPathForField(fieldPath)\n const indexExists = await safeFileExists(indexPath)\n if (!indexExists) throw new Error(`Index on field \"${fieldPath}\" does not exist`)\n\n const relativeFiles = await driver.listFilesRecursive(indexPath)\n const resultIndex = new Map<string, Set<I>>()\n\n await Promise.all(\n relativeFiles.map(async (relativePath) => {\n const fullPath = await driver.joinPath(indexPath, relativePath)\n const maps = await driver.readIndexObject(fullPath).catch(() => null)\n if (!Array.isArray(maps)) return\n for (const entry of maps) {\n for (const [rawKey, identifierList] of Object.entries(entry)) {\n if (!resultIndex.has(rawKey)) resultIndex.set(rawKey, new Set<I>())\n const target = resultIndex.get(rawKey)\n for (const identifier of identifierList) target?.add(identifier)\n }\n }\n }),\n )\n\n return resultIndex\n }\n\n // Track which field paths should be kept up-to-date incrementally.\n const indicesToMaintain: string[] = []\n\n const applyIndexDeltas = async (deltas: Map<string, IndexDelta<I>>) => {\n // For each indexed field with changes, touch only the affected bucket files\n await Promise.all(\n [...deltas.entries()].map(async ([fieldPath, delta]) => {\n const indexPath = await toIndexPathForField(fieldPath)\n const indexExists = await safeFileExists(indexPath)\n if (!indexExists) return // Only update indices that exist\n await driver.ensureDir(indexPath)\n\n // Compute impacted bucket filenames\n const touchedRawKeys = new Set<string>([\n ...delta.adds.keys(),\n ...delta.removes.keys(),\n ])\n\n const rawKeyToBucketFileName = new Map<string, string>()\n await Promise.all(\n [...touchedRawKeys].map(async (rawKey) => {\n rawKeyToBucketFileName.set(rawKey, await driver.fileNameForIndexKey(rawKey))\n }),\n )\n\n const touchedBucketFileNames = new Set<string>(rawKeyToBucketFileName.values())\n\n await Promise.all(\n [...touchedBucketFileNames].map(async (bucketFileName) => {\n const filePath = await driver.joinPath(indexPath, bucketFileName)\n const bucketIndex = await readBucketIndex(filePath)\n\n // Apply removals for keys that map to this bucket\n delta.removes.forEach((identifierSet, rawKey) => {\n if (rawKeyToBucketFileName.get(rawKey) !== bucketFileName) return\n const setForKey = bucketIndex.get(rawKey)\n if (!setForKey) return\n identifierSet.forEach(identifier => setForKey.delete(identifier))\n if (setForKey.size === 0) bucketIndex.delete(rawKey)\n })\n\n // Apply additions\n delta.adds.forEach((identifierSet, rawKey) => {\n if (rawKeyToBucketFileName.get(rawKey) !== bucketFileName) return\n const setForKey = bucketIndex.get(rawKey) ?? new Set<I>()\n identifierSet.forEach(identifier => setForKey.add(identifier))\n bucketIndex.set(rawKey, setForKey)\n })\n\n await writeBucketIndex(filePath, bucketIndex)\n }),\n )\n }),\n )\n }\n\n const removeIdFromIndex = async (fieldPath: string, identifier: I) => {\n const indexPath = await toIndexPathForField(fieldPath)\n const indexExists = await safeFileExists(indexPath)\n if (!indexExists) return\n\n const relativeFiles = await driver.listFilesRecursive(indexPath)\n await Promise.all(\n relativeFiles.map(async (relativePath) => {\n const filePath = await driver.joinPath(indexPath, relativePath)\n const data = await driver.readIndexObject(filePath).catch(() => null)\n if (!Array.isArray(data)) return\n\n let changed = false\n const bucketIndex = new Map<string, Set<I>>()\n for (const entry of data) {\n for (const [rawKey, identifierList] of Object.entries(entry)) {\n const set = new Set<I>(identifierList)\n const before = set.size\n set.delete(identifier)\n if (set.size !== before) changed = true\n if (set.size > 0) bucketIndex.set(rawKey, set)\n }\n }\n\n if (!changed) return\n await writeBucketIndex(filePath, bucketIndex)\n }),\n )\n }\n\n const addIdToIndex = async (fieldPath: string, value: any, identifier: I) => {\n if (value == null) return\n const rawKey = String(value)\n\n const indexPath = await toIndexPathForField(fieldPath)\n const indexExists = await safeFileExists(indexPath)\n if (!indexExists) return\n await driver.ensureDir(indexPath)\n\n const filePath = await toIndexBucketFilePath(indexPath, rawKey)\n const bucketIndex = await readBucketIndex(filePath)\n\n const setForKey = bucketIndex.get(rawKey) ?? new Set<I>()\n setForKey.add(identifier)\n bucketIndex.set(rawKey, setForKey)\n\n await writeBucketIndex(filePath, bucketIndex)\n }\n\n const updateIndexForReplace = async (oldItem: T, nextItem: T) => {\n await Promise.all(\n indicesToMaintain.map(async (fieldPath) => {\n await removeIdFromIndex(fieldPath, oldItem.id)\n const newValue = get(nextItem, fieldPath)\n await addIdToIndex(fieldPath, newValue, nextItem.id)\n }),\n )\n }\n\n const upsertItems = async (\n items: T[],\n mode: 'insert' | 'replace',\n ) => {\n const deltas = new Map<string, IndexDelta<I>>()\n\n await Promise.all(\n items.map(async (item) => {\n const filePath = await toItemsFilePath(item.id)\n const existingArray = await readItemsArrayOrEmpty(filePath)\n const indexOfItem = existingArray.findIndex(existing => existing.id === item.id)\n\n if (mode === 'insert') {\n if (indexOfItem !== -1) throw new Error(`Item with id \"${String(item.id)}\" already exists`)\n accumulateUpsertDelta(deltas, indicesToMaintain, undefined, item)\n await driver.writeObject(filePath, [...existingArray, item])\n } else {\n if (indexOfItem === -1) throw new Error(`Item with id \"${String(item.id)}\" does not exist`)\n const updatedArray = [...existingArray]\n const oldItem = updatedArray[indexOfItem]\n updatedArray[indexOfItem] = item\n await driver.writeObject(filePath, updatedArray)\n await updateIndexForReplace(oldItem, item)\n }\n }),\n )\n\n // Only apply deltas for inserts (replace handled by direct purge+add)\n if (deltas.size > 0) {\n await applyIndexDeltas(deltas)\n }\n }\n\n return createStorageAdapter<T, I>({\n setup: async () => {\n await driver.ensureDir(folderName)\n },\n\n teardown: async () => {\n // no-op\n },\n\n readAll,\n\n readIds: async (identifiers) => {\n const results: (T | null)[] = await Promise.all(\n identifiers.map(async (identifier) => {\n const filePath = await toItemsFilePath(identifier)\n const itemsInFile = await driver.readObject(filePath).catch(() => []) ?? []\n if (!Array.isArray(itemsInFile)) return null\n return itemsInFile.find(item => item.id === identifier) ?? null\n }),\n )\n return results.filter((value): value is T => value != null)\n },\n\n createIndex: async (fieldPath) => {\n if (fieldPath === 'id') throw new Error('Cannot create index on id field')\n indicesToMaintain.push(fieldPath)\n await ensureIndex(fieldPath)\n },\n\n dropIndex: async (fieldPath) => {\n const pathToDrop = await toIndexPathForField(fieldPath)\n const exists = await safeFileExists(pathToDrop)\n if (!exists) throw new Error(`Index on field \"${fieldPath}\" does not exist`)\n await driver.removeEntry(pathToDrop, { recursive: true })\n },\n\n readIndex,\n\n insert: async (itemsToInsert) => {\n await upsertItems(itemsToInsert, 'insert')\n },\n\n replace: async (itemsToReplace) => {\n await upsertItems(itemsToReplace, 'replace')\n },\n\n remove: async (itemsToRemove) => {\n const deltas = new Map<string, IndexDelta<I>>()\n\n await Promise.all(\n itemsToRemove.map(async (item) => {\n const filePath = await toItemsFilePath(item.id)\n const existingArray = await readItemsArrayOrEmpty(filePath)\n const indexOfItem = existingArray.findIndex(existing => existing.id === item.id)\n if (indexOfItem === -1) throw new Error(`Item with id \"${String(item.id)}\" does not exist`)\n\n accumulateRemoveDelta(deltas, indicesToMaintain, existingArray[indexOfItem])\n\n const updatedArray = [...existingArray]\n updatedArray.splice(indexOfItem, 1)\n await (updatedArray.length === 0\n ? driver.removeEntry(filePath).catch(() => { /* ignore */ })\n : driver.writeObject(filePath, updatedArray))\n }),\n )\n\n await applyIndexDeltas(deltas)\n },\n\n removeAll: async () => {\n const exists = await safeFileExists(folderName)\n if (!exists) return\n await driver.removeEntry(folderName, { recursive: true })\n },\n })\n}\n"],"mappings":"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"}
package/dist/index.umd.js CHANGED
@@ -1,2 +1,2 @@
1
- (function(x,E){typeof exports=="object"&&typeof module<"u"?module.exports=E(require("@signaldb/core")):typeof define=="function"&&define.amd?define(["@signaldb/core"],E):(x=typeof globalThis<"u"?globalThis:x||self,x.SignalDB=E(x.core))})(this,(function(x){"use strict";function E(e,l,I,f,d){e.has(l)||e.set(l,{adds:new Map,removes:new Map});const h=e.get(l);if(!h)return;const g=I==="add"?h.adds:h.removes;g.has(f)||g.set(f,new Set),g.get(f)?.add(d)}const R=(e,l,I,f)=>{for(const d of l){const h=x.get(f,d);h!=null&&E(e,d,"add",String(h),f.id)}};function B(e,l,I){for(const f of l){const d=x.get(I,f);d!=null&&E(e,f,"remove",String(d),I.id)}}function K(e,l){const I=e.joinPath(l,"items"),f=e.joinPath(l,"index"),d=async t=>e.fileExists(t).catch(()=>!1),h=async(t,n)=>e.removeEntry(t,n).catch(()=>{}),g=async t=>e.joinPath(await I,await e.fileNameForId(t)),F=async t=>e.joinPath(await f,await e.fileNameForIndexKey(t)),T=async(t,n)=>{const a=await e.fileNameForIndexKey(n);return e.joinPath(t,a)},A=async t=>{if(!await d(t))return[];const a=await e.readObject(t).catch(()=>[]);return Array.isArray(a)?a:[]},z=t=>{const n=new Map;if(!Array.isArray(t))return n;for(const a of t)for(const[s,i]of Object.entries(a))n.set(s,new Set(i));return n},S=async(t,n)=>{if(n.size===0){await d(t)&&await h(t);return}const a=[];n.forEach((s,i)=>{a.push({[i]:[...s]})}),await e.writeIndexObject(t,a)},O=async t=>{const n=await e.readIndexObject(t).catch(()=>null);return z(n)},k=async()=>{const t=await I;if(!await d(t))return[];const a=await e.listFilesRecursive(t),s=[];return await Promise.all(a.map(async i=>{const w=await e.joinPath(t,i),o=await e.readObject(w).catch(()=>null);Array.isArray(o)&&s.push(...o)})),s},$=async(t,n=k())=>{const a=await n,s=await F(t);await h(s,{recursive:!0}),await e.ensureDir(s);const i=new Map;for(const o of a){const c=x.get(o,t);if(c==null)continue;const r=String(c);i.has(r)||i.set(r,new Set),i.get(r)?.add(o.id)}const w={};for(const[o,c]of i){const r=await e.fileNameForIndexKey(o);w[r]||(w[r]=[]),w[r].push({[o]:[...c]})}await Promise.all(Object.entries(w).map(async([o,c])=>{const r=await e.joinPath(s,o);await e.writeIndexObject(r,c)}))},L=async t=>{const n=await F(t);if(!await d(n))throw new Error(`Index on field "${t}" does not exist`);const s=await e.listFilesRecursive(n),i=new Map;return await Promise.all(s.map(async w=>{const o=await e.joinPath(n,w),c=await e.readIndexObject(o).catch(()=>null);if(Array.isArray(c))for(const r of c)for(const[m,p]of Object.entries(r)){i.has(m)||i.set(m,new Set);const P=i.get(m);for(const y of p)P?.add(y)}})),i},b=[],D=async t=>{await Promise.all([...t.entries()].map(async([n,a])=>{const s=await F(n);if(!await d(s))return;await e.ensureDir(s);const w=new Set([...a.adds.keys(),...a.removes.keys()]),o=new Map;await Promise.all([...w].map(async r=>{o.set(r,await e.fileNameForIndexKey(r))}));const c=new Set(o.values());await Promise.all([...c].map(async r=>{const m=await e.joinPath(s,r),p=await O(m);a.removes.forEach((P,y)=>{if(o.get(y)!==r)return;const u=p.get(y);u&&(P.forEach(j=>u.delete(j)),u.size===0&&p.delete(y))}),a.adds.forEach((P,y)=>{if(o.get(y)!==r)return;const u=p.get(y)??new Set;P.forEach(j=>u.add(j)),p.set(y,u)}),await S(m,p)}))}))},N=async(t,n)=>{const a=await F(t);if(!await d(a))return;const i=await e.listFilesRecursive(a);await Promise.all(i.map(async w=>{const o=await e.joinPath(a,w),c=await e.readIndexObject(o).catch(()=>null);if(!Array.isArray(c))return;let r=!1;const m=new Map;for(const p of c)for(const[P,y]of Object.entries(p)){const u=new Set(y),j=u.size;u.delete(n),u.size!==j&&(r=!0),u.size>0&&m.set(P,u)}r&&await S(o,m)}))},V=async(t,n,a)=>{if(n==null)return;const s=String(n),i=await F(t);if(!await d(i))return;await e.ensureDir(i);const o=await T(i,s),c=await O(o),r=c.get(s)??new Set;r.add(a),c.set(s,r),await S(o,c)},q=async(t,n)=>{await Promise.all(b.map(async a=>{await N(a,t.id);const s=x.get(n,a);await V(a,s,n.id)}))},M=async(t,n)=>{const a=new Map;await Promise.all(t.map(async s=>{const i=await g(s.id),w=await A(i),o=w.findIndex(c=>c.id===s.id);if(n==="insert"){if(o!==-1)throw new Error(`Item with id "${String(s.id)}" already exists`);R(a,b,void 0,s),await e.writeObject(i,[...w,s])}else{if(o===-1)throw new Error(`Item with id "${String(s.id)}" does not exist`);const c=[...w],r=c[o];c[o]=s,await e.writeObject(i,c),await q(r,s)}})),a.size>0&&await D(a)};return x.createStorageAdapter({setup:async()=>{await e.ensureDir(l)},teardown:async()=>{},readAll:k,readIds:async t=>(await Promise.all(t.map(async a=>{const s=await g(a),i=await e.readObject(s).catch(()=>[])??[];return Array.isArray(i)?i.find(w=>w.id===a)??null:null}))).filter(a=>a!=null),createIndex:async t=>{if(t==="id")throw new Error("Cannot create index on id field");b.push(t),await $(t)},dropIndex:async t=>{const n=await F(t);if(!await d(n))throw new Error(`Index on field "${t}" does not exist`);await e.removeEntry(n,{recursive:!0})},readIndex:L,insert:async t=>{await M(t,"insert")},replace:async t=>{await M(t,"replace")},remove:async t=>{const n=new Map;await Promise.all(t.map(async a=>{const s=await g(a.id),i=await A(s),w=i.findIndex(c=>c.id===a.id);if(w===-1)throw new Error(`Item with id "${String(a.id)}" does not exist`);B(n,b,i[w]);const o=[...i];o.splice(w,1),await(o.length===0?e.removeEntry(s).catch(()=>{}):e.writeObject(s,o))})),await D(n)},removeAll:async()=>{await d(l)&&await e.removeEntry(l,{recursive:!0})}})}return K}));
2
- //# sourceMappingURL=index.umd.js.map
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?module.exports=t(require("@signaldb/core")):typeof define==`function`&&define.amd?define([`@signaldb/core`],t):(e=typeof globalThis<`u`?globalThis:e||self,e.SignalDB=t(e._signaldb_core))})(this,function(e){function t(e,t,n,r,i){e.has(t)||e.set(t,{adds:new Map,removes:new Map});let a=e.get(t);if(!a)return;let o=n===`add`?a.adds:a.removes;o.has(r)||o.set(r,new Set),o.get(r)?.add(i)}function n(e,n,r,i,a){let o=r==null?void 0:String(r),s=i==null?void 0:String(i);o!==s&&(o!=null&&t(e,n,`remove`,o,a),s!=null&&t(e,n,`add`,s,a))}var r=(r,i,a,o)=>{if(a)for(let t of i)n(r,t,(0,e.get)(a,t),(0,e.get)(o,t),o.id);else for(let n of i){let i=(0,e.get)(o,n);i!=null&&t(r,n,`add`,String(i),o.id)}};function i(n,r,i){for(let a of r){let r=(0,e.get)(i,a);r!=null&&t(n,a,`remove`,String(r),i.id)}}function a(t,n){let a=t.joinPath(n,`items`),o=t.joinPath(n,`index`),s=async e=>t.fileExists(e).catch(()=>!1),c=async(e,n)=>t.removeEntry(e,n).catch(()=>{}),l=async e=>t.joinPath(await a,await t.fileNameForId(e)),u=async e=>t.joinPath(await o,await t.fileNameForIndexKey(e)),d=async(e,n)=>{let r=await t.fileNameForIndexKey(n);return t.joinPath(e,r)},f=async e=>{if(!await s(e))return[];let n=await t.readObject(e).catch(()=>[]);return Array.isArray(n)?n:[]},p=e=>{let t=new Map;if(!Array.isArray(e))return t;for(let n of e)for(let[e,r]of Object.entries(n))t.set(e,new Set(r));return t},m=async(e,n)=>{if(n.size===0){await s(e)&&await c(e);return}let r=[];n.forEach((e,t)=>{r.push({[t]:[...e]})}),await t.writeIndexObject(e,r)},h=async e=>p(await t.readIndexObject(e).catch(()=>null)),g=async()=>{let e=await a;if(!await s(e))return[];let n=await t.listFilesRecursive(e),r=[];return await Promise.all(n.map(async n=>{let i=await t.joinPath(e,n),a=await t.readObject(i).catch(()=>null);Array.isArray(a)&&r.push(...a)})),r},_=async(n,r=g())=>{let i=await r,a=await u(n);await c(a,{recursive:!0}),await t.ensureDir(a);let o=new Map;for(let t of i){let r=(0,e.get)(t,n);if(r==null)continue;let i=String(r);o.has(i)||o.set(i,new Set),o.get(i)?.add(t.id)}let s={};for(let[e,n]of o){let r=await t.fileNameForIndexKey(e);s[r]||(s[r]=[]),s[r].push({[e]:[...n]})}await Promise.all(Object.entries(s).map(async([e,n])=>{let r=await t.joinPath(a,e);await t.writeIndexObject(r,n)}))},v=async e=>{let n=await u(e);if(!await s(n))throw Error(`Index on field "${e}" does not exist`);let r=await t.listFilesRecursive(n),i=new Map;return await Promise.all(r.map(async e=>{let r=await t.joinPath(n,e),a=await t.readIndexObject(r).catch(()=>null);if(Array.isArray(a))for(let e of a)for(let[t,n]of Object.entries(e)){i.has(t)||i.set(t,new Set);let e=i.get(t);for(let t of n)e?.add(t)}})),i},y=[],b=async e=>{await Promise.all([...e.entries()].map(async([e,n])=>{let r=await u(e);if(!await s(r))return;await t.ensureDir(r);let i=new Set([...n.adds.keys(),...n.removes.keys()]),a=new Map;await Promise.all([...i].map(async e=>{a.set(e,await t.fileNameForIndexKey(e))}));let o=new Set(a.values());await Promise.all([...o].map(async e=>{let i=await t.joinPath(r,e),o=await h(i);n.removes.forEach((t,n)=>{if(a.get(n)!==e)return;let r=o.get(n);r&&(t.forEach(e=>r.delete(e)),r.size===0&&o.delete(n))}),n.adds.forEach((t,n)=>{if(a.get(n)!==e)return;let r=o.get(n)??new Set;t.forEach(e=>r.add(e)),o.set(n,r)}),await m(i,o)}))}))},x=async(e,n)=>{let r=await u(e);if(!await s(r))return;let i=await t.listFilesRecursive(r);await Promise.all(i.map(async e=>{let i=await t.joinPath(r,e),a=await t.readIndexObject(i).catch(()=>null);if(!Array.isArray(a))return;let o=!1,s=new Map;for(let e of a)for(let[t,r]of Object.entries(e)){let e=new Set(r),i=e.size;e.delete(n),e.size!==i&&(o=!0),e.size>0&&s.set(t,e)}o&&await m(i,s)}))},S=async(e,n,r)=>{if(n==null)return;let i=String(n),a=await u(e);if(!await s(a))return;await t.ensureDir(a);let o=await d(a,i),c=await h(o),l=c.get(i)??new Set;l.add(r),c.set(i,l),await m(o,c)},C=async(t,n)=>{await Promise.all(y.map(async r=>{await x(r,t.id),await S(r,(0,e.get)(n,r),n.id)}))},w=async(e,n)=>{let i=new Map;await Promise.all(e.map(async e=>{let a=await l(e.id),o=await f(a),s=o.findIndex(t=>t.id===e.id);if(n===`insert`){if(s!==-1)throw Error(`Item with id "${String(e.id)}" already exists`);r(i,y,void 0,e),await t.writeObject(a,[...o,e])}else{if(s===-1)throw Error(`Item with id "${String(e.id)}" does not exist`);let n=[...o],r=n[s];n[s]=e,await t.writeObject(a,n),await C(r,e)}})),i.size>0&&await b(i)};return(0,e.createStorageAdapter)({setup:async()=>{await t.ensureDir(n)},teardown:async()=>{},readAll:g,readIds:async e=>(await Promise.all(e.map(async e=>{let n=await l(e),r=await t.readObject(n).catch(()=>[])??[];return Array.isArray(r)?r.find(t=>t.id===e)??null:null}))).filter(e=>e!=null),createIndex:async e=>{if(e===`id`)throw Error(`Cannot create index on id field`);y.push(e),await _(e)},dropIndex:async e=>{let n=await u(e);if(!await s(n))throw Error(`Index on field "${e}" does not exist`);await t.removeEntry(n,{recursive:!0})},readIndex:v,insert:async e=>{await w(e,`insert`)},replace:async e=>{await w(e,`replace`)},remove:async e=>{let n=new Map;await Promise.all(e.map(async e=>{let r=await l(e.id),a=await f(r),o=a.findIndex(t=>t.id===e.id);if(o===-1)throw Error(`Item with id "${String(e.id)}" does not exist`);i(n,y,a[o]);let s=[...a];s.splice(o,1),await(s.length===0?t.removeEntry(r).catch(()=>{}):t.writeObject(r,s))})),await b(n)},removeAll:async()=>{await s(n)&&await t.removeEntry(n,{recursive:!0})}})}return a});
2
+ //# sourceMappingURL=index.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.umd.js","sources":["../src/deltaHelpers.ts","../src/index.ts"],"sourcesContent":["import { get } from '@signaldb/core';\n/**\n * Records a single index mutation into the delta map for a given indexed field.\n *\n * The delta map is grouped by `fieldPath`, and then by stringified key (`rawKey`).\n * Each key maps to a set of identifiers to add/remove for that key.\n * @param deltas - Accumulator of per-field index deltas.\n * @param fieldPath - Dot-path of the indexed field (used as the delta bucket key).\n * @param changeKind - Whether this identifier should be added to or removed from the index key.\n * @param rawKey - The stringified index key value.\n * @param identifier - The item identifier to add/remove for `rawKey`.\n */\nexport function addToDelta(deltas, fieldPath, changeKind, rawKey, identifier) {\n if (!deltas.has(fieldPath))\n deltas.set(fieldPath, { adds: new Map(), removes: new Map() });\n const delta = deltas.get(fieldPath);\n if (!delta)\n return;\n const target = changeKind === 'add' ? delta.adds : delta.removes;\n if (!target.has(rawKey))\n target.set(rawKey, new Set());\n target.get(rawKey)?.add(identifier);\n}\n/**\n * Computes the delta for a change in a single indexed field.\n *\n * Values are coerced to string keys (with `null`/`undefined` treated as \"no key\").\n * If the derived keys are equal, no delta is recorded.\n * @param deltas - Accumulator of per-field index deltas.\n * @param fieldPath - Dot-path of the indexed field being tracked.\n * @param oldValue - Previous value of the field.\n * @param newValue - Next value of the field.\n * @param identifier - The item identifier affected by the change.\n */\nexport function addDeltaForChange(deltas, fieldPath, oldValue, newValue, identifier) {\n const oldKey = oldValue == null ? undefined : String(oldValue);\n const newKey = newValue == null ? undefined : String(newValue);\n if (oldKey === newKey)\n return;\n if (oldKey != null)\n addToDelta(deltas, fieldPath, 'remove', oldKey, identifier);\n if (newKey != null)\n addToDelta(deltas, fieldPath, 'add', newKey, identifier);\n}\n/**\n * Accumulates index deltas for an upsert operation.\n *\n * - If `existingItem` is present, compares each maintained index field between the old and new item,\n * recording removes/adds for key changes.\n * - If `existingItem` is absent, treats the operation as an insert and records adds for each\n * maintained index field that has a non-null value.\n * @param deltas - Accumulator of per-field index deltas.\n * @param indicesToMaintain - List of dot-paths for fields that are indexed.\n * @param existingItem - Previous stored item (if any).\n * @param nextItem - Incoming item to upsert.\n */\nexport const accumulateUpsertDelta = (deltas, indicesToMaintain, existingItem, nextItem) => {\n if (existingItem) {\n for (const fieldPath of indicesToMaintain) {\n addDeltaForChange(deltas, fieldPath, get(existingItem, fieldPath), get(nextItem, fieldPath), nextItem.id);\n }\n }\n else {\n for (const fieldPath of indicesToMaintain) {\n const value = get(nextItem, fieldPath);\n if (value == null)\n continue;\n addToDelta(deltas, fieldPath, 'add', String(value), nextItem.id);\n }\n }\n};\n/**\n * Accumulates index deltas for a remove/delete operation.\n *\n * For each maintained index field, records a removal of the item's identifier from the\n * corresponding stringified key (skipping `null`/`undefined` values).\n * @param deltas - Accumulator of per-field index deltas.\n * @param indicesToMaintain - List of dot-paths for fields that are indexed.\n * @param existingItem - The item being removed.\n */\nexport function accumulateRemoveDelta(deltas, indicesToMaintain, existingItem) {\n for (const fieldPath of indicesToMaintain) {\n const value = get(existingItem, fieldPath);\n if (value == null)\n continue;\n addToDelta(deltas, fieldPath, 'remove', String(value), existingItem.id);\n }\n}\n","import { createStorageAdapter, get } from '@signaldb/core';\nimport { accumulateUpsertDelta, accumulateRemoveDelta, } from './deltaHelpers';\n/**\n * Creates a storage adapter for managing a SignalDB collection using a generic filesystem-like driver.\n * Data is sharded into subdirectories based on item identifiers, and indices are maintained as files.\n * @param driver - The driver that handles low-level file operations.\n * @param folderName - The root folder path for storing the collection data.\n * @returns A SignalDB storage adapter for managing data in a filesystem-like storage.\n */\nexport default function createGenericFSAdapter(driver, folderName) {\n const itemsDirectoryPathPromise = driver.joinPath(folderName, 'items');\n const indexRootPathPromise = driver.joinPath(folderName, 'index');\n const safeFileExists = async (path) => driver.fileExists(path).catch(() => false);\n const safeRemoveEntry = async (path, options) => driver.removeEntry(path, options).catch(() => { });\n const toItemsFilePath = async (identifier) => driver.joinPath(await itemsDirectoryPathPromise, await driver.fileNameForId(identifier));\n const toIndexPathForField = async (fieldPath) => driver.joinPath(await indexRootPathPromise, await driver.fileNameForIndexKey(fieldPath));\n const toIndexBucketFilePath = async (indexPath, rawKey) => {\n const bucketFileName = await driver.fileNameForIndexKey(rawKey);\n return driver.joinPath(indexPath, bucketFileName);\n };\n const readItemsArrayOrEmpty = async (filePath) => {\n const exists = await safeFileExists(filePath);\n if (!exists)\n return [];\n const data = await driver.readObject(filePath).catch(() => []);\n return Array.isArray(data) ? data : [];\n };\n const loadBucketIndexFromData = (data) => {\n const bucketIndex = new Map();\n if (!Array.isArray(data))\n return bucketIndex;\n for (const entry of data) {\n for (const [rawKey, identifierList] of Object.entries(entry)) {\n bucketIndex.set(rawKey, new Set(identifierList));\n }\n }\n return bucketIndex;\n };\n const writeBucketIndex = async (filePath, bucketIndex) => {\n if (bucketIndex.size === 0) {\n const exists = await safeFileExists(filePath);\n if (exists)\n await safeRemoveEntry(filePath);\n return;\n }\n const output = [];\n bucketIndex.forEach((identifierSet, rawKey) => {\n output.push({ [rawKey]: [...identifierSet] });\n });\n await driver.writeIndexObject(filePath, output);\n };\n const readBucketIndex = async (filePath) => {\n const data = await driver.readIndexObject(filePath).catch(() => null);\n return loadBucketIndexFromData(data);\n };\n const readAll = async () => {\n const itemsDirectoryPath = await itemsDirectoryPathPromise;\n const directoryExists = await safeFileExists(itemsDirectoryPath);\n if (!directoryExists)\n return [];\n const relativeFiles = await driver.listFilesRecursive(itemsDirectoryPath);\n const aggregatedItems = [];\n await Promise.all(relativeFiles.map(async (relativePath) => {\n const fullPath = await driver.joinPath(itemsDirectoryPath, relativePath);\n const itemsInFile = await driver.readObject(fullPath).catch(() => null);\n if (Array.isArray(itemsInFile))\n aggregatedItems.push(...itemsInFile);\n }));\n return aggregatedItems;\n };\n const ensureIndex = async (fieldPath, itemsPromise = readAll()) => {\n const allItems = await itemsPromise;\n const indexPath = await toIndexPathForField(fieldPath);\n await safeRemoveEntry(indexPath, { recursive: true });\n await driver.ensureDir(indexPath);\n // Build value -> Set<identifier>\n const indexMap = new Map();\n for (const item of allItems) {\n const fieldValue = get(item, fieldPath);\n if (fieldValue == null)\n continue;\n const keyString = String(fieldValue);\n if (!indexMap.has(keyString))\n indexMap.set(keyString, new Set());\n indexMap.get(keyString)?.add(item.id);\n }\n // Group entries by bucket file name, then persist each bucket\n const buckets = {};\n for (const [rawKeyString, identifierSet] of indexMap) {\n const bucketFileName = await driver.fileNameForIndexKey(rawKeyString);\n if (!buckets[bucketFileName])\n buckets[bucketFileName] = [];\n buckets[bucketFileName].push({ [rawKeyString]: [...identifierSet] });\n }\n await Promise.all(Object.entries(buckets).map(async ([bucketFileName, records]) => {\n const filePath = await driver.joinPath(indexPath, bucketFileName);\n await driver.writeIndexObject(filePath, records);\n }));\n };\n const readIndex = async (fieldPath) => {\n const indexPath = await toIndexPathForField(fieldPath);\n const indexExists = await safeFileExists(indexPath);\n if (!indexExists)\n throw new Error(`Index on field \"${fieldPath}\" does not exist`);\n const relativeFiles = await driver.listFilesRecursive(indexPath);\n const resultIndex = new Map();\n await Promise.all(relativeFiles.map(async (relativePath) => {\n const fullPath = await driver.joinPath(indexPath, relativePath);\n const maps = await driver.readIndexObject(fullPath).catch(() => null);\n if (!Array.isArray(maps))\n return;\n for (const entry of maps) {\n for (const [rawKey, identifierList] of Object.entries(entry)) {\n if (!resultIndex.has(rawKey))\n resultIndex.set(rawKey, new Set());\n const target = resultIndex.get(rawKey);\n for (const identifier of identifierList)\n target?.add(identifier);\n }\n }\n }));\n return resultIndex;\n };\n // Track which field paths should be kept up-to-date incrementally.\n const indicesToMaintain = [];\n const applyIndexDeltas = async (deltas) => {\n // For each indexed field with changes, touch only the affected bucket files\n await Promise.all([...deltas.entries()].map(async ([fieldPath, delta]) => {\n const indexPath = await toIndexPathForField(fieldPath);\n const indexExists = await safeFileExists(indexPath);\n if (!indexExists)\n return; // Only update indices that exist\n await driver.ensureDir(indexPath);\n // Compute impacted bucket filenames\n const touchedRawKeys = new Set([\n ...delta.adds.keys(),\n ...delta.removes.keys(),\n ]);\n const rawKeyToBucketFileName = new Map();\n await Promise.all([...touchedRawKeys].map(async (rawKey) => {\n rawKeyToBucketFileName.set(rawKey, await driver.fileNameForIndexKey(rawKey));\n }));\n const touchedBucketFileNames = new Set(rawKeyToBucketFileName.values());\n await Promise.all([...touchedBucketFileNames].map(async (bucketFileName) => {\n const filePath = await driver.joinPath(indexPath, bucketFileName);\n const bucketIndex = await readBucketIndex(filePath);\n // Apply removals for keys that map to this bucket\n delta.removes.forEach((identifierSet, rawKey) => {\n if (rawKeyToBucketFileName.get(rawKey) !== bucketFileName)\n return;\n const setForKey = bucketIndex.get(rawKey);\n if (!setForKey)\n return;\n identifierSet.forEach(identifier => setForKey.delete(identifier));\n if (setForKey.size === 0)\n bucketIndex.delete(rawKey);\n });\n // Apply additions\n delta.adds.forEach((identifierSet, rawKey) => {\n if (rawKeyToBucketFileName.get(rawKey) !== bucketFileName)\n return;\n const setForKey = bucketIndex.get(rawKey) ?? new Set();\n identifierSet.forEach(identifier => setForKey.add(identifier));\n bucketIndex.set(rawKey, setForKey);\n });\n await writeBucketIndex(filePath, bucketIndex);\n }));\n }));\n };\n const removeIdFromIndex = async (fieldPath, identifier) => {\n const indexPath = await toIndexPathForField(fieldPath);\n const indexExists = await safeFileExists(indexPath);\n if (!indexExists)\n return;\n const relativeFiles = await driver.listFilesRecursive(indexPath);\n await Promise.all(relativeFiles.map(async (relativePath) => {\n const filePath = await driver.joinPath(indexPath, relativePath);\n const data = await driver.readIndexObject(filePath).catch(() => null);\n if (!Array.isArray(data))\n return;\n let changed = false;\n const bucketIndex = new Map();\n for (const entry of data) {\n for (const [rawKey, identifierList] of Object.entries(entry)) {\n const set = new Set(identifierList);\n const before = set.size;\n set.delete(identifier);\n if (set.size !== before)\n changed = true;\n if (set.size > 0)\n bucketIndex.set(rawKey, set);\n }\n }\n if (!changed)\n return;\n await writeBucketIndex(filePath, bucketIndex);\n }));\n };\n const addIdToIndex = async (fieldPath, value, identifier) => {\n if (value == null)\n return;\n const rawKey = String(value);\n const indexPath = await toIndexPathForField(fieldPath);\n const indexExists = await safeFileExists(indexPath);\n if (!indexExists)\n return;\n await driver.ensureDir(indexPath);\n const filePath = await toIndexBucketFilePath(indexPath, rawKey);\n const bucketIndex = await readBucketIndex(filePath);\n const setForKey = bucketIndex.get(rawKey) ?? new Set();\n setForKey.add(identifier);\n bucketIndex.set(rawKey, setForKey);\n await writeBucketIndex(filePath, bucketIndex);\n };\n const updateIndexForReplace = async (oldItem, nextItem) => {\n await Promise.all(indicesToMaintain.map(async (fieldPath) => {\n await removeIdFromIndex(fieldPath, oldItem.id);\n const newValue = get(nextItem, fieldPath);\n await addIdToIndex(fieldPath, newValue, nextItem.id);\n }));\n };\n const upsertItems = async (items, mode) => {\n const deltas = new Map();\n await Promise.all(items.map(async (item) => {\n const filePath = await toItemsFilePath(item.id);\n const existingArray = await readItemsArrayOrEmpty(filePath);\n const indexOfItem = existingArray.findIndex(existing => existing.id === item.id);\n if (mode === 'insert') {\n if (indexOfItem !== -1)\n throw new Error(`Item with id \"${String(item.id)}\" already exists`);\n accumulateUpsertDelta(deltas, indicesToMaintain, undefined, item);\n await driver.writeObject(filePath, [...existingArray, item]);\n }\n else {\n if (indexOfItem === -1)\n throw new Error(`Item with id \"${String(item.id)}\" does not exist`);\n const updatedArray = [...existingArray];\n const oldItem = updatedArray[indexOfItem];\n updatedArray[indexOfItem] = item;\n await driver.writeObject(filePath, updatedArray);\n await updateIndexForReplace(oldItem, item);\n }\n }));\n // Only apply deltas for inserts (replace handled by direct purge+add)\n if (deltas.size > 0) {\n await applyIndexDeltas(deltas);\n }\n };\n return createStorageAdapter({\n setup: async () => {\n await driver.ensureDir(folderName);\n },\n teardown: async () => {\n // no-op\n },\n readAll,\n readIds: async (identifiers) => {\n const results = await Promise.all(identifiers.map(async (identifier) => {\n const filePath = await toItemsFilePath(identifier);\n const itemsInFile = await driver.readObject(filePath).catch(() => []) ?? [];\n if (!Array.isArray(itemsInFile))\n return null;\n return itemsInFile.find(item => item.id === identifier) ?? null;\n }));\n return results.filter((value) => value != null);\n },\n createIndex: async (fieldPath) => {\n if (fieldPath === 'id')\n throw new Error('Cannot create index on id field');\n indicesToMaintain.push(fieldPath);\n await ensureIndex(fieldPath);\n },\n dropIndex: async (fieldPath) => {\n const pathToDrop = await toIndexPathForField(fieldPath);\n const exists = await safeFileExists(pathToDrop);\n if (!exists)\n throw new Error(`Index on field \"${fieldPath}\" does not exist`);\n await driver.removeEntry(pathToDrop, { recursive: true });\n },\n readIndex,\n insert: async (itemsToInsert) => {\n await upsertItems(itemsToInsert, 'insert');\n },\n replace: async (itemsToReplace) => {\n await upsertItems(itemsToReplace, 'replace');\n },\n remove: async (itemsToRemove) => {\n const deltas = new Map();\n await Promise.all(itemsToRemove.map(async (item) => {\n const filePath = await toItemsFilePath(item.id);\n const existingArray = await readItemsArrayOrEmpty(filePath);\n const indexOfItem = existingArray.findIndex(existing => existing.id === item.id);\n if (indexOfItem === -1)\n throw new Error(`Item with id \"${String(item.id)}\" does not exist`);\n accumulateRemoveDelta(deltas, indicesToMaintain, existingArray[indexOfItem]);\n const updatedArray = [...existingArray];\n updatedArray.splice(indexOfItem, 1);\n await (updatedArray.length === 0\n ? driver.removeEntry(filePath).catch(() => { })\n : driver.writeObject(filePath, updatedArray));\n }));\n await applyIndexDeltas(deltas);\n },\n removeAll: async () => {\n const exists = await safeFileExists(folderName);\n if (!exists)\n return;\n await driver.removeEntry(folderName, { recursive: true });\n },\n });\n}\n"],"names":["addToDelta","deltas","fieldPath","changeKind","rawKey","identifier","delta","target","accumulateUpsertDelta","indicesToMaintain","existingItem","nextItem","value","get","accumulateRemoveDelta","createGenericFSAdapter","driver","folderName","itemsDirectoryPathPromise","indexRootPathPromise","safeFileExists","path","safeRemoveEntry","options","toItemsFilePath","toIndexPathForField","toIndexBucketFilePath","indexPath","bucketFileName","readItemsArrayOrEmpty","filePath","data","loadBucketIndexFromData","bucketIndex","entry","identifierList","writeBucketIndex","output","identifierSet","readBucketIndex","readAll","itemsDirectoryPath","relativeFiles","aggregatedItems","relativePath","fullPath","itemsInFile","ensureIndex","itemsPromise","allItems","indexMap","item","fieldValue","keyString","buckets","rawKeyString","records","readIndex","resultIndex","maps","applyIndexDeltas","touchedRawKeys","rawKeyToBucketFileName","touchedBucketFileNames","setForKey","removeIdFromIndex","changed","set","before","addIdToIndex","updateIndexForReplace","oldItem","newValue","upsertItems","items","mode","existingArray","indexOfItem","existing","updatedArray","createStorageAdapter","identifiers","pathToDrop","itemsToInsert","itemsToReplace","itemsToRemove"],"mappings":"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"}
1
+ {"version":3,"file":"index.umd.js","names":[],"sources":["../src/deltaHelpers.ts","../src/index.ts"],"sourcesContent":["import { get } from '@signaldb/core'\n\nexport type IndexDelta<I> = {\n adds: Map<string, Set<I>>,\n removes: Map<string, Set<I>>,\n}\n\n/**\n * Records a single index mutation into the delta map for a given indexed field.\n *\n * The delta map is grouped by `fieldPath`, and then by stringified key (`rawKey`).\n * Each key maps to a set of identifiers to add/remove for that key.\n * @param deltas - Accumulator of per-field index deltas.\n * @param fieldPath - Dot-path of the indexed field (used as the delta bucket key).\n * @param changeKind - Whether this identifier should be added to or removed from the index key.\n * @param rawKey - The stringified index key value.\n * @param identifier - The item identifier to add/remove for `rawKey`.\n */\nexport function addToDelta<I>(\n deltas: Map<string, IndexDelta<I>>,\n fieldPath: string,\n changeKind: 'add' | 'remove',\n rawKey: string,\n identifier: I,\n) {\n if (!deltas.has(fieldPath)) deltas.set(fieldPath, { adds: new Map(), removes: new Map() })\n const delta = deltas.get(fieldPath)\n if (!delta) return\n const target = changeKind === 'add' ? delta.adds : delta.removes\n if (!target.has(rawKey)) target.set(rawKey, new Set<I>())\n target.get(rawKey)?.add(identifier)\n}\n\n/**\n * Computes the delta for a change in a single indexed field.\n *\n * Values are coerced to string keys (with `null`/`undefined` treated as \"no key\").\n * If the derived keys are equal, no delta is recorded.\n * @param deltas - Accumulator of per-field index deltas.\n * @param fieldPath - Dot-path of the indexed field being tracked.\n * @param oldValue - Previous value of the field.\n * @param newValue - Next value of the field.\n * @param identifier - The item identifier affected by the change.\n */\nexport function addDeltaForChange<I>(\n deltas: Map<string, IndexDelta<I>>,\n fieldPath: string,\n oldValue: any,\n newValue: any,\n identifier: I,\n) {\n const oldKey = oldValue == null ? undefined : String(oldValue)\n const newKey = newValue == null ? undefined : String(newValue)\n if (oldKey === newKey) return\n if (oldKey != null) addToDelta(deltas, fieldPath, 'remove', oldKey, identifier)\n if (newKey != null) addToDelta(deltas, fieldPath, 'add', newKey, identifier)\n}\n\n/**\n * Accumulates index deltas for an upsert operation.\n *\n * - If `existingItem` is present, compares each maintained index field between the old and new item,\n * recording removes/adds for key changes.\n * - If `existingItem` is absent, treats the operation as an insert and records adds for each\n * maintained index field that has a non-null value.\n * @param deltas - Accumulator of per-field index deltas.\n * @param indicesToMaintain - List of dot-paths for fields that are indexed.\n * @param existingItem - Previous stored item (if any).\n * @param nextItem - Incoming item to upsert.\n */\nexport const accumulateUpsertDelta = <T extends { id: I }, I>(\n deltas: Map<string, IndexDelta<I>>,\n indicesToMaintain: string[],\n existingItem: T | undefined,\n nextItem: T,\n) => {\n if (existingItem) {\n for (const fieldPath of indicesToMaintain) {\n addDeltaForChange(\n deltas,\n fieldPath,\n get(existingItem, fieldPath),\n get(nextItem, fieldPath),\n nextItem.id,\n )\n }\n } else {\n for (const fieldPath of indicesToMaintain) {\n const value = get(nextItem, fieldPath)\n if (value == null) continue\n addToDelta(deltas, fieldPath, 'add', String(value), nextItem.id)\n }\n }\n}\n\n/**\n * Accumulates index deltas for a remove/delete operation.\n *\n * For each maintained index field, records a removal of the item's identifier from the\n * corresponding stringified key (skipping `null`/`undefined` values).\n * @param deltas - Accumulator of per-field index deltas.\n * @param indicesToMaintain - List of dot-paths for fields that are indexed.\n * @param existingItem - The item being removed.\n */\nexport function accumulateRemoveDelta<T extends { id: I }, I>(\n deltas: Map<string, IndexDelta<I>>,\n indicesToMaintain: string[],\n existingItem: T,\n) {\n for (const fieldPath of indicesToMaintain) {\n const value = get(existingItem, fieldPath)\n if (value == null) continue\n addToDelta(deltas, fieldPath, 'remove', String(value), existingItem.id)\n }\n}\n","import { createStorageAdapter, get } from '@signaldb/core'\nimport {\n accumulateUpsertDelta,\n accumulateRemoveDelta,\n type IndexDelta,\n} from './deltaHelpers'\n\n/**\n * A driver interface that abstracts low-level filesystem operations.\n * Implementations can back this with Node.js fs/promises, browser FS APIs, or other storage mechanisms.\n */\nexport interface Driver<\n T extends { id: I } & Record<string, unknown>,\n I,\n> {\n fileNameForId(id: I): Promise<string>,\n fileNameForIndexKey(key: string): Promise<string>,\n joinPath(...parts: string[]): Promise<string>,\n ensureDir(path: string): Promise<void>,\n fileExists(path: string): Promise<boolean>,\n readObject(path: string): Promise<T[] | null>,\n writeObject(path: string, value: T[]): Promise<void>,\n readIndexObject(path: string): Promise<Record<string, I[]>[] | null>,\n writeIndexObject(path: string, value: Record<string, I[]>[]): Promise<void>,\n listFilesRecursive(directoryPath: string): Promise<string[]>,\n removeEntry(path: string, options?: { recursive?: boolean }): Promise<void>,\n}\n\n/**\n * Creates a storage adapter for managing a SignalDB collection using a generic filesystem-like driver.\n * Data is sharded into subdirectories based on item identifiers, and indices are maintained as files.\n * @param driver - The driver that handles low-level file operations.\n * @param folderName - The root folder path for storing the collection data.\n * @returns A SignalDB storage adapter for managing data in a filesystem-like storage.\n */\nexport default function createGenericFSAdapter<\n T extends { id: I } & Record<string, unknown>,\n I,\n>(\n driver: Driver<T, I>,\n folderName: string,\n) {\n const itemsDirectoryPathPromise = driver.joinPath(folderName, 'items')\n const indexRootPathPromise = driver.joinPath(folderName, 'index')\n\n const safeFileExists = async (path: string): Promise<boolean> =>\n driver.fileExists(path).catch(() => false)\n\n const safeRemoveEntry = async (path: string, options?: { recursive?: boolean }) =>\n driver.removeEntry(path, options).catch(() => { /* ignore */ })\n\n const toItemsFilePath = async (identifier: I): Promise<string> =>\n driver.joinPath(await itemsDirectoryPathPromise, await driver.fileNameForId(identifier))\n\n const toIndexPathForField = async (fieldPath: string): Promise<string> =>\n driver.joinPath(await indexRootPathPromise, await driver.fileNameForIndexKey(fieldPath))\n\n const toIndexBucketFilePath = async (indexPath: string, rawKey: string): Promise<string> => {\n const bucketFileName = await driver.fileNameForIndexKey(rawKey)\n return driver.joinPath(indexPath, bucketFileName)\n }\n\n const readItemsArrayOrEmpty = async (filePath: string): Promise<T[]> => {\n const exists = await safeFileExists(filePath)\n if (!exists) return []\n const data = await driver.readObject(filePath).catch(() => [])\n return Array.isArray(data) ? data : []\n }\n\n const loadBucketIndexFromData = <K extends string>(\n data: Record<K, I[]>[] | null,\n ): Map<string, Set<I>> => {\n const bucketIndex = new Map<string, Set<I>>()\n if (!Array.isArray(data)) return bucketIndex\n for (const entry of data) {\n for (const [rawKey, identifierList] of Object.entries(entry)) {\n bucketIndex.set(rawKey, new Set(identifierList as I[]))\n }\n }\n return bucketIndex\n }\n\n const writeBucketIndex = async (\n filePath: string,\n bucketIndex: Map<string, Set<I>>,\n ) => {\n if (bucketIndex.size === 0) {\n const exists = await safeFileExists(filePath)\n if (exists) await safeRemoveEntry(filePath)\n return\n }\n const output: Record<string, I[]>[] = []\n bucketIndex.forEach((identifierSet, rawKey) => {\n output.push({ [rawKey]: [...identifierSet] as I[] })\n })\n await driver.writeIndexObject(filePath, output)\n }\n\n const readBucketIndex = async (filePath: string): Promise<Map<string, Set<I>>> => {\n const data = await driver.readIndexObject(filePath).catch(() => null)\n return loadBucketIndexFromData(data)\n }\n\n const readAll = async (): Promise<T[]> => {\n const itemsDirectoryPath = await itemsDirectoryPathPromise\n const directoryExists = await safeFileExists(itemsDirectoryPath)\n if (!directoryExists) return []\n\n const relativeFiles = await driver.listFilesRecursive(itemsDirectoryPath)\n const aggregatedItems: T[] = []\n\n await Promise.all(\n relativeFiles.map(async (relativePath) => {\n const fullPath = await driver.joinPath(itemsDirectoryPath, relativePath)\n const itemsInFile = await driver.readObject(fullPath).catch(() => null)\n if (Array.isArray(itemsInFile)) aggregatedItems.push(...itemsInFile)\n }),\n )\n\n return aggregatedItems\n }\n\n const ensureIndex = async (\n fieldPath: string,\n itemsPromise: Promise<T[]> = readAll(),\n ): Promise<void> => {\n const allItems = await itemsPromise\n const indexPath = await toIndexPathForField(fieldPath)\n\n await safeRemoveEntry(indexPath, { recursive: true })\n await driver.ensureDir(indexPath)\n\n // Build value -> Set<identifier>\n const indexMap = new Map<string, Set<I>>()\n for (const item of allItems) {\n const fieldValue = get(item, fieldPath)\n if (fieldValue == null) continue\n const keyString = String(fieldValue)\n if (!indexMap.has(keyString)) indexMap.set(keyString, new Set<I>())\n indexMap.get(keyString)?.add(item.id)\n }\n\n // Group entries by bucket file name, then persist each bucket\n const buckets: Record<string, Record<string, I[]>[]> = {}\n for (const [rawKeyString, identifierSet] of indexMap) {\n const bucketFileName = await driver.fileNameForIndexKey(rawKeyString)\n if (!buckets[bucketFileName]) buckets[bucketFileName] = []\n buckets[bucketFileName].push({ [rawKeyString]: [...identifierSet] })\n }\n\n await Promise.all(\n Object.entries(buckets).map(async ([bucketFileName, records]) => {\n const filePath = await driver.joinPath(indexPath, bucketFileName)\n await driver.writeIndexObject(filePath, records)\n }),\n )\n }\n\n const readIndex = async (fieldPath: string) => {\n const indexPath = await toIndexPathForField(fieldPath)\n const indexExists = await safeFileExists(indexPath)\n if (!indexExists) throw new Error(`Index on field \"${fieldPath}\" does not exist`)\n\n const relativeFiles = await driver.listFilesRecursive(indexPath)\n const resultIndex = new Map<string, Set<I>>()\n\n await Promise.all(\n relativeFiles.map(async (relativePath) => {\n const fullPath = await driver.joinPath(indexPath, relativePath)\n const maps = await driver.readIndexObject(fullPath).catch(() => null)\n if (!Array.isArray(maps)) return\n for (const entry of maps) {\n for (const [rawKey, identifierList] of Object.entries(entry)) {\n if (!resultIndex.has(rawKey)) resultIndex.set(rawKey, new Set<I>())\n const target = resultIndex.get(rawKey)\n for (const identifier of identifierList) target?.add(identifier)\n }\n }\n }),\n )\n\n return resultIndex\n }\n\n // Track which field paths should be kept up-to-date incrementally.\n const indicesToMaintain: string[] = []\n\n const applyIndexDeltas = async (deltas: Map<string, IndexDelta<I>>) => {\n // For each indexed field with changes, touch only the affected bucket files\n await Promise.all(\n [...deltas.entries()].map(async ([fieldPath, delta]) => {\n const indexPath = await toIndexPathForField(fieldPath)\n const indexExists = await safeFileExists(indexPath)\n if (!indexExists) return // Only update indices that exist\n await driver.ensureDir(indexPath)\n\n // Compute impacted bucket filenames\n const touchedRawKeys = new Set<string>([\n ...delta.adds.keys(),\n ...delta.removes.keys(),\n ])\n\n const rawKeyToBucketFileName = new Map<string, string>()\n await Promise.all(\n [...touchedRawKeys].map(async (rawKey) => {\n rawKeyToBucketFileName.set(rawKey, await driver.fileNameForIndexKey(rawKey))\n }),\n )\n\n const touchedBucketFileNames = new Set<string>(rawKeyToBucketFileName.values())\n\n await Promise.all(\n [...touchedBucketFileNames].map(async (bucketFileName) => {\n const filePath = await driver.joinPath(indexPath, bucketFileName)\n const bucketIndex = await readBucketIndex(filePath)\n\n // Apply removals for keys that map to this bucket\n delta.removes.forEach((identifierSet, rawKey) => {\n if (rawKeyToBucketFileName.get(rawKey) !== bucketFileName) return\n const setForKey = bucketIndex.get(rawKey)\n if (!setForKey) return\n identifierSet.forEach(identifier => setForKey.delete(identifier))\n if (setForKey.size === 0) bucketIndex.delete(rawKey)\n })\n\n // Apply additions\n delta.adds.forEach((identifierSet, rawKey) => {\n if (rawKeyToBucketFileName.get(rawKey) !== bucketFileName) return\n const setForKey = bucketIndex.get(rawKey) ?? new Set<I>()\n identifierSet.forEach(identifier => setForKey.add(identifier))\n bucketIndex.set(rawKey, setForKey)\n })\n\n await writeBucketIndex(filePath, bucketIndex)\n }),\n )\n }),\n )\n }\n\n const removeIdFromIndex = async (fieldPath: string, identifier: I) => {\n const indexPath = await toIndexPathForField(fieldPath)\n const indexExists = await safeFileExists(indexPath)\n if (!indexExists) return\n\n const relativeFiles = await driver.listFilesRecursive(indexPath)\n await Promise.all(\n relativeFiles.map(async (relativePath) => {\n const filePath = await driver.joinPath(indexPath, relativePath)\n const data = await driver.readIndexObject(filePath).catch(() => null)\n if (!Array.isArray(data)) return\n\n let changed = false\n const bucketIndex = new Map<string, Set<I>>()\n for (const entry of data) {\n for (const [rawKey, identifierList] of Object.entries(entry)) {\n const set = new Set<I>(identifierList)\n const before = set.size\n set.delete(identifier)\n if (set.size !== before) changed = true\n if (set.size > 0) bucketIndex.set(rawKey, set)\n }\n }\n\n if (!changed) return\n await writeBucketIndex(filePath, bucketIndex)\n }),\n )\n }\n\n const addIdToIndex = async (fieldPath: string, value: any, identifier: I) => {\n if (value == null) return\n const rawKey = String(value)\n\n const indexPath = await toIndexPathForField(fieldPath)\n const indexExists = await safeFileExists(indexPath)\n if (!indexExists) return\n await driver.ensureDir(indexPath)\n\n const filePath = await toIndexBucketFilePath(indexPath, rawKey)\n const bucketIndex = await readBucketIndex(filePath)\n\n const setForKey = bucketIndex.get(rawKey) ?? new Set<I>()\n setForKey.add(identifier)\n bucketIndex.set(rawKey, setForKey)\n\n await writeBucketIndex(filePath, bucketIndex)\n }\n\n const updateIndexForReplace = async (oldItem: T, nextItem: T) => {\n await Promise.all(\n indicesToMaintain.map(async (fieldPath) => {\n await removeIdFromIndex(fieldPath, oldItem.id)\n const newValue = get(nextItem, fieldPath)\n await addIdToIndex(fieldPath, newValue, nextItem.id)\n }),\n )\n }\n\n const upsertItems = async (\n items: T[],\n mode: 'insert' | 'replace',\n ) => {\n const deltas = new Map<string, IndexDelta<I>>()\n\n await Promise.all(\n items.map(async (item) => {\n const filePath = await toItemsFilePath(item.id)\n const existingArray = await readItemsArrayOrEmpty(filePath)\n const indexOfItem = existingArray.findIndex(existing => existing.id === item.id)\n\n if (mode === 'insert') {\n if (indexOfItem !== -1) throw new Error(`Item with id \"${String(item.id)}\" already exists`)\n accumulateUpsertDelta(deltas, indicesToMaintain, undefined, item)\n await driver.writeObject(filePath, [...existingArray, item])\n } else {\n if (indexOfItem === -1) throw new Error(`Item with id \"${String(item.id)}\" does not exist`)\n const updatedArray = [...existingArray]\n const oldItem = updatedArray[indexOfItem]\n updatedArray[indexOfItem] = item\n await driver.writeObject(filePath, updatedArray)\n await updateIndexForReplace(oldItem, item)\n }\n }),\n )\n\n // Only apply deltas for inserts (replace handled by direct purge+add)\n if (deltas.size > 0) {\n await applyIndexDeltas(deltas)\n }\n }\n\n return createStorageAdapter<T, I>({\n setup: async () => {\n await driver.ensureDir(folderName)\n },\n\n teardown: async () => {\n // no-op\n },\n\n readAll,\n\n readIds: async (identifiers) => {\n const results: (T | null)[] = await Promise.all(\n identifiers.map(async (identifier) => {\n const filePath = await toItemsFilePath(identifier)\n const itemsInFile = await driver.readObject(filePath).catch(() => []) ?? []\n if (!Array.isArray(itemsInFile)) return null\n return itemsInFile.find(item => item.id === identifier) ?? null\n }),\n )\n return results.filter((value): value is T => value != null)\n },\n\n createIndex: async (fieldPath) => {\n if (fieldPath === 'id') throw new Error('Cannot create index on id field')\n indicesToMaintain.push(fieldPath)\n await ensureIndex(fieldPath)\n },\n\n dropIndex: async (fieldPath) => {\n const pathToDrop = await toIndexPathForField(fieldPath)\n const exists = await safeFileExists(pathToDrop)\n if (!exists) throw new Error(`Index on field \"${fieldPath}\" does not exist`)\n await driver.removeEntry(pathToDrop, { recursive: true })\n },\n\n readIndex,\n\n insert: async (itemsToInsert) => {\n await upsertItems(itemsToInsert, 'insert')\n },\n\n replace: async (itemsToReplace) => {\n await upsertItems(itemsToReplace, 'replace')\n },\n\n remove: async (itemsToRemove) => {\n const deltas = new Map<string, IndexDelta<I>>()\n\n await Promise.all(\n itemsToRemove.map(async (item) => {\n const filePath = await toItemsFilePath(item.id)\n const existingArray = await readItemsArrayOrEmpty(filePath)\n const indexOfItem = existingArray.findIndex(existing => existing.id === item.id)\n if (indexOfItem === -1) throw new Error(`Item with id \"${String(item.id)}\" does not exist`)\n\n accumulateRemoveDelta(deltas, indicesToMaintain, existingArray[indexOfItem])\n\n const updatedArray = [...existingArray]\n updatedArray.splice(indexOfItem, 1)\n await (updatedArray.length === 0\n ? driver.removeEntry(filePath).catch(() => { /* ignore */ })\n : driver.writeObject(filePath, updatedArray))\n }),\n )\n\n await applyIndexDeltas(deltas)\n },\n\n removeAll: async () => {\n const exists = await safeFileExists(folderName)\n if (!exists) return\n await driver.removeEntry(folderName, { recursive: true })\n },\n })\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signaldb/generic-fs",
3
- "version": "2.0.0-beta.2",
3
+ "version": "2.0.0-beta.20",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "build": "rimraf dist && vite build",
@@ -54,6 +54,6 @@
54
54
  "dist"
55
55
  ],
56
56
  "peerDependencies": {
57
- "@signaldb/core": "2.0.0-beta.2"
57
+ "@signaldb/core": "2.0.0-beta.20"
58
58
  }
59
59
  }