@gonvex/client 0.1.30 → 0.1.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,38 +1,78 @@
1
1
  /**
2
- * An ordered, in-memory view of mutations that have not settled yet.
2
+ * Ordered pending entity mutations layered over immutable authoritative data.
3
3
  *
4
- * Authoritative sync rows remain untouched. Consumers materialize this overlay
5
- * at read time, so rejecting an entry simply reveals the current server state.
4
+ * A source is one concrete sync/query subscription (including its arguments).
5
+ * Successful mutations remain pending until every source that exposed the
6
+ * optimistic row reports that mutation id in an authoritative update. This
7
+ * prevents a fast RPC acknowledgement from revealing an older subscription
8
+ * snapshot while its invalidation is still in flight.
6
9
  */
7
10
  export class OptimisticOverlay {
8
11
  entries = [];
9
12
  listeners = new Set();
10
13
  cache = new Map();
11
14
  version = 0;
12
- /** Append a mutation's patches after every currently pending mutation. */
13
- add(mutationId, patches) {
14
- if (patches.length === 0)
15
+ settling = false;
16
+ add(mutationId, patches, options = {}) {
17
+ const normalized = patches.map(clonePatch).filter((patch) => patchEntity(patch) !== "");
18
+ if (normalized.length === 0)
15
19
  return;
16
- this.entries.push({ mutationId, patches: patches.map(clonePatch) });
17
- this.changed(affectedCollections(patches));
20
+ this.entries.push({
21
+ mutationId,
22
+ patches: normalized,
23
+ accepted: options.accepted === true,
24
+ targets: new Set(),
25
+ acknowledgedTargets: new Set(),
26
+ });
27
+ this.changed(affectedEntities(normalized));
18
28
  }
19
- /** Remove patches after a successful authoritative server result. */
29
+ /** Reserve a live projection even when its first snapshot is still pending. */
30
+ expectSource(source, entity) {
31
+ let added = false;
32
+ for (const entry of this.entries) {
33
+ if (!entry.patches.some((patch) => patchEntity(patch) === entity))
34
+ continue;
35
+ if (entry.targets.has(source))
36
+ continue;
37
+ entry.targets.add(source);
38
+ added = true;
39
+ }
40
+ if (!added)
41
+ return;
42
+ this.version += 1;
43
+ this.cache.clear();
44
+ }
45
+ /** Mark the transport result successful without dropping visible optimism. */
46
+ accept(mutationId) {
47
+ const entry = this.entries.find((candidate) => candidate.mutationId === mutationId);
48
+ if (!entry)
49
+ return [];
50
+ entry.accepted = true;
51
+ return this.settleReadyEntries();
52
+ }
53
+ /** Compatibility alias. Prefer accept followed by authoritative acknowledge. */
20
54
  settle(mutationId) {
21
- this.remove(mutationId);
55
+ this.accept(mutationId);
22
56
  }
23
57
  /** Remove patches after a deterministic server rejection. */
24
58
  reject(mutationId) {
25
59
  this.remove(mutationId);
26
60
  }
27
- /** Materialize one collection without mutating its authoritative rows. */
28
- apply(collection, rows, keyField) {
29
- const cached = this.cache.get(collection);
61
+ apply(sourceOrEntity, entityOrRows, rowsOrKey, maybeKey) {
62
+ const legacy = Array.isArray(entityOrRows);
63
+ const source = legacy ? sourceOrEntity : sourceOrEntity;
64
+ const entity = legacy ? sourceOrEntity : entityOrRows;
65
+ const rows = (legacy ? entityOrRows : rowsOrKey);
66
+ const keyField = (legacy ? rowsOrKey : maybeKey);
67
+ const cacheKey = `${source}\u0000${entity}`;
68
+ const cached = this.cache.get(cacheKey);
30
69
  if (cached?.base === rows && cached.version === this.version)
31
70
  return cached.rows;
32
71
  let materialized = rows.slice();
33
72
  for (const entry of this.entries) {
73
+ let touched = false;
34
74
  for (const patch of entry.patches) {
35
- if (patch.collection !== collection)
75
+ if (patchEntity(patch) !== entity)
36
76
  continue;
37
77
  const index = materialized.findIndex((row) => {
38
78
  const key = row[keyField];
@@ -41,44 +81,124 @@ export class OptimisticOverlay {
41
81
  if (patch.op === "patch") {
42
82
  if (index >= 0) {
43
83
  materialized[index] = { ...materialized[index], ...patch.fields };
84
+ touched = true;
44
85
  }
45
86
  }
46
87
  else if (patch.op === "insert") {
47
- if (index < 0) {
88
+ if (index < 0)
48
89
  materialized.push({ ...patch.fields, [keyField]: patch.rowId });
49
- }
90
+ touched = true;
50
91
  }
51
92
  else if (index >= 0) {
52
93
  materialized = [...materialized.slice(0, index), ...materialized.slice(index + 1)];
94
+ touched = true;
53
95
  }
54
96
  }
97
+ if (touched) {
98
+ entry.targets.add(source);
99
+ }
100
+ else if (entry.targets.has(source)) {
101
+ // The source cannot expose this row, so it is already reconciled from
102
+ // that source's perspective.
103
+ entry.acknowledgedTargets.add(source);
104
+ }
55
105
  }
56
- this.cache.set(collection, { base: rows, version: this.version, rows: materialized });
106
+ this.cache.set(cacheKey, { base: rows, version: this.version, rows: materialized });
57
107
  return materialized;
58
108
  }
59
- /** Subscribe to collections whose materialized rows may have changed. */
109
+ /** Record authoritative delivery for a source; returns fully reconciled ids. */
110
+ acknowledge(source, mutationIds) {
111
+ if (!mutationIds?.length)
112
+ return [];
113
+ const ids = new Set(mutationIds);
114
+ for (const entry of this.entries) {
115
+ if (ids.has(entry.mutationId) && entry.targets.has(source)) {
116
+ entry.acknowledgedTargets.add(source);
117
+ }
118
+ }
119
+ return this.settleReadyEntries();
120
+ }
121
+ /** Reconcile restored committed entries against an authoritative snapshot. */
122
+ acknowledgeMatching(source, entity, rows, keyField) {
123
+ for (const entry of this.entries) {
124
+ if (!entry.accepted || !entry.targets.has(source))
125
+ continue;
126
+ const patches = entry.patches.filter((patch) => {
127
+ if (patchEntity(patch) !== entity)
128
+ return false;
129
+ if (patch.op === "delete")
130
+ return patchMatchesRows(patch, rows, keyField);
131
+ return rows.some((row) => {
132
+ const key = row[keyField];
133
+ return key !== null && key !== undefined && String(key) === patch.rowId;
134
+ });
135
+ });
136
+ if (patches.length === 0 || !patches.every((patch) => patchMatchesRows(patch, rows, keyField)))
137
+ continue;
138
+ entry.acknowledgedTargets.add(source);
139
+ }
140
+ return this.settleReadyEntries();
141
+ }
142
+ /** Stop waiting for a subscription that no longer exists. */
143
+ removeSource(source) {
144
+ for (const entry of this.entries) {
145
+ entry.targets.delete(source);
146
+ entry.acknowledgedTargets.delete(source);
147
+ }
148
+ for (const key of this.cache.keys()) {
149
+ if (key.startsWith(`${source}\u0000`))
150
+ this.cache.delete(key);
151
+ }
152
+ return this.settleReadyEntries();
153
+ }
60
154
  subscribe(listener) {
61
155
  this.listeners.add(listener);
62
156
  return () => this.listeners.delete(listener);
63
157
  }
64
- /** Whether any pending mutation touches this collection row. */
65
- pendingFor(collection, rowId) {
66
- return this.entries.some((entry) => entry.patches.some((patch) => (patch.collection === collection && patch.rowId === rowId)));
158
+ pendingFor(entity, rowId) {
159
+ return this.entries.some((entry) => entry.patches.some((patch) => (patchEntity(patch) === entity && patch.rowId === rowId)));
160
+ }
161
+ settleReadyEntries() {
162
+ // Removing an entry emits a new materialized snapshot. Query/sync
163
+ // listeners may synchronously acknowledge that snapshot and re-enter this
164
+ // method, so only the outer settlement pass is allowed to splice entries.
165
+ // The nested acknowledgement still updates acknowledgedTargets; the outer
166
+ // reverse loop observes that state when it reaches the remaining entry.
167
+ if (this.settling)
168
+ return [];
169
+ this.settling = true;
170
+ const settled = [];
171
+ try {
172
+ for (let index = this.entries.length - 1; index >= 0; index -= 1) {
173
+ const entry = this.entries[index];
174
+ if (!entry?.accepted)
175
+ continue;
176
+ if ([...entry.targets].some((target) => !entry.acknowledgedTargets.has(target)))
177
+ continue;
178
+ this.entries.splice(index, 1);
179
+ settled.push(entry.mutationId);
180
+ this.changed(affectedEntities(entry.patches));
181
+ }
182
+ return settled.reverse();
183
+ }
184
+ finally {
185
+ this.settling = false;
186
+ }
67
187
  }
68
188
  remove(mutationId) {
69
189
  const index = this.entries.findIndex((entry) => entry.mutationId === mutationId);
70
190
  if (index < 0)
71
191
  return;
72
192
  const [entry] = this.entries.splice(index, 1);
73
- this.changed(affectedCollections(entry.patches));
193
+ this.changed(affectedEntities(entry.patches));
74
194
  }
75
- changed(collections) {
195
+ changed(entities) {
76
196
  this.version += 1;
77
197
  this.cache.clear();
78
- for (const collection of collections) {
198
+ for (const entity of entities) {
79
199
  for (const listener of Array.from(this.listeners)) {
80
200
  try {
81
- listener(collection);
201
+ listener(entity);
82
202
  }
83
203
  catch {
84
204
  // A view listener must not be able to break mutation delivery.
@@ -87,12 +207,81 @@ export class OptimisticOverlay {
87
207
  }
88
208
  }
89
209
  }
90
- function affectedCollections(patches) {
91
- return new Set(patches.map((patch) => patch.collection));
210
+ export function optimisticPatchesFromReference(definition, args) {
211
+ if (!definition?.entity)
212
+ return [];
213
+ const record = isRecord(args) ? args : {};
214
+ const configuredRowId = definition.rowIdPath.length > 0
215
+ ? readPath(record, definition.rowIdPath)
216
+ : undefined;
217
+ const rowId = String(configuredRowId ?? record.id ?? record._id ?? "");
218
+ const nested = readPath(record, definition.fieldsPath);
219
+ if (!rowId || !isRecord(nested))
220
+ return [];
221
+ return [{
222
+ entity: definition.entity,
223
+ rowId,
224
+ op: "patch",
225
+ fields: normalizeOptimisticFields(nested),
226
+ }];
227
+ }
228
+ function normalizeOptimisticFields(fields) {
229
+ const normalized = { ...fields };
230
+ for (const [key, value] of Object.entries(fields)) {
231
+ const camel = key.replace(/_([a-z0-9])/g, (_, character) => character.toUpperCase());
232
+ if (!(camel in normalized))
233
+ normalized[camel] = value;
234
+ }
235
+ return normalized;
236
+ }
237
+ function readPath(value, path) {
238
+ let current = value;
239
+ for (const segment of path) {
240
+ if (!isRecord(current))
241
+ return undefined;
242
+ current = current[segment];
243
+ }
244
+ return current;
245
+ }
246
+ function isRecord(value) {
247
+ return !!value && typeof value === "object" && !Array.isArray(value);
248
+ }
249
+ function patchEntity(patch) {
250
+ return String(patch.entity ?? patch.collection ?? "");
251
+ }
252
+ function affectedEntities(patches) {
253
+ return new Set(patches.map(patchEntity).filter(Boolean));
92
254
  }
93
255
  function clonePatch(patch) {
94
256
  if (patch.op === "delete")
95
257
  return { ...patch };
96
258
  return { ...patch, fields: { ...patch.fields } };
97
259
  }
260
+ function patchMatchesRows(patch, rows, keyField) {
261
+ const row = rows.find((candidate) => {
262
+ const key = candidate[keyField];
263
+ return key !== null && key !== undefined && String(key) === patch.rowId;
264
+ });
265
+ if (patch.op === "delete")
266
+ return row === undefined;
267
+ if (!row)
268
+ return false;
269
+ return Object.entries(patch.fields).every(([key, value]) => valuesEqual(row[key], value));
270
+ }
271
+ function valuesEqual(left, right) {
272
+ if (Object.is(left, right))
273
+ return true;
274
+ if (Array.isArray(left) || Array.isArray(right)) {
275
+ return Array.isArray(left)
276
+ && Array.isArray(right)
277
+ && left.length === right.length
278
+ && left.every((value, index) => valuesEqual(value, right[index]));
279
+ }
280
+ if (!isRecord(left) || !isRecord(right))
281
+ return false;
282
+ const leftKeys = Object.keys(left).sort();
283
+ const rightKeys = Object.keys(right).sort();
284
+ return leftKeys.length === rightKeys.length
285
+ && leftKeys.every((key, index) => key === rightKeys[index] && valuesEqual(left[key], right[key]));
286
+ }
98
287
  //# sourceMappingURL=optimistic.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"optimistic.js","sourceRoot":"","sources":["../src/optimistic.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"optimistic.js","sourceRoot":"","sources":["../src/optimistic.ts"],"names":[],"mappings":"AA+CA;;;;;;;;GAQG;AACH,MAAM,OAAO,iBAAiB;IACX,OAAO,GAAmB,EAAE,CAAC;IAC7B,SAAS,GAAG,IAAI,GAAG,EAA4B,CAAC;IAChD,KAAK,GAAG,IAAI,GAAG,EAA2B,CAAC;IACpD,OAAO,GAAG,CAAC,CAAC;IACZ,QAAQ,GAAG,KAAK,CAAC;IAEzB,GAAG,CAAC,UAAkB,EAAE,OAA0B,EAAE,UAAkC,EAAE;QACtF,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;QACxF,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QACpC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;YAChB,UAAU;YACV,OAAO,EAAE,UAAU;YACnB,QAAQ,EAAE,OAAO,CAAC,QAAQ,KAAK,IAAI;YACnC,OAAO,EAAE,IAAI,GAAG,EAAE;YAClB,mBAAmB,EAAE,IAAI,GAAG,EAAE;SAC/B,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,+EAA+E;IAC/E,YAAY,CAAC,MAAc,EAAE,MAAc;QACzC,IAAI,KAAK,GAAG,KAAK,CAAC;QAClB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC;gBAAE,SAAS;YAC5E,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,SAAS;YACxC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC1B,KAAK,GAAG,IAAI,CAAC;QACf,CAAC;QACD,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,8EAA8E;IAC9E,MAAM,CAAC,UAAkB;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC;QACpF,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,CAAC;QACtB,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;QACtB,OAAO,IAAI,CAAC,kBAAkB,EAAE,CAAC;IACnC,CAAC;IAED,gFAAgF;IAChF,MAAM,CAAC,UAAkB;QACvB,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC1B,CAAC;IAED,6DAA6D;IAC7D,MAAM,CAAC,UAAkB;QACvB,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC1B,CAAC;IAQD,KAAK,CACH,cAAsB,EACtB,YAAqC,EACrC,SAAkC,EAClC,QAAiB;QAEjB,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC;QACxD,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,YAAsB,CAAC;QAChE,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAmB,CAAC;QACnE,MAAM,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAW,CAAC;QAC3D,MAAM,QAAQ,GAAG,GAAG,MAAM,SAAS,MAAM,EAAE,CAAC;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,MAAM,EAAE,IAAI,KAAK,IAAI,IAAI,MAAM,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO;YAAE,OAAO,MAAM,CAAC,IAAI,CAAC;QAEjF,IAAI,YAAY,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAChC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjC,IAAI,OAAO,GAAG,KAAK,CAAC;YACpB,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBAClC,IAAI,WAAW,CAAC,KAAK,CAAC,KAAK,MAAM;oBAAE,SAAS;gBAC5C,MAAM,KAAK,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE;oBAC3C,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC;oBAC1B,OAAO,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC;gBAC1E,CAAC,CAAC,CAAC;gBACH,IAAI,KAAK,CAAC,EAAE,KAAK,OAAO,EAAE,CAAC;oBACzB,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;wBACf,YAAY,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;wBAClE,OAAO,GAAG,IAAI,CAAC;oBACjB,CAAC;gBACH,CAAC;qBAAM,IAAI,KAAK,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;oBACjC,IAAI,KAAK,GAAG,CAAC;wBAAE,YAAY,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;oBAC/E,OAAO,GAAG,IAAI,CAAC;gBACjB,CAAC;qBAAM,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;oBACtB,YAAY,GAAG,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;oBACnF,OAAO,GAAG,IAAI,CAAC;gBACjB,CAAC;YACH,CAAC;YACD,IAAI,OAAO,EAAE,CAAC;gBACZ,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC5B,CAAC;iBAAM,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBACrC,sEAAsE;gBACtE,6BAA6B;gBAC7B,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;QACpF,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,gFAAgF;IAChF,WAAW,CAAC,MAAc,EAAE,WAA0C;QACpE,IAAI,CAAC,WAAW,EAAE,MAAM;YAAE,OAAO,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;QACjC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjC,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC3D,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,kBAAkB,EAAE,CAAC;IACnC,CAAC;IAED,8EAA8E;IAC9E,mBAAmB,CAAC,MAAc,EAAE,MAAc,EAAE,IAAoB,EAAE,QAAgB;QACxF,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,SAAS;YAC5D,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;gBAC7C,IAAI,WAAW,CAAC,KAAK,CAAC,KAAK,MAAM;oBAAE,OAAO,KAAK,CAAC;gBAChD,IAAI,KAAK,CAAC,EAAE,KAAK,QAAQ;oBAAE,OAAO,gBAAgB,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;gBAC1E,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;oBACvB,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC;oBAC1B,OAAO,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC;gBAC1E,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YACH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;gBAAE,SAAS;YACzG,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,IAAI,CAAC,kBAAkB,EAAE,CAAC;IACnC,CAAC;IAED,6DAA6D;IAC7D,YAAY,CAAC,MAAc;QACzB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC7B,KAAK,CAAC,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC3C,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YACpC,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,MAAM,QAAQ,CAAC;gBAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,IAAI,CAAC,kBAAkB,EAAE,CAAC;IACnC,CAAC;IAED,SAAS,CAAC,QAAkC;QAC1C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED,UAAU,CAAC,MAAc,EAAE,KAAa;QACtC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAChE,WAAW,CAAC,KAAK,CAAC,KAAK,MAAM,IAAI,KAAK,CAAC,KAAK,KAAK,KAAK,CACvD,CAAC,CAAC,CAAC;IACN,CAAC;IAEO,kBAAkB;QACxB,kEAAkE;QAClE,0EAA0E;QAC1E,0EAA0E;QAC1E,0EAA0E;QAC1E,wEAAwE;QACxE,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,KAAK,IAAI,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;gBACjE,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAClC,IAAI,CAAC,KAAK,EAAE,QAAQ;oBAAE,SAAS;gBAC/B,IAAI,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;oBAAE,SAAS;gBAC1F,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gBAC9B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;gBAC/B,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YAChD,CAAC;YACD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACxB,CAAC;IACH,CAAC;IAEO,MAAM,CAAC,UAAkB;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC;QACjF,IAAI,KAAK,GAAG,CAAC;YAAE,OAAO;QACtB,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,KAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACjD,CAAC;IAEO,OAAO,CAAC,QAAqB;QACnC,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC9B,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;gBAClD,IAAI,CAAC;oBACH,QAAQ,CAAC,MAAM,CAAC,CAAC;gBACnB,CAAC;gBAAC,MAAM,CAAC;oBACP,+DAA+D;gBACjE,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAED,MAAM,UAAU,8BAA8B,CAC5C,UAAoD,EACpD,IAAa;IAEb,IAAI,CAAC,UAAU,EAAE,MAAM;QAAE,OAAO,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1C,MAAM,eAAe,GAAG,UAAU,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;QACrD,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,SAAS,CAAC;QACxC,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,KAAK,GAAG,MAAM,CAAC,eAAe,IAAI,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;IACvD,IAAI,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3C,OAAO,CAAC;YACN,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,KAAK;YACL,EAAE,EAAE,OAAO;YACX,MAAM,EAAE,yBAAyB,CAAC,MAAM,CAAC;SAC1C,CAAC,CAAC;AACL,CAAC;AAED,SAAS,yBAAyB,CAAC,MAA+B;IAChE,MAAM,UAAU,GAA4B,EAAE,GAAG,MAAM,EAAE,CAAC;IAC1D,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,SAAiB,EAAE,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC;QAC7F,IAAI,CAAC,CAAC,KAAK,IAAI,UAAU,CAAC;YAAE,UAAU,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;IACxD,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc,EAAE,IAAuB;IACvD,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,MAAM,OAAO,IAAI,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,OAAO,SAAS,CAAC;QACzC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,WAAW,CAAC,KAAsB;IACzC,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAmC;IAC3D,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,UAAU,CAAC,KAAsB;IACxC,IAAI,KAAK,CAAC,EAAE,KAAK,QAAQ;QAAE,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;IAC/C,OAAO,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;AACnD,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAsB,EAAE,IAAoB,EAAE,QAAgB;IACtF,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;QAClC,MAAM,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;QAChC,OAAO,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC;IAC1E,CAAC,CAAC,CAAC;IACH,IAAI,KAAK,CAAC,EAAE,KAAK,QAAQ;QAAE,OAAO,GAAG,KAAK,SAAS,CAAC;IACpD,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACvB,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AAC5F,CAAC;AAED,SAAS,WAAW,CAAC,IAAa,EAAE,KAAc;IAChD,IAAI,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;eACrB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;eACpB,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM;eAC5B,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1C,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5C,OAAO,QAAQ,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM;WACtC,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,SAAS,CAAC,KAAK,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACtG,CAAC"}
package/dist/outbox.d.ts CHANGED
@@ -4,10 +4,32 @@ export type MutationOutboxOptions = {
4
4
  indexedDB?: IDBFactory;
5
5
  IDBKeyRange?: typeof IDBKeyRange;
6
6
  enabled?: boolean;
7
+ /**
8
+ * Injectable durable record storage for runtimes without IndexedDB (React
9
+ * Native). When provided, the queue semantics still run in the SDK; the
10
+ * store only persists entries so they survive an app restart.
11
+ */
12
+ store?: OutboxStore;
13
+ };
14
+ /**
15
+ * A dumb durable record store backing {@link StoreMutationOutbox}. It holds
16
+ * whole entries keyed by id and knows nothing about queue semantics — total
17
+ * order, causal barriers, and inflight recovery all stay in the SDK.
18
+ */
19
+ export type OutboxStore = {
20
+ /** Every persisted entry across all scopes; called once to hydrate. */
21
+ load(): Promise<MutationOutboxEntry[]>;
22
+ /** Insert or replace the entry with this id. */
23
+ put(entry: MutationOutboxEntry): Promise<void>;
24
+ delete(id: number): Promise<void>;
25
+ clear(scope?: string): Promise<void>;
26
+ close?(): void;
7
27
  };
8
28
  export type MutationOutboxEntry = {
9
29
  /** Auto-incremented sequence number. Lower ids always happened first. */
10
30
  id: number;
31
+ /** Authenticated project/tenant/user identity that owns this mutation. */
32
+ scope: string;
11
33
  path: string;
12
34
  args: unknown;
13
35
  idempotencyKey: string;
@@ -19,23 +41,28 @@ export type MutationOutboxEntry = {
19
41
  attempts: number;
20
42
  nextAttemptAt: number;
21
43
  lastError?: string;
22
- state: "pending" | "inflight";
44
+ state: "pending" | "inflight" | "committed";
23
45
  };
24
46
  export type EnqueueMutation = {
47
+ scope: string;
25
48
  path: string;
26
49
  args: unknown;
27
50
  idempotencyKey?: string;
28
51
  entityKeys?: string[];
29
52
  patches?: OptimisticPatch[];
53
+ /** Direct online sends start inflight so the background drain cannot race them. */
54
+ state?: "pending" | "inflight";
30
55
  };
31
56
  export type MutationOutbox = {
32
57
  enqueue(mutation: EnqueueMutation): Promise<MutationOutboxEntry>;
33
- loadAll(): Promise<MutationOutboxEntry[]>;
34
- nextReady(now: number): Promise<MutationOutboxEntry | undefined>;
58
+ loadAll(scope: string): Promise<MutationOutboxEntry[]>;
59
+ nextReady(scope: string, now: number): Promise<MutationOutboxEntry | undefined>;
35
60
  markInflight(id: number): Promise<void>;
61
+ markCommitted(id: number): Promise<void>;
36
62
  ack(id: number): Promise<void>;
37
63
  fail(id: number, error: string): Promise<void>;
38
- count(): Promise<number>;
64
+ count(scope: string): Promise<number>;
65
+ clear(scope: string): Promise<void>;
39
66
  subscribe(listener: () => void): () => void;
40
67
  };
41
68
  /**
@@ -63,24 +90,65 @@ export declare class DexieMutationOutbox implements MutationOutbox {
63
90
  private nextMemoryId;
64
91
  constructor(options?: MutationOutboxOptions);
65
92
  enqueue(mutation: EnqueueMutation): Promise<MutationOutboxEntry>;
66
- loadAll(): Promise<MutationOutboxEntry[]>;
67
- nextReady(now: number): Promise<MutationOutboxEntry | undefined>;
93
+ loadAll(scope: string): Promise<MutationOutboxEntry[]>;
94
+ nextReady(scope: string, now: number): Promise<MutationOutboxEntry | undefined>;
68
95
  markInflight(id: number): Promise<void>;
96
+ markCommitted(id: number): Promise<void>;
69
97
  ack(id: number): Promise<void>;
70
98
  fail(id: number, error: string): Promise<void>;
71
- count(): Promise<number>;
99
+ count(scope: string): Promise<number>;
100
+ clear(scope: string): Promise<void>;
72
101
  subscribe(listener: () => void): () => void;
73
102
  private enqueueInMemory;
74
103
  private loadAllFromMemory;
75
104
  private markInflightInMemory;
105
+ private markCommittedInMemory;
76
106
  private ackInMemory;
77
107
  private failInMemory;
78
108
  private sortedMemoryEntries;
79
109
  private remember;
80
- private replaceMemoryEntries;
110
+ private replaceMemoryEntriesForScope;
81
111
  private notify;
82
112
  private degradeToMemory;
83
113
  private open;
84
114
  private createDatabase;
85
115
  }
116
+ /**
117
+ * The same totally ordered queue semantics as {@link DexieMutationOutbox},
118
+ * run entirely in memory with every state transition written through an
119
+ * injected {@link OutboxStore}. Hydration replays `store.load()` once and
120
+ * seeds the auto-increment id from the highest persisted id, so replayed
121
+ * entries keep their original ids, idempotency keys, and enqueue order.
122
+ *
123
+ * The store is an optimization for durability, not a prerequisite for the
124
+ * optimistic mutation path. A failing store permanently degrades this
125
+ * instance to the same queue semantics in memory for the current session.
126
+ */
127
+ export declare class StoreMutationOutbox implements MutationOutbox {
128
+ private readonly store;
129
+ private readonly listeners;
130
+ private readonly entries;
131
+ private readonly ready;
132
+ private memoryOnly;
133
+ private nextId;
134
+ constructor(store: OutboxStore, options?: {
135
+ enabled?: boolean;
136
+ });
137
+ enqueue(mutation: EnqueueMutation): Promise<MutationOutboxEntry>;
138
+ loadAll(scope: string): Promise<MutationOutboxEntry[]>;
139
+ nextReady(scope: string, now: number): Promise<MutationOutboxEntry | undefined>;
140
+ markInflight(id: number): Promise<void>;
141
+ markCommitted(id: number): Promise<void>;
142
+ ack(id: number): Promise<void>;
143
+ fail(id: number, error: string): Promise<void>;
144
+ count(scope: string): Promise<number>;
145
+ clear(scope: string): Promise<void>;
146
+ subscribe(listener: () => void): () => void;
147
+ private hydrate;
148
+ private persistPut;
149
+ private persistDelete;
150
+ private sortedEntries;
151
+ private notify;
152
+ private degradeToMemory;
153
+ }
86
154
  export declare function createMutationOutbox(options?: MutationOutboxOptions): MutationOutbox;