@ebbjs/storage 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,335 @@
1
+ import { unwrap as _, openDB as b } from "idb";
2
+ import { m as k, a as O, i as T, c as v } from "../cursor-record-D39emd6R.js";
3
+ import { c as N, l as P, f as R, a as C, b as B, j as M, k as H, n as F, q as G, s as L, M as j, m as K, p as I, r as U, i as Y } from "../replica-record-D3lkFACh.js";
4
+ import { compare as V } from "@ebbjs/core";
5
+ const z = 8, m = "actionPosition", A = "replica", Q = (t, e, a, n) => {
6
+ if (t.objectStoreNames.contains("actions"))
7
+ n.objectStore("actions").indexNames.contains("position") || n.objectStore("actions").createIndex("position", "position");
8
+ else {
9
+ const s = t.createObjectStore("actions", { keyPath: "id" });
10
+ s.createIndex("subject_id", "subject_ids", { multiEntry: !0 }), s.createIndex("position", "position");
11
+ }
12
+ if (!t.objectStoreNames.contains("entities")) {
13
+ const s = t.createObjectStore("entities", { keyPath: "id" });
14
+ s.indexNames.contains("type") || s.createIndex("type", "type");
15
+ }
16
+ if (t.objectStoreNames.contains("relationships") || t.createObjectStore("relationships", { keyPath: "key" }), !t.objectStoreNames.contains("dirty")) {
17
+ const s = t.createObjectStore("dirty", { keyPath: "entityId" });
18
+ s.indexNames.contains("entityType") || s.createIndex("entityType", "entityType");
19
+ }
20
+ t.objectStoreNames.contains("cursors") || t.createObjectStore("cursors", { keyPath: "groupId" }), t.objectStoreNames.contains("outbox") || t.createObjectStore("outbox", { keyPath: "action.id" }), t.objectStoreNames.contains("sequence") || t.createObjectStore("sequence", { keyPath: "id" }), t.objectStoreNames.contains("replica") || t.createObjectStore("replica", { keyPath: ["type", "id"] }), t.objectStoreNames.contains("replicaCursor") || t.createObjectStore("replicaCursor", { keyPath: "id" }), e < 8 && J(n);
21
+ }, J = (t) => {
22
+ const e = _(t.objectStore("actions")), a = t.objectStore("sequence");
23
+ let n = 0;
24
+ const s = e.openCursor();
25
+ s.onsuccess = () => {
26
+ const c = s.result;
27
+ if (c === null) {
28
+ a.put({ id: m, value: n });
29
+ return;
30
+ }
31
+ n += 1, c.update({ ...c.value, position: n }), c.continue();
32
+ };
33
+ }, W = (t) => {
34
+ const e = /* @__PURE__ */ new Set();
35
+ for (const a of t.updates)
36
+ e.add(a.subject_id);
37
+ return Array.from(e);
38
+ }, x = (t) => {
39
+ const { subject_ids: e, position: a, ...n } = t;
40
+ return n;
41
+ }, h = async (t, e) => {
42
+ const a = t.objectStore("actions"), n = await a.get(e.id), s = await t.objectStore("sequence").get(m), c = n === void 0, l = c ? (s?.value ?? 0) + 1 : n.position, p = n === void 0 ? e : { ...e, updates: k(n.updates, e.updates) }, y = O(n?.updates ?? [], e.updates);
43
+ return await a.put({ ...p, position: l, subject_ids: W(p) }), c && await t.objectStore("sequence").put({ id: m, value: l }), { action: p, position: l, added: y };
44
+ }, X = (t) => ({
45
+ async append(e) {
46
+ const a = t.transaction(["actions", "sequence"], "readwrite"), n = await h(a, e);
47
+ return await a.done, n;
48
+ },
49
+ async appendMany(e) {
50
+ const a = t.transaction(["actions", "sequence"], "readwrite"), n = [];
51
+ for (const s of e)
52
+ n.push(await h(a, s));
53
+ return await a.done, n;
54
+ },
55
+ async readTail(e) {
56
+ const a = t.transaction("actions", "readonly"), n = await a.store.index("position").getAll(IDBKeyRange.lowerBound(e, !0));
57
+ return await a.done, n.map((s) => ({
58
+ action: x(s),
59
+ position: s.position,
60
+ added: s.updates
61
+ }));
62
+ },
63
+ async lastPosition() {
64
+ return (await t.get("sequence", m))?.value ?? 0;
65
+ },
66
+ async getAll() {
67
+ return (await t.getAll("actions")).map(x);
68
+ },
69
+ async getForEntity(e) {
70
+ const a = t.transaction("actions", "readonly"), n = await a.store.index("subject_id").getAll(e);
71
+ return await a.done, n.map(x).sort((c, l) => c.gsn - l.gsn);
72
+ },
73
+ async clear() {
74
+ const e = t.transaction(["actions", "sequence"], "readwrite");
75
+ await e.objectStore("actions").clear(), await e.objectStore("sequence").put({ id: m, value: 0 }), await e.done;
76
+ }
77
+ }), q = (t) => t === void 0 ? null : v(t), Z = (t) => {
78
+ const e = async (a) => q(await t.get("cursors", a));
79
+ return {
80
+ async get(a) {
81
+ return (await t.get("cursors", a))?.cursor ?? null;
82
+ },
83
+ async set(a, n) {
84
+ const s = await e(a);
85
+ await t.put("cursors", { groupId: a, ...s, cursor: n });
86
+ },
87
+ async getRecord(a) {
88
+ return e(a);
89
+ },
90
+ async setRecord(a, n) {
91
+ if (T(n)) {
92
+ await t.delete("cursors", a);
93
+ return;
94
+ }
95
+ await t.put("cursors", {
96
+ groupId: a,
97
+ ...v(n)
98
+ });
99
+ },
100
+ async records() {
101
+ const a = await t.getAll("cursors"), n = /* @__PURE__ */ new Map();
102
+ for (const s of a)
103
+ n.set(s.groupId, q(s) ?? {});
104
+ return n;
105
+ },
106
+ async clear() {
107
+ await t.clear("cursors");
108
+ }
109
+ };
110
+ }, $ = (t) => ({
111
+ async mark(e, a) {
112
+ await t.get("dirty", e) || await t.put("dirty", { entityId: e, entityType: a });
113
+ },
114
+ async isDirty(e) {
115
+ return await t.get("dirty", e) !== void 0;
116
+ },
117
+ async getDirtyForType(e) {
118
+ return (await t.getAllFromIndex("dirty", "entityType", e)).map((n) => n.entityId);
119
+ },
120
+ async clear(e) {
121
+ await t.delete("dirty", e);
122
+ },
123
+ async clearAll() {
124
+ await t.clear("dirty");
125
+ }
126
+ }), tt = (t, e, a) => {
127
+ const n = (o) => structuredClone(o), s = async (o, r) => {
128
+ r === null ? await t.delete("relationships", o) : await t.put("relationships", { key: o, rows: r });
129
+ }, c = async (o) => {
130
+ const r = await t.get("relationships", o.key);
131
+ await s(o.key, L(r?.rows, o));
132
+ }, l = async (o) => {
133
+ const r = await t.get("relationships", o.key);
134
+ await s(o.key, G(r?.rows, o));
135
+ }, p = async (o, r) => {
136
+ for (const u of [M(o, r), H(o, r)])
137
+ u.remove !== null && await l(u.remove), u.add !== null && await c(u.add);
138
+ }, y = async (o) => {
139
+ if (!await a.isDirty(o)) return;
140
+ const u = await e.getForEntity(o);
141
+ if (u.length === 0) return;
142
+ let w = null;
143
+ for (const g of u)
144
+ for (const S of g.updates)
145
+ S.subject_id === o && (w = F(w, S, g.gsn, g.hlc));
146
+ if (w === null) return;
147
+ const D = await t.get("entities", o);
148
+ await t.put("entities", n(w)), await p(D, w), await a.clear(o);
149
+ }, i = async (o) => {
150
+ for (const r of await a.getDirtyForType(o))
151
+ await y(r);
152
+ }, d = async (o) => {
153
+ const r = await t.get("relationships", o);
154
+ return B(r?.rows);
155
+ };
156
+ return {
157
+ async get(o) {
158
+ await y(o);
159
+ const r = await t.get("entities", o);
160
+ return r ? n(r) : null;
161
+ },
162
+ async set(o) {
163
+ const r = await t.get("entities", o.id);
164
+ await t.put("entities", n(o)), await p(r, o);
165
+ },
166
+ async query(o) {
167
+ return await i(o), (await t.getAllFromIndex("entities", "type", o)).map(n);
168
+ },
169
+ async queryByRelationship({
170
+ as: o,
171
+ type: r,
172
+ targetId: u
173
+ }) {
174
+ return await i(I), d(U(o, r, u));
175
+ },
176
+ async queryByRelationshipSource({
177
+ as: o,
178
+ type: r,
179
+ sourceId: u
180
+ }) {
181
+ await i(I);
182
+ const w = await t.get("relationships", R(o, r, u));
183
+ return C(w?.rows);
184
+ },
185
+ async queryByMembership(o) {
186
+ return await i(j), d(K(o));
187
+ },
188
+ async queryByMembershipEntity(o) {
189
+ await i(j);
190
+ const r = await t.get("relationships", N(o));
191
+ return P(r?.rows);
192
+ },
193
+ async reset() {
194
+ await t.clear("relationships"), await t.clear("entities");
195
+ }
196
+ };
197
+ }, E = (t) => ({
198
+ action: t.action,
199
+ status: t.status,
200
+ enqueuedAtHlc: t.enqueuedAtHlc,
201
+ // A row predating the field reads as "always concurrent", never
202
+ // silently dropped.
203
+ basedOnGsn: t.basedOnGsn ?? 0,
204
+ conflict: t.conflict
205
+ }), et = (t) => ({
206
+ async put(e) {
207
+ await t.put("outbox", {
208
+ action: e.action,
209
+ status: e.status,
210
+ enqueuedAtHlc: e.enqueuedAtHlc,
211
+ basedOnGsn: e.basedOnGsn,
212
+ conflict: e.conflict
213
+ });
214
+ },
215
+ async putAndDelete(e, a) {
216
+ const n = t.transaction("outbox", "readwrite");
217
+ n.store.put({
218
+ action: e.action,
219
+ status: e.status,
220
+ enqueuedAtHlc: e.enqueuedAtHlc,
221
+ basedOnGsn: e.basedOnGsn,
222
+ conflict: e.conflict
223
+ }), n.store.delete(a), await n.done;
224
+ },
225
+ async list() {
226
+ return (await t.getAll("outbox")).map(E).sort((a, n) => V(a.enqueuedAtHlc, n.enqueuedAtHlc));
227
+ },
228
+ async get(e) {
229
+ const a = await t.get("outbox", e);
230
+ return a === void 0 ? null : E(a);
231
+ },
232
+ async delete(e) {
233
+ await t.delete("outbox", e);
234
+ },
235
+ async clear() {
236
+ await t.clear("outbox");
237
+ }
238
+ }), at = (t) => ({
239
+ async load() {
240
+ const e = t.transaction(["replica", "replicaCursor"], "readonly"), a = await e.objectStore("replicaCursor").get(A);
241
+ if (a === void 0)
242
+ return await e.done, null;
243
+ const n = await e.objectStore("replica").getAll();
244
+ await e.done;
245
+ const s = {
246
+ format: a.format,
247
+ position: a.position,
248
+ revision: a.revision,
249
+ entities: n
250
+ };
251
+ return Y(s) ? s : null;
252
+ },
253
+ async save(e) {
254
+ const a = t.transaction(["replica", "replicaCursor"], "readwrite"), n = a.objectStore("replica");
255
+ await n.clear();
256
+ for (const s of e.entities)
257
+ await n.put(s);
258
+ await a.objectStore("replicaCursor").put({
259
+ id: A,
260
+ format: e.format,
261
+ position: e.position,
262
+ revision: e.revision
263
+ }), await a.done;
264
+ },
265
+ async clear() {
266
+ const e = t.transaction(["replica", "replicaCursor"], "readwrite");
267
+ await e.objectStore("replica").clear(), await e.objectStore("replicaCursor").clear(), await e.done;
268
+ }
269
+ }), it = async (t = {}) => {
270
+ const e = t.dbName ?? "ebb-storage", a = await b(e, z, {
271
+ upgrade: Q
272
+ }), n = X(a), s = $(a), c = tt(a, n, s), l = Z(a), p = et(a), y = at(a);
273
+ return {
274
+ actions: {
275
+ async append(i) {
276
+ const d = await n.append(i);
277
+ for (const f of i.updates)
278
+ await s.mark(f.subject_id, f.subject_type);
279
+ return d;
280
+ },
281
+ async appendMany(i) {
282
+ const d = await n.appendMany(i);
283
+ for (const f of i)
284
+ for (const o of f.updates)
285
+ await s.mark(o.subject_id, o.subject_type);
286
+ return d;
287
+ },
288
+ async readTail(i) {
289
+ return n.readTail(i);
290
+ },
291
+ async lastPosition() {
292
+ return n.lastPosition();
293
+ },
294
+ async getAll() {
295
+ return n.getAll();
296
+ },
297
+ async getForEntity(i) {
298
+ return n.getForEntity(i);
299
+ },
300
+ async clear() {
301
+ await n.clear(), await s.clearAll(), await c.reset(), await y.clear();
302
+ }
303
+ },
304
+ entities: c,
305
+ dirtyTracker: {
306
+ async mark(i, d) {
307
+ await s.mark(i, d);
308
+ },
309
+ async isDirty(i) {
310
+ return s.isDirty(i);
311
+ },
312
+ async getDirtyForType(i) {
313
+ return s.getDirtyForType(i);
314
+ },
315
+ async clear(i) {
316
+ await s.clear(i);
317
+ },
318
+ async clearAll() {
319
+ await s.clearAll();
320
+ }
321
+ },
322
+ cursors: l,
323
+ outbox: p,
324
+ replica: y,
325
+ async isDirty(i) {
326
+ return s.isDirty(i);
327
+ },
328
+ async reset() {
329
+ await n.clear(), await s.clearAll(), await c.reset(), await y.clear(), await l.clear();
330
+ }
331
+ };
332
+ };
333
+ export {
334
+ it as createIndexedDBAdapter
335
+ };