@ebbjs/storage 1.0.0 → 1.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.
- package/dist/indexeddb/index.d.ts +32 -15
- package/dist/indexeddb/index.js +180 -162
- package/dist/memory/index.d.ts +33 -16
- package/dist/memory/index.js +104 -83
- package/dist/replica/index.d.ts +39 -10
- package/dist/replica/index.js +162 -155
- package/dist/replica-record-BaptWabD.js +243 -0
- package/dist/types/index.d.ts +51 -17
- package/package.json +2 -2
- package/dist/replica-record-D5gGEoVQ.js +0 -179
|
@@ -122,9 +122,10 @@ interface MembershipLink {
|
|
|
122
122
|
* handled by the DirtyTracker.
|
|
123
123
|
*
|
|
124
124
|
* ## Merge Semantics
|
|
125
|
-
* - **
|
|
126
|
-
* - **
|
|
127
|
-
* - **
|
|
125
|
+
* - **merge** — Last-Writer-Wins (LWW) at the component's field: higher HLC wins; tiebreak by lexicographic `update_id`
|
|
126
|
+
* - **replace** — the component's field is set whole; the first write to an absent row creates it
|
|
127
|
+
* - **drop** — the component's field is removed; the row survives
|
|
128
|
+
* - **delete** — soft delete (sets `deleted_hlc`); the row keeps its type
|
|
128
129
|
*
|
|
129
130
|
* A field value is either a leaf merged by the LWW rule above, or a
|
|
130
131
|
* `{ map }` of nested field values merged key by key under the same
|
|
@@ -136,6 +137,9 @@ interface MembershipLink {
|
|
|
136
137
|
* - `get(id)` — returns entity by ID, materializes if dirty
|
|
137
138
|
* - `set(entity)` — directly sets an entity (bypasses materialization)
|
|
138
139
|
* - `query(type)` — returns all materialized entities of a type
|
|
140
|
+
* - `queryByComponent(component)` — returns the live ids carrying that
|
|
141
|
+
* `<model>/<field>` component in ascending order, materializing dirty rows
|
|
142
|
+
* of the component's model first
|
|
139
143
|
* - `queryByRelationship({ as, type, targetId })` — returns the distinct
|
|
140
144
|
* source ids indexed under that triple in ascending order,
|
|
141
145
|
* materializing dirty relationship rows first
|
|
@@ -154,6 +158,18 @@ interface EntityStore {
|
|
|
154
158
|
get(id: string): Promise<Entity | null>;
|
|
155
159
|
set(entity: Entity): Promise<void>;
|
|
156
160
|
query(type: string): Promise<readonly Entity[]>;
|
|
161
|
+
/**
|
|
162
|
+
* Live rows currently carrying `component` (`<model>/<field>`), ascending by
|
|
163
|
+
* id. Existence is the set of present fields on a row, so this is an index
|
|
164
|
+
* read rather than a row filter; a tombstoned row's components are not
|
|
165
|
+
* existence.
|
|
166
|
+
*
|
|
167
|
+
* The dirty rows materialized first are the component prefix's model. That is
|
|
168
|
+
* the current `<model>/<field>` addressing rule (#797); a component namespace
|
|
169
|
+
* that is not the row's model (#805's `ebb/*` components on ordinary rows)
|
|
170
|
+
* has to decode the model differently and revisit this step.
|
|
171
|
+
*/
|
|
172
|
+
queryByComponent(component: string): Promise<readonly string[]>;
|
|
157
173
|
queryByRelationship(query: RelationshipIndexQuery): Promise<readonly string[]>;
|
|
158
174
|
queryByRelationshipSource(query: RelationshipSourceQuery): Promise<readonly RelationshipLink[]>;
|
|
159
175
|
queryByMembership(groupId: string): Promise<readonly string[]>;
|
|
@@ -236,32 +252,32 @@ type OutboxStatus = "pending" | "acknowledged" | "error" | "conflicted";
|
|
|
236
252
|
/**
|
|
237
253
|
* One side of a contested slot: the buffered local write, or the value
|
|
238
254
|
* the server holds once the catch-up window is applied. A leaf carries
|
|
239
|
-
* its LWW triple; a whole-
|
|
255
|
+
* its LWW triple; a whole-component map replacement has no single leaf, so
|
|
240
256
|
* `update_id` / `hlc` are absent and `value` is the projected map. A
|
|
241
|
-
*
|
|
257
|
+
* component an inbound `merge` or `delete` reverted also has no triple, and
|
|
242
258
|
* `value` is `undefined` because the server holds no value.
|
|
243
259
|
*/
|
|
244
260
|
interface ConflictSide {
|
|
245
261
|
/** Projected leaf or map value. `undefined` when the server holds nothing. */
|
|
246
262
|
readonly value: unknown;
|
|
247
|
-
/** `update_id` of the FieldValue; absent for a map side or a reverted
|
|
263
|
+
/** `update_id` of the FieldValue; absent for a map side or a reverted component. */
|
|
248
264
|
readonly update_id?: string;
|
|
249
|
-
/** HLC carried by the FieldValue; absent for a map side or a reverted
|
|
265
|
+
/** HLC carried by the FieldValue; absent for a map side or a reverted component. */
|
|
250
266
|
readonly hlc?: string;
|
|
251
267
|
}
|
|
252
268
|
/**
|
|
253
|
-
* One contested position on a losing Action: a
|
|
254
|
-
* path from the
|
|
255
|
-
* leaf
|
|
256
|
-
*
|
|
269
|
+
* One contested position on a losing Action: a component plus the map-key
|
|
270
|
+
* path from the component's value root to the position. `path` is empty for a
|
|
271
|
+
* plain leaf component, an entity-level touch that overlaps no position, or a
|
|
272
|
+
* component an inbound `merge` / `delete` reverted. Concurrent writes to
|
|
257
273
|
* different keys are different slots and so are not conflicts.
|
|
258
274
|
*/
|
|
259
275
|
interface ConflictSlot {
|
|
260
276
|
/** The `subject_id` of the Update that carried the write. */
|
|
261
277
|
readonly subjectId: string;
|
|
262
|
-
/** The field name on that subject. */
|
|
263
|
-
readonly
|
|
264
|
-
/** Ordered map keys from the
|
|
278
|
+
/** The `<model>/<field>` component name on that subject. */
|
|
279
|
+
readonly component: string;
|
|
280
|
+
/** Ordered map keys from the component root to the position; empty at the root. */
|
|
265
281
|
readonly path: readonly string[];
|
|
266
282
|
/** The buffered local value at the position. */
|
|
267
283
|
readonly local: ConflictSide;
|
|
@@ -285,7 +301,8 @@ interface ConflictRemoteAction {
|
|
|
285
301
|
*/
|
|
286
302
|
interface ConflictSubjectState {
|
|
287
303
|
readonly subjectId: string;
|
|
288
|
-
|
|
304
|
+
/** The model the row is committed under. */
|
|
305
|
+
readonly model: string;
|
|
289
306
|
readonly before: Entity | null;
|
|
290
307
|
readonly after: Entity | null;
|
|
291
308
|
}
|
package/dist/indexeddb/index.js
CHANGED
|
@@ -1,125 +1,125 @@
|
|
|
1
|
-
import { unwrap as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { compare as
|
|
5
|
-
const
|
|
6
|
-
const s = e > 0 && e <
|
|
7
|
-
if (
|
|
8
|
-
for (const
|
|
9
|
-
t.deleteObjectStore(
|
|
1
|
+
import { unwrap as D, openDB as O } from "idb";
|
|
2
|
+
import { c as T, l as N, f as R, a as b, b as C, e as k, o as P, p as B, z as M, B as F, C as H, M as x, m as L, A as j, r as G, i as K, u as I } from "../replica-record-BaptWabD.js";
|
|
3
|
+
import { m as U, a as V, i as Y, c as h } from "../cursor-record-D39emd6R.js";
|
|
4
|
+
import { componentModel as z, compare as X } from "@ebbjs/core";
|
|
5
|
+
const Q = 11, J = 9, W = 11, f = "actionPosition", A = "replica", Z = (t, e, o, a) => {
|
|
6
|
+
const s = [J, W], u = e > 0 && s.some((i) => e < i);
|
|
7
|
+
if (u)
|
|
8
|
+
for (const i of Array.from(t.objectStoreNames))
|
|
9
|
+
t.deleteObjectStore(i);
|
|
10
10
|
if (t.objectStoreNames.contains("actions"))
|
|
11
|
-
|
|
11
|
+
a.objectStore("actions").indexNames.contains("position") || a.objectStore("actions").createIndex("position", "position");
|
|
12
12
|
else {
|
|
13
|
-
const
|
|
14
|
-
|
|
13
|
+
const i = t.createObjectStore("actions", { keyPath: "id" });
|
|
14
|
+
i.createIndex("subject_id", "subject_ids", { multiEntry: !0 }), i.createIndex("position", "position");
|
|
15
15
|
}
|
|
16
16
|
if (!t.objectStoreNames.contains("entities")) {
|
|
17
|
-
const
|
|
18
|
-
|
|
17
|
+
const i = t.createObjectStore("entities", { keyPath: "id" });
|
|
18
|
+
i.indexNames.contains("type") || i.createIndex("type", "type"), i.createIndex("components", "components", { multiEntry: !0 });
|
|
19
19
|
}
|
|
20
20
|
if (t.objectStoreNames.contains("relationships") || t.createObjectStore("relationships", { keyPath: "key" }), !t.objectStoreNames.contains("dirty")) {
|
|
21
|
-
const
|
|
22
|
-
|
|
21
|
+
const i = t.createObjectStore("dirty", { keyPath: "entityId" });
|
|
22
|
+
i.indexNames.contains("entityType") || i.createIndex("entityType", "entityType");
|
|
23
23
|
}
|
|
24
|
-
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" }),
|
|
25
|
-
},
|
|
26
|
-
const e =
|
|
27
|
-
let
|
|
24
|
+
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" }), u ? a.objectStore("sequence").put({ id: f, value: 0 }) : e < 8 && $(a);
|
|
25
|
+
}, $ = (t) => {
|
|
26
|
+
const e = D(t.objectStore("actions")), o = t.objectStore("sequence");
|
|
27
|
+
let a = 0;
|
|
28
28
|
const s = e.openCursor();
|
|
29
29
|
s.onsuccess = () => {
|
|
30
|
-
const
|
|
31
|
-
if (
|
|
32
|
-
|
|
30
|
+
const u = s.result;
|
|
31
|
+
if (u === null) {
|
|
32
|
+
o.put({ id: f, value: a });
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
a += 1, u.update({ ...u.value, position: a }), u.continue();
|
|
36
36
|
};
|
|
37
|
-
},
|
|
37
|
+
}, tt = (t) => {
|
|
38
38
|
const e = /* @__PURE__ */ new Set();
|
|
39
|
-
for (const
|
|
40
|
-
e.add(
|
|
39
|
+
for (const o of t.updates)
|
|
40
|
+
e.add(o.subject_id);
|
|
41
41
|
return Array.from(e);
|
|
42
|
-
},
|
|
43
|
-
const { subject_ids: e, position:
|
|
44
|
-
return
|
|
45
|
-
},
|
|
46
|
-
const
|
|
47
|
-
return await
|
|
48
|
-
},
|
|
42
|
+
}, g = (t) => {
|
|
43
|
+
const { subject_ids: e, position: o, ...a } = t;
|
|
44
|
+
return a;
|
|
45
|
+
}, E = async (t, e) => {
|
|
46
|
+
const o = t.objectStore("actions"), a = await o.get(e.id), s = await t.objectStore("sequence").get(f), u = a === void 0, i = u ? (s?.value ?? 0) + 1 : a.position, y = a === void 0 ? e : { ...e, updates: U(a.updates, e.updates) }, w = V(a?.updates ?? [], e.updates);
|
|
47
|
+
return await o.put({ ...y, position: i, subject_ids: tt(y) }), u && await t.objectStore("sequence").put({ id: f, value: i }), { action: y, position: i, added: w };
|
|
48
|
+
}, et = (t) => ({
|
|
49
49
|
async append(e) {
|
|
50
|
-
const
|
|
51
|
-
return await
|
|
50
|
+
const o = t.transaction(["actions", "sequence"], "readwrite"), a = await E(o, e);
|
|
51
|
+
return await o.done, a;
|
|
52
52
|
},
|
|
53
53
|
async appendMany(e) {
|
|
54
|
-
const
|
|
54
|
+
const o = t.transaction(["actions", "sequence"], "readwrite"), a = [];
|
|
55
55
|
for (const s of e)
|
|
56
|
-
|
|
57
|
-
return await
|
|
56
|
+
a.push(await E(o, s));
|
|
57
|
+
return await o.done, a;
|
|
58
58
|
},
|
|
59
59
|
async readTail(e) {
|
|
60
|
-
const
|
|
61
|
-
return await
|
|
62
|
-
action:
|
|
60
|
+
const o = t.transaction("actions", "readonly"), a = await o.store.index("position").getAll(IDBKeyRange.lowerBound(e, !0));
|
|
61
|
+
return await o.done, a.map((s) => ({
|
|
62
|
+
action: g(s),
|
|
63
63
|
position: s.position,
|
|
64
64
|
added: s.updates
|
|
65
65
|
}));
|
|
66
66
|
},
|
|
67
67
|
async lastPosition() {
|
|
68
|
-
return (await t.get("sequence",
|
|
68
|
+
return (await t.get("sequence", f))?.value ?? 0;
|
|
69
69
|
},
|
|
70
70
|
async getAll() {
|
|
71
|
-
return (await t.getAll("actions")).map(
|
|
71
|
+
return (await t.getAll("actions")).map(g);
|
|
72
72
|
},
|
|
73
73
|
async getForEntity(e) {
|
|
74
|
-
const
|
|
75
|
-
return await
|
|
74
|
+
const o = t.transaction("actions", "readonly"), a = await o.store.index("subject_id").getAll(e);
|
|
75
|
+
return await o.done, a.map(g).sort((u, i) => u.gsn - i.gsn);
|
|
76
76
|
},
|
|
77
77
|
async clear() {
|
|
78
78
|
const e = t.transaction(["actions", "sequence"], "readwrite");
|
|
79
|
-
await e.objectStore("actions").clear(), await e.objectStore("sequence").put({ id:
|
|
79
|
+
await e.objectStore("actions").clear(), await e.objectStore("sequence").put({ id: f, value: 0 }), await e.done;
|
|
80
80
|
}
|
|
81
|
-
}),
|
|
82
|
-
const e = async (
|
|
81
|
+
}), v = (t) => t === void 0 ? null : h(t), ot = (t) => {
|
|
82
|
+
const e = async (o) => v(await t.get("cursors", o));
|
|
83
83
|
return {
|
|
84
|
-
async get(
|
|
85
|
-
return (await t.get("cursors",
|
|
84
|
+
async get(o) {
|
|
85
|
+
return (await t.get("cursors", o))?.cursor ?? null;
|
|
86
86
|
},
|
|
87
|
-
async set(
|
|
88
|
-
const s = await e(
|
|
89
|
-
await t.put("cursors", { groupId:
|
|
87
|
+
async set(o, a) {
|
|
88
|
+
const s = await e(o);
|
|
89
|
+
await t.put("cursors", { groupId: o, ...s, cursor: a });
|
|
90
90
|
},
|
|
91
|
-
async getRecord(
|
|
92
|
-
return e(
|
|
91
|
+
async getRecord(o) {
|
|
92
|
+
return e(o);
|
|
93
93
|
},
|
|
94
|
-
async setRecord(
|
|
95
|
-
if (
|
|
96
|
-
await t.delete("cursors",
|
|
94
|
+
async setRecord(o, a) {
|
|
95
|
+
if (Y(a)) {
|
|
96
|
+
await t.delete("cursors", o);
|
|
97
97
|
return;
|
|
98
98
|
}
|
|
99
99
|
await t.put("cursors", {
|
|
100
|
-
groupId:
|
|
101
|
-
...
|
|
100
|
+
groupId: o,
|
|
101
|
+
...h(a)
|
|
102
102
|
});
|
|
103
103
|
},
|
|
104
104
|
async records() {
|
|
105
|
-
const
|
|
106
|
-
for (const s of
|
|
107
|
-
|
|
108
|
-
return
|
|
105
|
+
const o = await t.getAll("cursors"), a = /* @__PURE__ */ new Map();
|
|
106
|
+
for (const s of o)
|
|
107
|
+
a.set(s.groupId, v(s) ?? {});
|
|
108
|
+
return a;
|
|
109
109
|
},
|
|
110
110
|
async clear() {
|
|
111
111
|
await t.clear("cursors");
|
|
112
112
|
}
|
|
113
113
|
};
|
|
114
|
-
},
|
|
115
|
-
async mark(e,
|
|
116
|
-
await t.get("dirty", e) || await t.put("dirty", { entityId: e, entityType:
|
|
114
|
+
}, at = (t) => ({
|
|
115
|
+
async mark(e, o) {
|
|
116
|
+
await t.get("dirty", e) || await t.put("dirty", { entityId: e, entityType: o });
|
|
117
117
|
},
|
|
118
118
|
async isDirty(e) {
|
|
119
119
|
return await t.get("dirty", e) !== void 0;
|
|
120
120
|
},
|
|
121
121
|
async getDirtyForType(e) {
|
|
122
|
-
return (await t.getAllFromIndex("dirty", "entityType", e)).map((
|
|
122
|
+
return (await t.getAllFromIndex("dirty", "entityType", e)).map((a) => a.entityId);
|
|
123
123
|
},
|
|
124
124
|
async clear(e) {
|
|
125
125
|
await t.delete("dirty", e);
|
|
@@ -127,87 +127,99 @@ const Y = 10, V = 9, w = "actionPosition", j = "replica", z = (t, e, a, o) => {
|
|
|
127
127
|
async clearAll() {
|
|
128
128
|
await t.clear("dirty");
|
|
129
129
|
}
|
|
130
|
-
}),
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
await
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
130
|
+
}), nt = (t, e, o) => {
|
|
131
|
+
const a = (n) => ({
|
|
132
|
+
...structuredClone(n),
|
|
133
|
+
components: k(n)
|
|
134
|
+
}), s = (n) => {
|
|
135
|
+
const { components: r, ...l } = n;
|
|
136
|
+
return l;
|
|
137
|
+
}, u = async (n) => {
|
|
138
|
+
const r = await t.get("entities", n);
|
|
139
|
+
return r === void 0 ? void 0 : s(r);
|
|
140
|
+
}, i = async (n, r) => {
|
|
141
|
+
r === null ? await t.delete("relationships", n) : await t.put("relationships", { key: n, rows: r });
|
|
142
142
|
}, y = async (n) => {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
143
|
+
const r = await t.get("relationships", n.key);
|
|
144
|
+
await i(n.key, H(r?.rows, n));
|
|
145
|
+
}, w = async (n) => {
|
|
146
|
+
const r = await t.get("relationships", n.key);
|
|
147
|
+
await i(n.key, F(r?.rows, n));
|
|
148
|
+
}, c = async (n, r) => {
|
|
149
|
+
for (const l of [P(n, r), B(n, r)])
|
|
150
|
+
l.remove !== null && await w(l.remove), l.add !== null && await y(l.add);
|
|
151
|
+
}, p = async (n) => {
|
|
152
|
+
if (!await o.isDirty(n)) return;
|
|
153
|
+
const l = await e.getForEntity(n);
|
|
154
|
+
if (l.length === 0) return;
|
|
155
|
+
const S = M(l, n);
|
|
156
|
+
if (S === null) return;
|
|
157
|
+
const q = await u(n);
|
|
158
|
+
await t.put("entities", a(S)), await c(q, S), await o.clear(n);
|
|
153
159
|
}, d = async (n) => {
|
|
154
|
-
const
|
|
155
|
-
|
|
160
|
+
for (const r of await o.getDirtyForType(n))
|
|
161
|
+
await p(r);
|
|
162
|
+
}, m = async (n) => {
|
|
163
|
+
const r = await t.get("relationships", n);
|
|
164
|
+
return C(r?.rows);
|
|
156
165
|
};
|
|
157
166
|
return {
|
|
158
167
|
async get(n) {
|
|
159
|
-
await
|
|
160
|
-
const
|
|
161
|
-
return
|
|
168
|
+
await p(n);
|
|
169
|
+
const r = await t.get("entities", n);
|
|
170
|
+
return r === void 0 ? null : s(r);
|
|
162
171
|
},
|
|
163
172
|
async set(n) {
|
|
164
|
-
const
|
|
165
|
-
await t.put("entities",
|
|
173
|
+
const r = await u(n.id);
|
|
174
|
+
await t.put("entities", a(n)), await c(r, n);
|
|
166
175
|
},
|
|
167
176
|
async query(n) {
|
|
168
|
-
return await
|
|
177
|
+
return await d(n), (await t.getAllFromIndex("entities", "type", n)).map(s);
|
|
178
|
+
},
|
|
179
|
+
async queryByComponent(n) {
|
|
180
|
+
return await d(z(n)), (await t.getAllFromIndex("entities", "components", n)).filter((l) => l.deleted_hlc === null).map((l) => l.id).sort();
|
|
169
181
|
},
|
|
170
182
|
async queryByRelationship({
|
|
171
183
|
as: n,
|
|
172
|
-
type:
|
|
173
|
-
targetId:
|
|
184
|
+
type: r,
|
|
185
|
+
targetId: l
|
|
174
186
|
}) {
|
|
175
|
-
return await
|
|
187
|
+
return await d(j), m(G(n, r, l));
|
|
176
188
|
},
|
|
177
189
|
async queryByRelationshipSource({
|
|
178
190
|
as: n,
|
|
179
|
-
type:
|
|
180
|
-
sourceId:
|
|
191
|
+
type: r,
|
|
192
|
+
sourceId: l
|
|
181
193
|
}) {
|
|
182
|
-
await
|
|
183
|
-
const
|
|
184
|
-
return
|
|
194
|
+
await d(j);
|
|
195
|
+
const S = await t.get("relationships", R(n, r, l));
|
|
196
|
+
return b(S?.rows);
|
|
185
197
|
},
|
|
186
198
|
async queryByMembership(n) {
|
|
187
|
-
return await
|
|
199
|
+
return await d(x), m(L(n));
|
|
188
200
|
},
|
|
189
201
|
async queryByMembershipEntity(n) {
|
|
190
|
-
await
|
|
191
|
-
const
|
|
192
|
-
return
|
|
202
|
+
await d(x);
|
|
203
|
+
const r = await t.get("relationships", T(n));
|
|
204
|
+
return N(r?.rows);
|
|
193
205
|
},
|
|
194
206
|
async reset() {
|
|
195
207
|
await t.clear("relationships"), await t.clear("entities");
|
|
196
208
|
}
|
|
197
209
|
};
|
|
198
|
-
},
|
|
210
|
+
}, st = (t) => ({
|
|
199
211
|
...t,
|
|
200
212
|
scope: t.scope ?? "field",
|
|
201
213
|
remoteActions: t.remoteActions ?? []
|
|
202
|
-
}),
|
|
214
|
+
}), _ = (t) => ({
|
|
203
215
|
action: t.action,
|
|
204
216
|
status: t.status,
|
|
205
217
|
enqueuedAtHlc: t.enqueuedAtHlc,
|
|
206
218
|
// A row predating the field reads as "always concurrent", never
|
|
207
219
|
// silently dropped.
|
|
208
220
|
basedOnGsn: t.basedOnGsn ?? 0,
|
|
209
|
-
conflict: t.conflict === void 0 ? void 0 :
|
|
210
|
-
}),
|
|
221
|
+
conflict: t.conflict === void 0 ? void 0 : st(t.conflict)
|
|
222
|
+
}), rt = (t) => ({
|
|
211
223
|
async put(e) {
|
|
212
224
|
await t.put("outbox", {
|
|
213
225
|
action: e.action,
|
|
@@ -217,22 +229,22 @@ const Y = 10, V = 9, w = "actionPosition", j = "replica", z = (t, e, a, o) => {
|
|
|
217
229
|
conflict: e.conflict
|
|
218
230
|
});
|
|
219
231
|
},
|
|
220
|
-
async putAndDelete(e,
|
|
221
|
-
const
|
|
222
|
-
|
|
232
|
+
async putAndDelete(e, o) {
|
|
233
|
+
const a = t.transaction("outbox", "readwrite");
|
|
234
|
+
a.store.put({
|
|
223
235
|
action: e.action,
|
|
224
236
|
status: e.status,
|
|
225
237
|
enqueuedAtHlc: e.enqueuedAtHlc,
|
|
226
238
|
basedOnGsn: e.basedOnGsn,
|
|
227
239
|
conflict: e.conflict
|
|
228
|
-
}),
|
|
240
|
+
}), a.store.delete(o), await a.done;
|
|
229
241
|
},
|
|
230
242
|
async list() {
|
|
231
|
-
return (await t.getAll("outbox")).map(
|
|
243
|
+
return (await t.getAll("outbox")).map(_).sort((o, a) => X(o.enqueuedAtHlc, a.enqueuedAtHlc));
|
|
232
244
|
},
|
|
233
245
|
async get(e) {
|
|
234
|
-
const
|
|
235
|
-
return
|
|
246
|
+
const o = await t.get("outbox", e);
|
|
247
|
+
return o === void 0 ? null : _(o);
|
|
236
248
|
},
|
|
237
249
|
async delete(e) {
|
|
238
250
|
await t.delete("outbox", e);
|
|
@@ -240,76 +252,82 @@ const Y = 10, V = 9, w = "actionPosition", j = "replica", z = (t, e, a, o) => {
|
|
|
240
252
|
async clear() {
|
|
241
253
|
await t.clear("outbox");
|
|
242
254
|
}
|
|
243
|
-
}),
|
|
255
|
+
}), it = (t) => ({
|
|
244
256
|
async load() {
|
|
245
|
-
const e = t.transaction(["replica", "replicaCursor"], "readonly"),
|
|
246
|
-
if (
|
|
257
|
+
const e = t.transaction(["replica", "replicaCursor"], "readonly"), o = await e.objectStore("replicaCursor").get(A);
|
|
258
|
+
if (o === void 0)
|
|
247
259
|
return await e.done, null;
|
|
248
|
-
const
|
|
260
|
+
const a = await e.objectStore("replica").getAll();
|
|
249
261
|
await e.done;
|
|
250
262
|
const s = {
|
|
251
|
-
format:
|
|
252
|
-
position:
|
|
253
|
-
revision:
|
|
254
|
-
entities:
|
|
263
|
+
format: o.format,
|
|
264
|
+
position: o.position,
|
|
265
|
+
revision: o.revision,
|
|
266
|
+
entities: a
|
|
255
267
|
};
|
|
256
268
|
return K(s) ? s : null;
|
|
257
269
|
},
|
|
258
270
|
async save(e) {
|
|
259
|
-
const
|
|
260
|
-
await
|
|
271
|
+
const o = t.transaction(["replica", "replicaCursor"], "readwrite"), a = o.objectStore("replica");
|
|
272
|
+
await a.clear();
|
|
261
273
|
for (const s of e.entities)
|
|
262
|
-
await
|
|
263
|
-
await
|
|
264
|
-
id:
|
|
274
|
+
await a.put(s);
|
|
275
|
+
await o.objectStore("replicaCursor").put({
|
|
276
|
+
id: A,
|
|
265
277
|
format: e.format,
|
|
266
278
|
position: e.position,
|
|
267
279
|
revision: e.revision
|
|
268
|
-
}), await
|
|
280
|
+
}), await o.done;
|
|
269
281
|
},
|
|
270
282
|
async clear() {
|
|
271
283
|
const e = t.transaction(["replica", "replicaCursor"], "readwrite");
|
|
272
284
|
await e.objectStore("replica").clear(), await e.objectStore("replicaCursor").clear(), await e.done;
|
|
273
285
|
}
|
|
274
|
-
}),
|
|
275
|
-
const e = t.dbName ?? "ebb-storage",
|
|
276
|
-
upgrade:
|
|
277
|
-
}),
|
|
286
|
+
}), yt = async (t = {}) => {
|
|
287
|
+
const e = t.dbName ?? "ebb-storage", o = await O(e, Q, {
|
|
288
|
+
upgrade: Z
|
|
289
|
+
}), a = et(o), s = at(o), u = nt(o, a, s), i = ot(o), y = rt(o), w = it(o);
|
|
278
290
|
return {
|
|
279
291
|
actions: {
|
|
280
292
|
async append(c) {
|
|
281
|
-
const
|
|
282
|
-
for (const
|
|
283
|
-
await s.mark(
|
|
284
|
-
|
|
293
|
+
const p = await a.append(c);
|
|
294
|
+
for (const d of c.updates)
|
|
295
|
+
await s.mark(
|
|
296
|
+
d.subject_id,
|
|
297
|
+
I(d, await u.get(d.subject_id))
|
|
298
|
+
);
|
|
299
|
+
return p;
|
|
285
300
|
},
|
|
286
301
|
async appendMany(c) {
|
|
287
|
-
const
|
|
288
|
-
for (const
|
|
289
|
-
for (const
|
|
290
|
-
await s.mark(
|
|
291
|
-
|
|
302
|
+
const p = await a.appendMany(c);
|
|
303
|
+
for (const d of c)
|
|
304
|
+
for (const m of d.updates)
|
|
305
|
+
await s.mark(
|
|
306
|
+
m.subject_id,
|
|
307
|
+
I(m, await u.get(m.subject_id))
|
|
308
|
+
);
|
|
309
|
+
return p;
|
|
292
310
|
},
|
|
293
311
|
async readTail(c) {
|
|
294
|
-
return
|
|
312
|
+
return a.readTail(c);
|
|
295
313
|
},
|
|
296
314
|
async lastPosition() {
|
|
297
|
-
return
|
|
315
|
+
return a.lastPosition();
|
|
298
316
|
},
|
|
299
317
|
async getAll() {
|
|
300
|
-
return
|
|
318
|
+
return a.getAll();
|
|
301
319
|
},
|
|
302
320
|
async getForEntity(c) {
|
|
303
|
-
return
|
|
321
|
+
return a.getForEntity(c);
|
|
304
322
|
},
|
|
305
323
|
async clear() {
|
|
306
|
-
await
|
|
324
|
+
await a.clear(), await s.clearAll(), await u.reset(), await w.clear();
|
|
307
325
|
}
|
|
308
326
|
},
|
|
309
|
-
entities:
|
|
327
|
+
entities: u,
|
|
310
328
|
dirtyTracker: {
|
|
311
|
-
async mark(c,
|
|
312
|
-
await s.mark(c,
|
|
329
|
+
async mark(c, p) {
|
|
330
|
+
await s.mark(c, p);
|
|
313
331
|
},
|
|
314
332
|
async isDirty(c) {
|
|
315
333
|
return s.isDirty(c);
|
|
@@ -324,17 +342,17 @@ const Y = 10, V = 9, w = "actionPosition", j = "replica", z = (t, e, a, o) => {
|
|
|
324
342
|
await s.clearAll();
|
|
325
343
|
}
|
|
326
344
|
},
|
|
327
|
-
cursors:
|
|
328
|
-
outbox:
|
|
329
|
-
replica:
|
|
345
|
+
cursors: i,
|
|
346
|
+
outbox: y,
|
|
347
|
+
replica: w,
|
|
330
348
|
async isDirty(c) {
|
|
331
349
|
return s.isDirty(c);
|
|
332
350
|
},
|
|
333
351
|
async reset() {
|
|
334
|
-
await
|
|
352
|
+
await a.clear(), await s.clearAll(), await u.reset(), await w.clear(), await i.clear();
|
|
335
353
|
}
|
|
336
354
|
};
|
|
337
355
|
};
|
|
338
356
|
export {
|
|
339
|
-
|
|
357
|
+
yt as createIndexedDBAdapter
|
|
340
358
|
};
|