doxum 0.1.5 → 0.1.7
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/README.md +75 -9
- package/dist/{contract-4E3moCbY.d.ts → contract-DNZ4D53r.d.ts} +87 -76
- package/dist/{contract-uYJTmT8o.d.cts → contract-j3SLGAwh.d.cts} +87 -76
- package/dist/index.cjs +284 -947
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -64
- package/dist/index.d.ts +3 -64
- package/dist/index.js +218 -872
- package/dist/index.js.map +1 -1
- package/dist/integration-B56u1l9V.js +30 -0
- package/dist/integration-B56u1l9V.js.map +1 -0
- package/dist/integration-CZwCwFBS.cjs +35 -0
- package/dist/integration-CZwCwFBS.cjs.map +1 -0
- package/dist/integration.cjs +12 -14
- package/dist/integration.d.cts +3 -2
- package/dist/integration.d.ts +3 -2
- package/dist/integration.js +3 -14
- package/dist/local-sync.cjs +57 -18
- package/dist/local-sync.cjs.map +1 -1
- package/dist/local-sync.d.cts +2 -2
- package/dist/local-sync.d.ts +2 -2
- package/dist/local-sync.js +57 -18
- package/dist/local-sync.js.map +1 -1
- package/dist/{ownership-CU-9DKJQ.cjs → ownership-CY0nPXGF.cjs} +4 -1
- package/dist/ownership-CY0nPXGF.cjs.map +1 -0
- package/dist/{ownership-B-VAPcce.js → ownership-CduRygE7.js} +4 -1
- package/dist/ownership-CduRygE7.js.map +1 -0
- package/dist/react.cjs +27 -19
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +27 -19
- package/dist/react.js.map +1 -1
- package/dist/runtime-0mOFbe_H.cjs +2439 -0
- package/dist/runtime-0mOFbe_H.cjs.map +1 -0
- package/dist/runtime-B22tuj9A.d.cts +150 -0
- package/dist/runtime-BFmhzPpZ.d.ts +150 -0
- package/dist/runtime-DF1q9Gje.js +2129 -0
- package/dist/runtime-DF1q9Gje.js.map +1 -0
- package/package.json +1 -1
- package/skills/doxum-runtime/SKILL.md +2 -1
- package/skills/doxum-runtime/references/guide.en.md +38 -26
- package/skills/doxum-runtime/references/guide.zh-CN.md +24 -21
- package/skills/doxum-runtime/references/invariants.en.md +13 -10
- package/skills/doxum-runtime/references/invariants.zh-CN.md +3 -3
- package/skills/doxum-runtime/references/patterns.en.md +26 -64
- package/skills/doxum-runtime/references/patterns.zh-CN.md +15 -52
- package/dist/dependency-C5_R1tvQ.js +0 -496
- package/dist/dependency-C5_R1tvQ.js.map +0 -1
- package/dist/dependency-Dfzs3khk.cjs +0 -722
- package/dist/dependency-Dfzs3khk.cjs.map +0 -1
- package/dist/integration.cjs.map +0 -1
- package/dist/integration.js.map +0 -1
- package/dist/ownership-B-VAPcce.js.map +0 -1
- package/dist/ownership-CU-9DKJQ.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const
|
|
3
|
-
const require_ownership = require("./ownership-
|
|
2
|
+
const require_runtime = require("./runtime-0mOFbe_H.cjs");
|
|
3
|
+
const require_ownership = require("./ownership-CY0nPXGF.cjs");
|
|
4
4
|
const require_driver = require("./driver-CNxqMVFH.cjs");
|
|
5
5
|
//#region core/src/impact.ts
|
|
6
6
|
const emptyCollectionImpact = Object.freeze({
|
|
@@ -29,7 +29,7 @@ const createImpact = (input) => {
|
|
|
29
29
|
if (pathBuckets.get(void 0)?.some(test)) return true;
|
|
30
30
|
return pathBuckets.get(address[0])?.some(test) ?? false;
|
|
31
31
|
};
|
|
32
|
-
const pathsAffect = (address) => address.length === 0 ? paths.length > 0 : somePath(address, (changed) =>
|
|
32
|
+
const pathsAffect = (address) => address.length === 0 ? paths.length > 0 : somePath(address, (changed) => require_runtime.overlaps(changed, address));
|
|
33
33
|
let collectionCache;
|
|
34
34
|
const findCollection = (address) => input.collections?.find((entry) => entry.address.length === address.length && entry.address.every((segment, index) => segment === address[index]));
|
|
35
35
|
return {
|
|
@@ -38,12 +38,12 @@ const createImpact = (input) => {
|
|
|
38
38
|
affects: (value) => {
|
|
39
39
|
require_ownership.profile.impact.affects();
|
|
40
40
|
if (kind === "reset") return true;
|
|
41
|
-
if (!
|
|
42
|
-
if (pathsAffect(
|
|
41
|
+
if (!require_runtime.belongs(value, input.schema)) return false;
|
|
42
|
+
if (pathsAffect(require_runtime.address(value))) return true;
|
|
43
43
|
if (value.kind === "collection") {
|
|
44
|
-
const collection = findCollection(
|
|
44
|
+
const collection = findCollection(require_runtime.address(value));
|
|
45
45
|
if (!collection) return false;
|
|
46
|
-
const id$1 =
|
|
46
|
+
const id$1 = require_runtime.id(value);
|
|
47
47
|
if (id$1 !== void 0) return collection.added.has(id$1) || collection.removed.has(id$1) || collection.updated.has(id$1);
|
|
48
48
|
return collection.added.size > 0 || collection.removed.size > 0 || collection.updated.size > 0 || collection.orderChanged;
|
|
49
49
|
}
|
|
@@ -55,7 +55,7 @@ const createImpact = (input) => {
|
|
|
55
55
|
const cached = collectionCache?.find((entry) => entry.address.length === selector.address.length && entry.address.every((segment, index) => segment === selector.address[index]))?.value;
|
|
56
56
|
if (cached) return cached;
|
|
57
57
|
const exact = findCollection(selector.address);
|
|
58
|
-
if (somePath(selector.address, (changed) =>
|
|
58
|
+
if (somePath(selector.address, (changed) => require_runtime.contains(changed, selector.address) && changed.length < selector.address.length)) {
|
|
59
59
|
const reset = { kind: "reset" };
|
|
60
60
|
(collectionCache ??= []).push({
|
|
61
61
|
address: selector.address,
|
|
@@ -89,83 +89,175 @@ const createImpact = (input) => {
|
|
|
89
89
|
//#endregion
|
|
90
90
|
//#region core/src/history.ts
|
|
91
91
|
const createHistory = (input) => {
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
let undos = [];
|
|
93
|
+
let redos = [];
|
|
94
94
|
const listeners = /* @__PURE__ */ new Set();
|
|
95
95
|
let state = Object.freeze({
|
|
96
96
|
undoDepth: 0,
|
|
97
97
|
redoDepth: 0
|
|
98
98
|
});
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
let revision = 0;
|
|
100
|
+
let pending = false;
|
|
101
|
+
let disposed = false;
|
|
102
|
+
let group;
|
|
103
|
+
const unchanged = () => ({
|
|
104
|
+
status: "unchanged",
|
|
105
|
+
revision: input.revision()
|
|
106
|
+
});
|
|
107
|
+
const publish = () => {
|
|
108
|
+
if (state.undoDepth === undos.length && state.redoDepth === redos.length) return;
|
|
109
|
+
state = Object.freeze({
|
|
101
110
|
undoDepth: undos.length,
|
|
102
111
|
redoDepth: redos.length
|
|
103
112
|
});
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
113
|
+
revision++;
|
|
114
|
+
pending = true;
|
|
115
|
+
};
|
|
116
|
+
const flush = () => {
|
|
117
|
+
if (!pending) return [];
|
|
118
|
+
pending = false;
|
|
119
|
+
const errors = [];
|
|
120
|
+
for (const listener of [...listeners]) {
|
|
121
|
+
if (!listeners.has(listener)) continue;
|
|
122
|
+
try {
|
|
123
|
+
listener();
|
|
124
|
+
} catch (error) {
|
|
125
|
+
errors.push({
|
|
126
|
+
phase: "listener",
|
|
127
|
+
error
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return errors;
|
|
110
132
|
};
|
|
111
133
|
const clear = () => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
134
|
+
group = void 0;
|
|
135
|
+
undos.length = redos.length = 0;
|
|
136
|
+
publish();
|
|
137
|
+
};
|
|
138
|
+
const travel = (direction) => {
|
|
139
|
+
input.assertIdle();
|
|
140
|
+
const from = direction === "redo" ? redos : undos;
|
|
141
|
+
const to = direction === "redo" ? undos : redos;
|
|
142
|
+
const previousUndos = undos;
|
|
143
|
+
const previousRedos = redos;
|
|
144
|
+
const entry = direction === "cancel" ? from.at(-1) : from.pop();
|
|
145
|
+
if (!entry) return unchanged();
|
|
146
|
+
if (direction === "cancel") {
|
|
147
|
+
if (!group || group.entry !== entry) throw new Error("History group no longer owns its entry.");
|
|
148
|
+
undos = group.undos;
|
|
149
|
+
redos = group.redos;
|
|
150
|
+
} else to.push(entry);
|
|
151
|
+
let committed = false;
|
|
152
|
+
try {
|
|
153
|
+
const operations = direction === "redo" ? entry.batches.flatMap((batch) => batch.operations) : entry.batches.slice().reverse().flatMap((batch) => batch.inverse);
|
|
154
|
+
const result = input.apply(operations);
|
|
155
|
+
committed = result.status !== "rejected";
|
|
156
|
+
if (committed && direction === "cancel") group = void 0;
|
|
157
|
+
if (result.status === "unchanged") {
|
|
158
|
+
publish();
|
|
159
|
+
const errors = input.notify(flush);
|
|
160
|
+
if (errors.length) throw new AggregateError(errors.map((entry) => entry.error), "History listeners failed.");
|
|
161
|
+
}
|
|
162
|
+
return result;
|
|
163
|
+
} finally {
|
|
164
|
+
if (!committed) if (direction === "cancel") {
|
|
165
|
+
undos = previousUndos;
|
|
166
|
+
redos = previousRedos;
|
|
167
|
+
} else {
|
|
168
|
+
to.pop();
|
|
169
|
+
from.push(entry);
|
|
170
|
+
}
|
|
116
171
|
}
|
|
117
172
|
};
|
|
118
173
|
return {
|
|
119
174
|
api: {
|
|
120
|
-
current,
|
|
175
|
+
current: () => state,
|
|
176
|
+
revision: () => revision,
|
|
121
177
|
subscribe: (listener) => {
|
|
178
|
+
if (disposed) throw new require_runtime.DocumentDisposedError();
|
|
122
179
|
listeners.add(listener);
|
|
123
|
-
return () =>
|
|
180
|
+
return () => {
|
|
181
|
+
listeners.delete(listener);
|
|
182
|
+
};
|
|
124
183
|
},
|
|
125
184
|
undo: () => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
revision: input.revision()
|
|
130
|
-
};
|
|
131
|
-
const result = input.apply(entry.inverse);
|
|
132
|
-
if (result.status === "committed") {
|
|
133
|
-
redos.push(entry);
|
|
134
|
-
emit();
|
|
135
|
-
} else undos.push(entry);
|
|
136
|
-
return result;
|
|
185
|
+
input.assertIdle();
|
|
186
|
+
group = void 0;
|
|
187
|
+
return travel("undo");
|
|
137
188
|
},
|
|
138
189
|
redo: () => {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
revision: input.revision()
|
|
143
|
-
};
|
|
144
|
-
const result = input.apply(entry.operations);
|
|
145
|
-
if (result.status === "committed") {
|
|
146
|
-
undos.push(entry);
|
|
147
|
-
emit();
|
|
148
|
-
} else redos.push(entry);
|
|
149
|
-
return result;
|
|
190
|
+
input.assertIdle();
|
|
191
|
+
group = void 0;
|
|
192
|
+
return travel("redo");
|
|
150
193
|
},
|
|
151
|
-
clear
|
|
194
|
+
clear: () => {
|
|
195
|
+
input.assertIdle();
|
|
196
|
+
clear();
|
|
197
|
+
const errors = input.notify(flush);
|
|
198
|
+
if (errors.length) throw new AggregateError(errors.map((entry) => entry.error), "History listeners failed.");
|
|
199
|
+
},
|
|
200
|
+
group: () => {
|
|
201
|
+
input.assertIdle();
|
|
202
|
+
if (group) throw new Error("A history group is already active.");
|
|
203
|
+
if (input.capacity <= 0) throw new Error("History is disabled.");
|
|
204
|
+
const scope = {
|
|
205
|
+
undos: undos.slice(),
|
|
206
|
+
redos: redos.slice()
|
|
207
|
+
};
|
|
208
|
+
group = scope;
|
|
209
|
+
return Object.freeze({
|
|
210
|
+
end: () => {
|
|
211
|
+
input.assertIdle();
|
|
212
|
+
if (group === scope) group = void 0;
|
|
213
|
+
},
|
|
214
|
+
cancel: () => {
|
|
215
|
+
input.assertIdle();
|
|
216
|
+
if (group !== scope) return unchanged();
|
|
217
|
+
if (!scope.entry) {
|
|
218
|
+
group = void 0;
|
|
219
|
+
return unchanged();
|
|
220
|
+
}
|
|
221
|
+
const result = travel("cancel");
|
|
222
|
+
if (result.status !== "rejected") group = void 0;
|
|
223
|
+
return result;
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
}
|
|
152
227
|
},
|
|
153
228
|
record: (operations, inverse) => {
|
|
154
229
|
if (input.capacity <= 0) return;
|
|
155
|
-
|
|
230
|
+
const batch = {
|
|
156
231
|
operations,
|
|
157
232
|
inverse
|
|
158
|
-
}
|
|
159
|
-
if (
|
|
233
|
+
};
|
|
234
|
+
if (group?.entry) group.entry.batches.push(batch);
|
|
235
|
+
else {
|
|
236
|
+
const entry = { batches: [batch] };
|
|
237
|
+
undos.push(entry);
|
|
238
|
+
if (group) group.entry = entry;
|
|
239
|
+
if (undos.length > input.capacity) undos.shift();
|
|
240
|
+
}
|
|
160
241
|
redos.length = 0;
|
|
161
|
-
|
|
242
|
+
publish();
|
|
243
|
+
},
|
|
244
|
+
publish,
|
|
245
|
+
flush,
|
|
246
|
+
endGroup: () => {
|
|
247
|
+
group = void 0;
|
|
162
248
|
},
|
|
163
|
-
invalidate: clear
|
|
249
|
+
invalidate: clear,
|
|
250
|
+
dispose: () => {
|
|
251
|
+
disposed = true;
|
|
252
|
+
listeners.clear();
|
|
253
|
+
clear();
|
|
254
|
+
pending = false;
|
|
255
|
+
}
|
|
164
256
|
};
|
|
165
257
|
};
|
|
166
258
|
//#endregion
|
|
167
259
|
//#region core/src/access/writer.ts
|
|
168
|
-
const schemaRoot = (schema) =>
|
|
260
|
+
const schemaRoot = (schema) => require_runtime.object(schema.shape);
|
|
169
261
|
const emit = (sink, operation) => sink(operation);
|
|
170
262
|
const writerFor = (node, inputAddress, sink) => {
|
|
171
263
|
const address = Object.freeze(inputAddress);
|
|
@@ -180,7 +272,7 @@ const writerFor = (node, inputAddress, sink) => {
|
|
|
180
272
|
at: address
|
|
181
273
|
}) : void 0
|
|
182
274
|
};
|
|
183
|
-
if (node.kind === "dict"
|
|
275
|
+
if (node.kind === "dict") return {
|
|
184
276
|
set: (key, value) => emit(sink, {
|
|
185
277
|
type: "dict.set",
|
|
186
278
|
at: address,
|
|
@@ -233,20 +325,20 @@ const writerFor = (node, inputAddress, sink) => {
|
|
|
233
325
|
}) } : {}
|
|
234
326
|
};
|
|
235
327
|
if (node.kind === "tree") return {
|
|
236
|
-
insert: (treeNodeId, value,
|
|
328
|
+
insert: (treeNodeId, value, position) => emit(sink, {
|
|
237
329
|
type: "tree.insert",
|
|
238
330
|
at: address,
|
|
239
331
|
treeNodeId,
|
|
240
332
|
value,
|
|
241
|
-
parentId,
|
|
242
|
-
index
|
|
333
|
+
parentId: position?.parentId,
|
|
334
|
+
index: position?.index
|
|
243
335
|
}),
|
|
244
|
-
move: (treeNodeId,
|
|
336
|
+
move: (treeNodeId, position) => emit(sink, {
|
|
245
337
|
type: "tree.move",
|
|
246
338
|
at: address,
|
|
247
339
|
treeNodeId,
|
|
248
|
-
parentId,
|
|
249
|
-
index
|
|
340
|
+
parentId: position?.parentId,
|
|
341
|
+
index: position?.index
|
|
250
342
|
}),
|
|
251
343
|
remove: (treeNodeId) => emit(sink, {
|
|
252
344
|
type: "tree.remove",
|
|
@@ -330,7 +422,6 @@ const writerFor = (node, inputAddress, sink) => {
|
|
|
330
422
|
})
|
|
331
423
|
};
|
|
332
424
|
}
|
|
333
|
-
if (node.kind === "single") return writerFor(node.value, address, sink);
|
|
334
425
|
if (node.kind === "variant") return {
|
|
335
426
|
replace: (value) => emit(sink, {
|
|
336
427
|
type: "variant.replace",
|
|
@@ -356,69 +447,15 @@ const documentWriter = (schema, sink) => writerFor(schemaRoot(schema), [], sink)
|
|
|
356
447
|
//#endregion
|
|
357
448
|
//#region core/src/mutation/issue.ts
|
|
358
449
|
const ownAddress$1 = (address) => Object.freeze(address.slice());
|
|
359
|
-
const at
|
|
450
|
+
const at = (address, code, message, operation) => Object.freeze({
|
|
360
451
|
source: "mutation",
|
|
361
452
|
code,
|
|
362
453
|
address: ownAddress$1(address),
|
|
363
454
|
message,
|
|
364
455
|
...operation === void 0 ? {} : { operation }
|
|
365
456
|
});
|
|
366
|
-
const from = (operation, code, message) => at
|
|
367
|
-
const input = (code, message) => at
|
|
368
|
-
//#endregion
|
|
369
|
-
//#region core/src/mutation/anchor.ts
|
|
370
|
-
const length = (keys) => keys.length;
|
|
371
|
-
const keyAt = (keys, index) => Array.isArray(keys) ? keys[index] : keys.at(index);
|
|
372
|
-
const keyIndex = (keys, key) => Array.isArray(keys) ? keys.indexOf(key) : keys.index(key);
|
|
373
|
-
const keys = (values, keyOf) => ({
|
|
374
|
-
length: values.length,
|
|
375
|
-
at: (index) => index >= 0 && index < values.length ? keyOf(values[index]) : void 0,
|
|
376
|
-
index: (key) => {
|
|
377
|
-
for (let index = 0; index < values.length; index += 1) if (keyOf(values[index]) === key) return index;
|
|
378
|
-
return -1;
|
|
379
|
-
}
|
|
380
|
-
});
|
|
381
|
-
const index = (keys, anchor) => {
|
|
382
|
-
if (!anchor) return length(keys);
|
|
383
|
-
if ("at" in anchor) return anchor.at === "start" ? 0 : length(keys);
|
|
384
|
-
if ("before" in anchor) return keyIndex(keys, anchor.before);
|
|
385
|
-
return keyIndex(keys, anchor.after) + 1;
|
|
386
|
-
};
|
|
387
|
-
const at = (keys, position) => position <= 0 ? { at: "start" } : { after: keyAt(keys, position - 1) };
|
|
388
|
-
const valid = (keys, anchor) => {
|
|
389
|
-
if (!anchor) return true;
|
|
390
|
-
if (typeof anchor !== "object" || anchor === null) return false;
|
|
391
|
-
if (Number("at" in anchor) + Number("before" in anchor) + Number("after" in anchor) !== 1) return false;
|
|
392
|
-
if ("at" in anchor) return anchor.at === "start" || anchor.at === "end";
|
|
393
|
-
return keyIndex(keys, "before" in anchor ? anchor.before : anchor.after) >= 0;
|
|
394
|
-
};
|
|
395
|
-
const afterRemove = (keys, removedIndex, anchor) => {
|
|
396
|
-
const position = index(keys, anchor);
|
|
397
|
-
return position > removedIndex ? position - 1 : position;
|
|
398
|
-
};
|
|
399
|
-
const validPositions = (length, positions) => {
|
|
400
|
-
let previous = -1;
|
|
401
|
-
for (let index = 0; index < positions.length; index += 1) {
|
|
402
|
-
const position = positions[index];
|
|
403
|
-
if (!Number.isInteger(position) || position < 0 || position <= previous || position > length + index) return false;
|
|
404
|
-
previous = position;
|
|
405
|
-
}
|
|
406
|
-
return true;
|
|
407
|
-
};
|
|
408
|
-
const restore = (keys, inserted, positions) => {
|
|
409
|
-
const currentLength = keys.length;
|
|
410
|
-
if (inserted.length !== positions.length || !validPositions(currentLength, positions)) throw new Error("Ordered restore positions are invalid.");
|
|
411
|
-
let readIndex = currentLength - 1;
|
|
412
|
-
let insertedIndex = inserted.length - 1;
|
|
413
|
-
keys.length = currentLength + inserted.length;
|
|
414
|
-
for (let writeIndex = keys.length - 1; writeIndex >= 0; writeIndex -= 1) if (insertedIndex >= 0 && positions[insertedIndex] === writeIndex) {
|
|
415
|
-
keys[writeIndex] = inserted[insertedIndex];
|
|
416
|
-
insertedIndex -= 1;
|
|
417
|
-
} else {
|
|
418
|
-
keys[writeIndex] = keys[readIndex];
|
|
419
|
-
readIndex -= 1;
|
|
420
|
-
}
|
|
421
|
-
};
|
|
457
|
+
const from = (operation, code, message) => at(operation.at, code, message, operation.type);
|
|
458
|
+
const input = (code, message) => at([], code, message);
|
|
422
459
|
//#endregion
|
|
423
460
|
//#region core/src/mutation/execute-entity.ts
|
|
424
461
|
const resolveEntityCollection = (node, value) => {
|
|
@@ -463,13 +500,13 @@ const executeEntity = (target, operation, copyPayload) => {
|
|
|
463
500
|
}
|
|
464
501
|
if (collection.kind === "map" && (operation.anchor || operation.positions)) return rejected$4(operation, "invalid-anchor", "Map entries do not support ordering metadata.");
|
|
465
502
|
if (ids && operation.positions) {
|
|
466
|
-
if (operation.positions.length !== operation.entries.length || !validPositions(ids.length, operation.positions)) return rejected$4(operation, "invalid-operation", "Entity restore positions are invalid.");
|
|
467
|
-
} else if (ids && !valid(ids, operation.anchor)) return rejected$4(operation, "invalid-anchor", "Collection anchor is invalid.");
|
|
503
|
+
if (operation.positions.length !== operation.entries.length || !require_runtime.validPositions(ids.length, operation.positions)) return rejected$4(operation, "invalid-operation", "Entity restore positions are invalid.");
|
|
504
|
+
} else if (ids && !require_runtime.valid(ids, operation.anchor)) return rejected$4(operation, "invalid-anchor", "Collection anchor is invalid.");
|
|
468
505
|
for (const entry of operation.entries) byId[entry.id] = copyPayload ? require_ownership.cloneValue(entry.value, "canonical") : require_ownership.transferPayload(entry.value);
|
|
469
|
-
if (ids) if (operation.positions) restore(ids, operation.entries.map((entry) => entry.id), operation.positions);
|
|
506
|
+
if (ids) if (operation.positions) require_runtime.restore(ids, operation.entries.map((entry) => entry.id), operation.positions);
|
|
470
507
|
else if (!operation.anchor || "at" in operation.anchor && operation.anchor.at === "end") for (const entry of operation.entries) ids.push(entry.id);
|
|
471
508
|
else {
|
|
472
|
-
const insertion = index(ids, operation.anchor);
|
|
509
|
+
const insertion = require_runtime.index(ids, operation.anchor);
|
|
473
510
|
const currentLength = ids.length;
|
|
474
511
|
ids.length = currentLength + operation.entries.length;
|
|
475
512
|
for (let index = currentLength - 1; index >= insertion; index -= 1) ids[index + operation.entries.length] = ids[index];
|
|
@@ -535,15 +572,15 @@ const executeEntity = (target, operation, copyPayload) => {
|
|
|
535
572
|
const position = ids?.indexOf(operation.id) ?? -1;
|
|
536
573
|
if (!exists) return rejected$4(operation, "missing-entity", `Entity '${operation.id}' does not exist.`);
|
|
537
574
|
if (!ids || position < 0) return rejected$4(operation, "invalid-collection", `Collection index is missing '${operation.id}'.`);
|
|
538
|
-
if (!valid(ids, operation.anchor)) return rejected$4(operation, "invalid-anchor", "Collection anchor is invalid.");
|
|
575
|
+
if (!require_runtime.valid(ids, operation.anchor)) return rejected$4(operation, "invalid-anchor", "Collection anchor is invalid.");
|
|
539
576
|
if (operation.anchor && ("before" in operation.anchor && operation.anchor.before === operation.id || "after" in operation.anchor && operation.anchor.after === operation.id)) return rejected$4(operation, "invalid-anchor", "An entity cannot be moved relative to itself.");
|
|
540
|
-
const nextIndex = afterRemove(ids, position, operation.anchor);
|
|
577
|
+
const nextIndex = require_runtime.afterRemove(ids, position, operation.anchor);
|
|
541
578
|
if (nextIndex === position) return { status: "unchanged" };
|
|
542
579
|
const inverse = {
|
|
543
580
|
type: "entity.move",
|
|
544
581
|
at: operation.at,
|
|
545
582
|
id: operation.id,
|
|
546
|
-
anchor: at(ids, position)
|
|
583
|
+
anchor: require_runtime.at(ids, position)
|
|
547
584
|
};
|
|
548
585
|
ids.splice(position, 1);
|
|
549
586
|
ids.splice(nextIndex, 0, operation.id);
|
|
@@ -564,7 +601,7 @@ const executeList = (target, operation, copyPayload) => {
|
|
|
564
601
|
if (!Array.isArray(target.value) && !absent) return rejected$3(operation, "invalid-address", "List target is invalid.");
|
|
565
602
|
if (absent && operation.type !== "list.replace") return rejected$3(operation, "invalid-address", "Only list replacement can initialize an optional list.");
|
|
566
603
|
const list = Array.isArray(target.value) ? target.value : [];
|
|
567
|
-
const orderedKeys = keys(list, target.node.keyOf);
|
|
604
|
+
const orderedKeys = require_runtime.keys(list, target.node.keyOf);
|
|
568
605
|
const own = (value) => copyPayload ? require_ownership.ownPayload(value) : value;
|
|
569
606
|
if (operation.type === "list.replace") {
|
|
570
607
|
if (operation.keys.length !== operation.value.length) return rejected$3(operation, "invalid-list-keys", "List replacement keys are invalid.");
|
|
@@ -599,8 +636,8 @@ const executeList = (target, operation, copyPayload) => {
|
|
|
599
636
|
if (operation.type === "list.insert") {
|
|
600
637
|
if (target.node.keyOf(operation.value) !== operation.key) return rejected$3(operation, "invalid-list-key", "List item key does not match schema.");
|
|
601
638
|
if (orderedKeys.index(operation.key) >= 0) return rejected$3(operation, "duplicate-list-item", `List item '${operation.key}' already exists.`);
|
|
602
|
-
if (!valid(orderedKeys, operation.anchor)) return rejected$3(operation, "invalid-anchor", "List anchor is invalid.");
|
|
603
|
-
list.splice(index(orderedKeys, operation.anchor), 0, own(operation.value));
|
|
639
|
+
if (!require_runtime.valid(orderedKeys, operation.anchor)) return rejected$3(operation, "invalid-anchor", "List anchor is invalid.");
|
|
640
|
+
list.splice(require_runtime.index(orderedKeys, operation.anchor), 0, own(operation.value));
|
|
604
641
|
return {
|
|
605
642
|
status: "changed",
|
|
606
643
|
inverse: [{
|
|
@@ -618,7 +655,7 @@ const executeList = (target, operation, copyPayload) => {
|
|
|
618
655
|
at: operation.at,
|
|
619
656
|
key: operation.key,
|
|
620
657
|
value: require_ownership.cloneValue(list[position], "inverse"),
|
|
621
|
-
anchor: at(orderedKeys, position)
|
|
658
|
+
anchor: require_runtime.at(orderedKeys, position)
|
|
622
659
|
};
|
|
623
660
|
list.splice(position, 1);
|
|
624
661
|
return {
|
|
@@ -626,15 +663,15 @@ const executeList = (target, operation, copyPayload) => {
|
|
|
626
663
|
inverse: [inverse]
|
|
627
664
|
};
|
|
628
665
|
}
|
|
629
|
-
if (!valid(orderedKeys, operation.anchor)) return rejected$3(operation, "invalid-anchor", "List anchor is invalid.");
|
|
666
|
+
if (!require_runtime.valid(orderedKeys, operation.anchor)) return rejected$3(operation, "invalid-anchor", "List anchor is invalid.");
|
|
630
667
|
if (operation.anchor && ("before" in operation.anchor && operation.anchor.before === operation.key || "after" in operation.anchor && operation.anchor.after === operation.key)) return rejected$3(operation, "invalid-anchor", "A list item cannot be moved relative to itself.");
|
|
631
|
-
const nextIndex = afterRemove(orderedKeys, position, operation.anchor);
|
|
668
|
+
const nextIndex = require_runtime.afterRemove(orderedKeys, position, operation.anchor);
|
|
632
669
|
if (nextIndex === position) return { status: "unchanged" };
|
|
633
670
|
const inverse = {
|
|
634
671
|
type: "list.move",
|
|
635
672
|
at: operation.at,
|
|
636
673
|
key: operation.key,
|
|
637
|
-
anchor: at(orderedKeys, position)
|
|
674
|
+
anchor: require_runtime.at(orderedKeys, position)
|
|
638
675
|
};
|
|
639
676
|
const [entry] = list.splice(position, 1);
|
|
640
677
|
list.splice(nextIndex, 0, entry);
|
|
@@ -817,7 +854,7 @@ const changeChanged = (change, value) => {
|
|
|
817
854
|
return false;
|
|
818
855
|
};
|
|
819
856
|
const is = (value) => require_ownership.isRecord(value) && require_ownership.isRecord(value.nodes);
|
|
820
|
-
const contains
|
|
857
|
+
const contains = (tree, id) => has$1(tree.nodes, id);
|
|
821
858
|
const validate = (value) => {
|
|
822
859
|
if (!is(value)) return false;
|
|
823
860
|
const ids = Object.keys(value.nodes);
|
|
@@ -859,7 +896,6 @@ const documentTreeError = (node, value, address) => {
|
|
|
859
896
|
}
|
|
860
897
|
return;
|
|
861
898
|
}
|
|
862
|
-
if (node.kind === "single") return documentTreeError(node.value, value, address);
|
|
863
899
|
if (node.kind === "variant") {
|
|
864
900
|
if (!require_ownership.isRecord(value) || typeof value[node.tag] !== "string") return void 0;
|
|
865
901
|
const variant = node.variants[value[node.tag]];
|
|
@@ -898,7 +934,7 @@ const replace = (current, operation) => {
|
|
|
898
934
|
};
|
|
899
935
|
};
|
|
900
936
|
const insert = (tree, operation, value) => {
|
|
901
|
-
if (contains
|
|
937
|
+
if (contains(tree, operation.treeNodeId)) return rejected$2("duplicate-tree-node", `Tree node '${operation.treeNodeId}' already exists.`);
|
|
902
938
|
if (!validIndex(operation.index)) return rejected$2("invalid-tree-index", "Tree index is invalid.");
|
|
903
939
|
if (tree.rootId === void 0) {
|
|
904
940
|
if (operation.parentId !== void 0) return rejected$2("missing-tree-parent", `Tree parent '${operation.parentId}' does not exist.`);
|
|
@@ -1023,9 +1059,8 @@ const move = (tree, operation) => {
|
|
|
1023
1059
|
if (!currentParent || parentId === void 0) return rejected$2("invalid-tree", "Tree parent links are inconsistent.");
|
|
1024
1060
|
const originalIndex = childIndex(currentParent, operation.treeNodeId);
|
|
1025
1061
|
if (originalIndex < 0) return rejected$2("invalid-tree", "Tree parent links are inconsistent.");
|
|
1026
|
-
let nextIndex = Math.min(operation.index ?? nextParent.children.length, nextParent.children.length);
|
|
1027
1062
|
currentParent.children.splice(originalIndex, 1);
|
|
1028
|
-
|
|
1063
|
+
const nextIndex = Math.min(operation.index ?? nextParent.children.length, nextParent.children.length);
|
|
1029
1064
|
if (parentId === operation.parentId && nextIndex === originalIndex) {
|
|
1030
1065
|
currentParent.children.splice(originalIndex, 0, operation.treeNodeId);
|
|
1031
1066
|
return { status: "unchanged" };
|
|
@@ -1076,7 +1111,7 @@ const executeTree = (root, target, operation, copyPayload) => {
|
|
|
1076
1111
|
issue: from(operation, "invalid-address", "Tree target is invalid.")
|
|
1077
1112
|
};
|
|
1078
1113
|
const result = replace(target.value, operation);
|
|
1079
|
-
if (result.status === "changed")
|
|
1114
|
+
if (result.status === "changed") require_runtime.set(root, operation.at, require_ownership.ownPayload(operation.value));
|
|
1080
1115
|
return outcome(operation, result);
|
|
1081
1116
|
}
|
|
1082
1117
|
if (!is(target.value)) return {
|
|
@@ -1129,6 +1164,16 @@ const executeValue = (target, operation, copyPayload) => {
|
|
|
1129
1164
|
}
|
|
1130
1165
|
if (operation.type === "variant.replace") {
|
|
1131
1166
|
if (require_ownership.sameStructuralValue(target.value, operation.value)) return { status: "unchanged" };
|
|
1167
|
+
if (target.value === void 0 && target.node.optional) {
|
|
1168
|
+
target.parent[target.key] = own(operation.value);
|
|
1169
|
+
return {
|
|
1170
|
+
status: "changed",
|
|
1171
|
+
inverse: [{
|
|
1172
|
+
type: "value.clear",
|
|
1173
|
+
at: operation.at
|
|
1174
|
+
}]
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1132
1177
|
const inverse = {
|
|
1133
1178
|
type: "variant.replace",
|
|
1134
1179
|
at: operation.at,
|
|
@@ -1207,7 +1252,7 @@ const executeClear = (target, operation) => {
|
|
|
1207
1252
|
issue: from(operation, "required-field", "Only optional values can be cleared.")
|
|
1208
1253
|
};
|
|
1209
1254
|
if (!hasOwn$1(target.parent, target.key)) return { status: "unchanged" };
|
|
1210
|
-
if (target.node.kind !== "field" && target.node.kind !== "variant" && target.node.kind !== "dict" && target.node.kind !== "
|
|
1255
|
+
if (target.node.kind !== "field" && target.node.kind !== "variant" && target.node.kind !== "dict" && target.node.kind !== "list" && target.node.kind !== "tree") return {
|
|
1211
1256
|
status: "rejected",
|
|
1212
1257
|
issue: from(operation, "invalid-operation", "This optional value has no clear operation.")
|
|
1213
1258
|
};
|
|
@@ -1223,8 +1268,7 @@ const executeClear = (target, operation) => {
|
|
|
1223
1268
|
at: operation.at,
|
|
1224
1269
|
value: require_ownership.cloneValue(target.value, "inverse")
|
|
1225
1270
|
};
|
|
1226
|
-
case "dict":
|
|
1227
|
-
case "record": return {
|
|
1271
|
+
case "dict": return {
|
|
1228
1272
|
type: "dict.replace",
|
|
1229
1273
|
at: operation.at,
|
|
1230
1274
|
value: require_ownership.cloneValue(target.value, "inverse")
|
|
@@ -1263,7 +1307,7 @@ const execute = (root, operation, target, copyPayload) => {
|
|
|
1263
1307
|
if (operation.type === "value.clear") return !target ? invalidTarget(operation) : executeClear(target, operation);
|
|
1264
1308
|
if (operation.type === "field.set" || operation.type === "field.clear") return !target || target.node.kind !== "field" ? invalidTarget(operation) : executeValue(target, operation, copyPayload);
|
|
1265
1309
|
if (operation.type === "variant.replace") return !target || target.node.kind !== "variant" ? invalidTarget(operation) : executeValue(target, operation, copyPayload);
|
|
1266
|
-
if (operation.type === "dict.set" || operation.type === "dict.delete" || operation.type === "dict.replace") return !target || target.node.kind !== "dict"
|
|
1310
|
+
if (operation.type === "dict.set" || operation.type === "dict.delete" || operation.type === "dict.replace") return !target || target.node.kind !== "dict" ? invalidTarget(operation) : executeValue(target, operation, copyPayload);
|
|
1267
1311
|
if (operation.type === "entity.create" || operation.type === "entity.remove" || operation.type === "entity.move") return !target || target.node.kind !== "table" && target.node.kind !== "map" ? invalidTarget(operation) : executeEntity(target, operation, copyPayload);
|
|
1268
1312
|
if (operation.type === "list.insert" || operation.type === "list.move" || operation.type === "list.remove" || operation.type === "list.replace") return !target || target.node.kind !== "list" ? invalidTarget(operation) : executeList(target, operation, copyPayload);
|
|
1269
1313
|
if (operation.type === "tree.insert" || operation.type === "tree.move" || operation.type === "tree.remove" || operation.type === "tree.set" || operation.type === "tree.replace") return !target || target.node.kind !== "tree" ? invalidTarget(operation) : executeTree(root, target, operation, copyPayload);
|
|
@@ -1276,7 +1320,7 @@ const execute = (root, operation, target, copyPayload) => {
|
|
|
1276
1320
|
//#region core/src/mutation/journal.ts
|
|
1277
1321
|
const indexNode = () => ({ children: /* @__PURE__ */ new Map() });
|
|
1278
1322
|
const hasOwn = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
1279
|
-
const sameAddress
|
|
1323
|
+
const sameAddress = (left, right) => {
|
|
1280
1324
|
if (left.length !== right.length) return false;
|
|
1281
1325
|
for (let index = 0; index < left.length; index += 1) if (left[index] !== right[index]) return false;
|
|
1282
1326
|
return true;
|
|
@@ -1326,14 +1370,14 @@ const indexedSubjects = (root, address) => {
|
|
|
1326
1370
|
return subjects;
|
|
1327
1371
|
};
|
|
1328
1372
|
const writePresence = (root, address, before) => {
|
|
1329
|
-
const target =
|
|
1373
|
+
const target = require_runtime.locate(root, address);
|
|
1330
1374
|
if (!target) return;
|
|
1331
1375
|
if (before.status === "present") target.parent[target.key] = before.value;
|
|
1332
1376
|
else if (Array.isArray(target.parent)) target.parent.splice(Number(target.key), 1);
|
|
1333
1377
|
else delete target.parent[String(target.key)];
|
|
1334
1378
|
};
|
|
1335
1379
|
const writeContainer = (root, address, value) => {
|
|
1336
|
-
const target =
|
|
1380
|
+
const target = require_runtime.locate(root, address);
|
|
1337
1381
|
if (!target) return;
|
|
1338
1382
|
target.parent[target.key] = value;
|
|
1339
1383
|
};
|
|
@@ -1375,7 +1419,7 @@ const restoreEntity = (value, subject) => {
|
|
|
1375
1419
|
};
|
|
1376
1420
|
const restoreRootSubject = (value, subject) => {
|
|
1377
1421
|
if (subject.kind === "value") return subject.before.status === "present" ? subject.before.value : void 0;
|
|
1378
|
-
if (subject.kind === "variant") return subject.before;
|
|
1422
|
+
if (subject.kind === "variant") return subject.before.status === "present" ? subject.before.value : void 0;
|
|
1379
1423
|
if (subject.kind === "dict") {
|
|
1380
1424
|
if (require_ownership.isRecord(value)) restoreDict(value, subject.state);
|
|
1381
1425
|
return value;
|
|
@@ -1391,17 +1435,17 @@ const restoreRootSubject = (value, subject) => {
|
|
|
1391
1435
|
return restoreChange(value, subject.state);
|
|
1392
1436
|
};
|
|
1393
1437
|
const restoreSubject = (value, prefix, subject) => {
|
|
1394
|
-
if (sameAddress
|
|
1438
|
+
if (sameAddress(prefix, subject.address)) return restoreRootSubject(value, subject);
|
|
1395
1439
|
const address = subject.address.slice(prefix.length);
|
|
1396
1440
|
if (subject.kind === "value") {
|
|
1397
1441
|
writePresence(value, address, subject.before);
|
|
1398
1442
|
return value;
|
|
1399
1443
|
}
|
|
1400
1444
|
if (subject.kind === "variant") {
|
|
1401
|
-
|
|
1445
|
+
writePresence(value, address, subject.before);
|
|
1402
1446
|
return value;
|
|
1403
1447
|
}
|
|
1404
|
-
const current =
|
|
1448
|
+
const current = require_runtime.read(value, address);
|
|
1405
1449
|
if (subject.kind === "dict") {
|
|
1406
1450
|
if (require_ownership.isRecord(current)) restoreDict(current, subject.state);
|
|
1407
1451
|
return value;
|
|
@@ -1419,13 +1463,13 @@ const restoreSubject = (value, prefix, subject) => {
|
|
|
1419
1463
|
return value;
|
|
1420
1464
|
};
|
|
1421
1465
|
const valueChanged = (root, subject) => {
|
|
1422
|
-
const target =
|
|
1466
|
+
const target = require_runtime.locate(root, subject.address);
|
|
1423
1467
|
const exists = !!target && hasOwn(target.parent, target.key);
|
|
1424
1468
|
if (subject.before.status === "absent") return exists;
|
|
1425
1469
|
return !exists || !Object.is(subject.before.value, target?.value);
|
|
1426
1470
|
};
|
|
1427
1471
|
const dictChanged = (root, subject) => {
|
|
1428
|
-
const value =
|
|
1472
|
+
const value = require_runtime.read(root, subject.address);
|
|
1429
1473
|
if (!require_ownership.isRecord(value)) return true;
|
|
1430
1474
|
if (subject.state.mode === "whole") return !require_ownership.sameStructuralValue(subject.state.value, value);
|
|
1431
1475
|
for (const [key, before] of subject.state.entries) {
|
|
@@ -1435,7 +1479,7 @@ const dictChanged = (root, subject) => {
|
|
|
1435
1479
|
return false;
|
|
1436
1480
|
};
|
|
1437
1481
|
const listChanged = (root, subject) => {
|
|
1438
|
-
const value =
|
|
1482
|
+
const value = require_runtime.read(root, subject.address);
|
|
1439
1483
|
if (!Array.isArray(value)) return true;
|
|
1440
1484
|
if (subject.state.mode === "whole") return !require_ownership.sameStructuralValue(subject.state.value, value);
|
|
1441
1485
|
const positions = /* @__PURE__ */ new Map();
|
|
@@ -1467,7 +1511,7 @@ const commonOrderChanged = (before, after) => {
|
|
|
1467
1511
|
return false;
|
|
1468
1512
|
};
|
|
1469
1513
|
const analyzeEntity = (root, subject) => {
|
|
1470
|
-
const resolution = entityCollection(subject,
|
|
1514
|
+
const resolution = entityCollection(subject, require_runtime.read(root, subject.address));
|
|
1471
1515
|
const added = /* @__PURE__ */ new Set();
|
|
1472
1516
|
const removed = /* @__PURE__ */ new Set();
|
|
1473
1517
|
const updated = /* @__PURE__ */ new Set();
|
|
@@ -1499,22 +1543,26 @@ const analyzeEntity = (root, subject) => {
|
|
|
1499
1543
|
};
|
|
1500
1544
|
const subjectChanged = (root, subject) => {
|
|
1501
1545
|
if (subject.kind === "value") return valueChanged(root, subject);
|
|
1502
|
-
if (subject.kind === "variant")
|
|
1546
|
+
if (subject.kind === "variant") {
|
|
1547
|
+
const target = require_runtime.locate(root, subject.address);
|
|
1548
|
+
const exists = !!target && hasOwn(target.parent, target.key);
|
|
1549
|
+
return subject.before.status === "absent" ? exists : !exists || !require_ownership.sameStructuralValue(subject.before.value, target?.value);
|
|
1550
|
+
}
|
|
1503
1551
|
if (subject.kind === "dict") return dictChanged(root, subject);
|
|
1504
1552
|
if (subject.kind === "list") return listChanged(root, subject);
|
|
1505
|
-
return changeChanged(subject.state,
|
|
1553
|
+
return changeChanged(subject.state, require_runtime.read(root, subject.address));
|
|
1506
1554
|
};
|
|
1507
1555
|
const listOrderBefore = (value, node, inverse) => {
|
|
1508
1556
|
const order = value.map(node.keyOf);
|
|
1509
1557
|
if (inverse.type === "list.remove") return order.filter((key) => key !== inverse.key);
|
|
1510
1558
|
if (inverse.type === "list.insert") {
|
|
1511
|
-
order.splice(index(order, inverse.anchor), 0, inverse.key);
|
|
1559
|
+
order.splice(require_runtime.index(order, inverse.anchor), 0, inverse.key);
|
|
1512
1560
|
return order;
|
|
1513
1561
|
}
|
|
1514
1562
|
if (inverse.type === "list.move") {
|
|
1515
1563
|
const position = order.indexOf(inverse.key);
|
|
1516
1564
|
if (position >= 0) order.splice(position, 1);
|
|
1517
|
-
order.splice(index(order, inverse.anchor), 0, inverse.key);
|
|
1565
|
+
order.splice(require_runtime.index(order, inverse.anchor), 0, inverse.key);
|
|
1518
1566
|
}
|
|
1519
1567
|
return order;
|
|
1520
1568
|
};
|
|
@@ -1556,12 +1604,12 @@ const restoreEntityOrder = (order, inverses) => {
|
|
|
1556
1604
|
continue;
|
|
1557
1605
|
}
|
|
1558
1606
|
if (inverse.kind === "restore") {
|
|
1559
|
-
restore(order, inverse.ids, inverse.positions);
|
|
1607
|
+
require_runtime.restore(order, inverse.ids, inverse.positions);
|
|
1560
1608
|
continue;
|
|
1561
1609
|
}
|
|
1562
1610
|
const position = order.indexOf(inverse.id);
|
|
1563
|
-
if (position < 0 || !valid(order, inverse.anchor)) throw new Error(`Entity order inverse cannot restore '${inverse.id}'.`);
|
|
1564
|
-
const nextIndex = afterRemove(order, position, inverse.anchor);
|
|
1611
|
+
if (position < 0 || !require_runtime.valid(order, inverse.anchor)) throw new Error(`Entity order inverse cannot restore '${inverse.id}'.`);
|
|
1612
|
+
const nextIndex = require_runtime.afterRemove(order, position, inverse.anchor);
|
|
1565
1613
|
order.splice(position, 1);
|
|
1566
1614
|
order.splice(nextIndex, 0, inverse.id);
|
|
1567
1615
|
}
|
|
@@ -1618,7 +1666,7 @@ const createChangeJournal = (root) => {
|
|
|
1618
1666
|
const candidates = buckets.get(addressHash) ?? [];
|
|
1619
1667
|
for (const subject of candidates) {
|
|
1620
1668
|
require_ownership.profile.journal.comparison();
|
|
1621
|
-
if (subject.kind === kind && sameAddress
|
|
1669
|
+
if (subject.kind === kind && sameAddress(subject.address, address)) return subject;
|
|
1622
1670
|
}
|
|
1623
1671
|
}
|
|
1624
1672
|
const ownerOf = (address) => {
|
|
@@ -1661,11 +1709,11 @@ const createChangeJournal = (root) => {
|
|
|
1661
1709
|
const recordVariant = (resolved, operation, inverse) => {
|
|
1662
1710
|
if (find("variant", operation.at, resolved.addressHash)) return;
|
|
1663
1711
|
const first = inverse[0];
|
|
1664
|
-
if (first?.type !== "variant.replace") return inverseMismatch(operation);
|
|
1712
|
+
if (first?.type !== "variant.replace" && first?.type !== "value.clear") return inverseMismatch(operation);
|
|
1665
1713
|
add({
|
|
1666
1714
|
...base(resolved, operation),
|
|
1667
1715
|
kind: "variant",
|
|
1668
|
-
before: absorb(first.value, operation.at)
|
|
1716
|
+
before: first.type === "value.clear" ? absent : present(absorb(first.value, operation.at))
|
|
1669
1717
|
});
|
|
1670
1718
|
};
|
|
1671
1719
|
const recordDict = (resolved, operation, inverse) => {
|
|
@@ -1722,7 +1770,7 @@ const createChangeJournal = (root) => {
|
|
|
1722
1770
|
});
|
|
1723
1771
|
return;
|
|
1724
1772
|
}
|
|
1725
|
-
const value =
|
|
1773
|
+
const value = require_runtime.read(root, operation.at);
|
|
1726
1774
|
if (!Array.isArray(value)) return inverseMismatch(operation);
|
|
1727
1775
|
subject = add({
|
|
1728
1776
|
...base(resolved, operation),
|
|
@@ -1760,7 +1808,7 @@ const createChangeJournal = (root) => {
|
|
|
1760
1808
|
};
|
|
1761
1809
|
const recordEntity = (resolved, operation, inverse) => {
|
|
1762
1810
|
if (resolved.node.kind !== "table" && resolved.node.kind !== "map") return inverseMismatch(operation);
|
|
1763
|
-
const resolution = resolveEntityCollection(resolved.node,
|
|
1811
|
+
const resolution = resolveEntityCollection(resolved.node, require_runtime.read(root, operation.at));
|
|
1764
1812
|
if (resolution.status === "invalid") return inverseMismatch(operation);
|
|
1765
1813
|
const collection = resolution.collection;
|
|
1766
1814
|
const subject = find("entity", operation.at, resolved.addressHash) ?? add({
|
|
@@ -1796,7 +1844,7 @@ const createChangeJournal = (root) => {
|
|
|
1796
1844
|
return inverseMismatch(operation);
|
|
1797
1845
|
};
|
|
1798
1846
|
const recordTree = (resolved, operation, inverse) => {
|
|
1799
|
-
const current =
|
|
1847
|
+
const current = require_runtime.read(root, operation.at);
|
|
1800
1848
|
if (inverse.length === 1 && inverse[0].type === "value.clear" && operation.type === "tree.replace") {
|
|
1801
1849
|
const subject = find("tree", operation.at, resolved.addressHash);
|
|
1802
1850
|
if (subject) subject.state = {
|
|
@@ -1829,6 +1877,10 @@ const createChangeJournal = (root) => {
|
|
|
1829
1877
|
record: (resolved, operation, inverse) => {
|
|
1830
1878
|
require_ownership.profile.batch.journalRecord();
|
|
1831
1879
|
if (ownerOf(operation.at)) return;
|
|
1880
|
+
if (operation.type === "value.clear" && resolved.node.kind === "variant") {
|
|
1881
|
+
recordVariant(resolved, operation, inverse);
|
|
1882
|
+
return;
|
|
1883
|
+
}
|
|
1832
1884
|
if (operation.type === "field.set" || operation.type === "field.clear" || operation.type === "value.clear") {
|
|
1833
1885
|
recordValue(resolved, operation, inverse);
|
|
1834
1886
|
return;
|
|
@@ -1870,7 +1922,7 @@ const createChangeJournal = (root) => {
|
|
|
1870
1922
|
const changeAt = (address, addressHash) => {
|
|
1871
1923
|
const candidates = collectionBuckets.get(addressHash) ?? [];
|
|
1872
1924
|
collectionBuckets.set(addressHash, candidates);
|
|
1873
|
-
let change = candidates.find((entry) => sameAddress
|
|
1925
|
+
let change = candidates.find((entry) => sameAddress(entry.address, address));
|
|
1874
1926
|
if (!change) {
|
|
1875
1927
|
change = {
|
|
1876
1928
|
address,
|
|
@@ -1914,7 +1966,7 @@ const createChangeJournal = (root) => {
|
|
|
1914
1966
|
const has = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
1915
1967
|
const stringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
1916
1968
|
const positions = (value) => Array.isArray(value) && value.every((entry) => Number.isInteger(entry) && entry >= 0);
|
|
1917
|
-
const address
|
|
1969
|
+
const address = (value) => stringArray(value);
|
|
1918
1970
|
const anchor = (value) => {
|
|
1919
1971
|
if (!require_ownership.isRecord(value)) return false;
|
|
1920
1972
|
if (Number(has(value, "at")) + Number(has(value, "before")) + Number(has(value, "after")) !== 1) return false;
|
|
@@ -1935,7 +1987,7 @@ const rejected = (code, message) => ({
|
|
|
1935
1987
|
});
|
|
1936
1988
|
const decode = (input) => {
|
|
1937
1989
|
if (!require_ownership.isRecord(input)) return rejected("invalid-operation", "Operation must be an object.");
|
|
1938
|
-
if (!address
|
|
1990
|
+
if (!address(input.at)) return rejected("invalid-address", "Operation address is malformed.");
|
|
1939
1991
|
if (typeof input.type !== "string") return rejected("invalid-operation", "Operation type must be a string.");
|
|
1940
1992
|
switch (input.type) {
|
|
1941
1993
|
case "field.set":
|
|
@@ -2026,7 +2078,7 @@ const createMutationSession = (root, schema, options = {}) => {
|
|
|
2026
2078
|
const rollback = () => {
|
|
2027
2079
|
if (state === "rolled-back") return;
|
|
2028
2080
|
for (let stepIndex = steps.length - 1; stepIndex >= 0; stepIndex -= 1) for (const inverse of steps[stepIndex].inverse) {
|
|
2029
|
-
const result = execute(root, inverse,
|
|
2081
|
+
const result = execute(root, inverse, require_runtime.resolveLocated(schema, root, inverse.at), true);
|
|
2030
2082
|
if (result.status === "rejected") throw new Error(`Document rollback failed: ${result.issue.message}`);
|
|
2031
2083
|
}
|
|
2032
2084
|
state = "rolled-back";
|
|
@@ -2042,7 +2094,7 @@ const createMutationSession = (root, schema, options = {}) => {
|
|
|
2042
2094
|
}
|
|
2043
2095
|
const normalized = normalize(decoded.operation);
|
|
2044
2096
|
require_ownership.profile.batch.entry(normalized.type === "entity.create" ? normalized.entries.length : normalized.type === "entity.remove" ? normalized.ids.length : 1);
|
|
2045
|
-
const resolved =
|
|
2097
|
+
const resolved = require_runtime.resolveLocated(schema, root, normalized.at);
|
|
2046
2098
|
if (resolved?.collection) require_ownership.profile.batch.collectionResolved();
|
|
2047
2099
|
require_ownership.profile.mutation.executed();
|
|
2048
2100
|
const result = execute(root, normalized, resolved, options.copyPayload === true || requiresPayloadCopy(normalized));
|
|
@@ -2111,352 +2163,6 @@ const mutateOperations = (root, schema, operations, options = {}) => {
|
|
|
2111
2163
|
return session.finish();
|
|
2112
2164
|
};
|
|
2113
2165
|
//#endregion
|
|
2114
|
-
//#region core/src/mutation/footprint.ts
|
|
2115
|
-
const sameAddress = (left, right) => left.length === right.length && left.every((segment, index) => segment === right[index]);
|
|
2116
|
-
const containsAddress = (parent, child) => parent.length <= child.length && parent.every((segment, index) => segment === child[index]);
|
|
2117
|
-
const address = (value) => Array.isArray(value) && value.every((segment) => typeof segment === "string") ? Object.freeze(value.slice()) : void 0;
|
|
2118
|
-
const targetKey = (target) => {
|
|
2119
|
-
const at = target.at.join("\0");
|
|
2120
|
-
if (target.kind === "dictionary-key" || target.kind === "list-item") return `${target.kind}:${at}:${target.key}`;
|
|
2121
|
-
if (target.kind === "entity" || target.kind === "tree-node") return `${target.kind}:${at}:${target.id}`;
|
|
2122
|
-
return `${target.kind}:${at}`;
|
|
2123
|
-
};
|
|
2124
|
-
const freezeTarget = (target) => Object.freeze({
|
|
2125
|
-
...target,
|
|
2126
|
-
at: Object.freeze(target.at.slice())
|
|
2127
|
-
});
|
|
2128
|
-
const add = (targets, target) => {
|
|
2129
|
-
const stable = freezeTarget(target);
|
|
2130
|
-
targets.set(targetKey(stable), stable);
|
|
2131
|
-
};
|
|
2132
|
-
const commandFootprint = (operations) => {
|
|
2133
|
-
const targets = /* @__PURE__ */ new Map();
|
|
2134
|
-
for (const operation of operations) switch (operation.type) {
|
|
2135
|
-
case "field.set":
|
|
2136
|
-
case "field.clear":
|
|
2137
|
-
case "value.clear":
|
|
2138
|
-
case "variant.replace":
|
|
2139
|
-
add(targets, {
|
|
2140
|
-
kind: "value",
|
|
2141
|
-
at: operation.at
|
|
2142
|
-
});
|
|
2143
|
-
break;
|
|
2144
|
-
case "dict.replace":
|
|
2145
|
-
add(targets, {
|
|
2146
|
-
kind: "dictionary",
|
|
2147
|
-
at: operation.at
|
|
2148
|
-
});
|
|
2149
|
-
break;
|
|
2150
|
-
case "dict.set":
|
|
2151
|
-
case "dict.delete":
|
|
2152
|
-
add(targets, {
|
|
2153
|
-
kind: "dictionary-key",
|
|
2154
|
-
at: operation.at,
|
|
2155
|
-
key: operation.key
|
|
2156
|
-
});
|
|
2157
|
-
break;
|
|
2158
|
-
case "entity.create":
|
|
2159
|
-
add(targets, {
|
|
2160
|
-
kind: "collection",
|
|
2161
|
-
at: operation.at
|
|
2162
|
-
});
|
|
2163
|
-
for (const entry of operation.entries) add(targets, {
|
|
2164
|
-
kind: "entity",
|
|
2165
|
-
at: operation.at,
|
|
2166
|
-
id: entry.id
|
|
2167
|
-
});
|
|
2168
|
-
break;
|
|
2169
|
-
case "entity.remove":
|
|
2170
|
-
add(targets, {
|
|
2171
|
-
kind: "collection",
|
|
2172
|
-
at: operation.at
|
|
2173
|
-
});
|
|
2174
|
-
for (const id of operation.ids) add(targets, {
|
|
2175
|
-
kind: "entity",
|
|
2176
|
-
at: operation.at,
|
|
2177
|
-
id
|
|
2178
|
-
});
|
|
2179
|
-
break;
|
|
2180
|
-
case "entity.move":
|
|
2181
|
-
add(targets, {
|
|
2182
|
-
kind: "collection",
|
|
2183
|
-
at: operation.at
|
|
2184
|
-
});
|
|
2185
|
-
add(targets, {
|
|
2186
|
-
kind: "entity",
|
|
2187
|
-
at: operation.at,
|
|
2188
|
-
id: operation.id
|
|
2189
|
-
});
|
|
2190
|
-
break;
|
|
2191
|
-
case "list.insert":
|
|
2192
|
-
case "list.move":
|
|
2193
|
-
case "list.remove":
|
|
2194
|
-
add(targets, {
|
|
2195
|
-
kind: "list",
|
|
2196
|
-
at: operation.at
|
|
2197
|
-
});
|
|
2198
|
-
add(targets, {
|
|
2199
|
-
kind: "list-item",
|
|
2200
|
-
at: operation.at,
|
|
2201
|
-
key: operation.key
|
|
2202
|
-
});
|
|
2203
|
-
break;
|
|
2204
|
-
case "list.replace":
|
|
2205
|
-
add(targets, {
|
|
2206
|
-
kind: "list",
|
|
2207
|
-
at: operation.at
|
|
2208
|
-
});
|
|
2209
|
-
for (const key of operation.keys) add(targets, {
|
|
2210
|
-
kind: "list-item",
|
|
2211
|
-
at: operation.at,
|
|
2212
|
-
key
|
|
2213
|
-
});
|
|
2214
|
-
break;
|
|
2215
|
-
case "tree.insert":
|
|
2216
|
-
case "tree.move":
|
|
2217
|
-
case "tree.remove":
|
|
2218
|
-
case "tree.set":
|
|
2219
|
-
add(targets, {
|
|
2220
|
-
kind: "tree",
|
|
2221
|
-
at: operation.at
|
|
2222
|
-
});
|
|
2223
|
-
add(targets, {
|
|
2224
|
-
kind: "tree-node",
|
|
2225
|
-
at: operation.at,
|
|
2226
|
-
id: operation.treeNodeId
|
|
2227
|
-
});
|
|
2228
|
-
break;
|
|
2229
|
-
case "tree.replace":
|
|
2230
|
-
add(targets, {
|
|
2231
|
-
kind: "tree",
|
|
2232
|
-
at: operation.at
|
|
2233
|
-
});
|
|
2234
|
-
break;
|
|
2235
|
-
}
|
|
2236
|
-
return Object.freeze(Array.from(targets.values()));
|
|
2237
|
-
};
|
|
2238
|
-
const overlapsValueAndEntity = (value, entity) => containsAddress([...entity.at, entity.id], value.at) || containsAddress(value.at, [...entity.at, entity.id]);
|
|
2239
|
-
const targetsOverlap = (left, right) => {
|
|
2240
|
-
if (left.kind === "value" && right.kind === "value") return containsAddress(left.at, right.at) || containsAddress(right.at, left.at);
|
|
2241
|
-
if (left.kind === "value" && right.kind === "entity") return overlapsValueAndEntity(left, right);
|
|
2242
|
-
if (left.kind === "entity" && right.kind === "value") return overlapsValueAndEntity(right, left);
|
|
2243
|
-
if (left.kind === "dictionary" && right.kind === "dictionary") return sameAddress(left.at, right.at);
|
|
2244
|
-
if (left.kind === "dictionary" && right.kind === "dictionary-key") return sameAddress(left.at, right.at);
|
|
2245
|
-
if (left.kind === "dictionary-key" && right.kind === "dictionary") return sameAddress(left.at, right.at);
|
|
2246
|
-
if (left.kind === "dictionary-key" && right.kind === "dictionary-key") return sameAddress(left.at, right.at) && left.key === right.key;
|
|
2247
|
-
if (left.kind === "collection" && right.kind === "collection") return sameAddress(left.at, right.at);
|
|
2248
|
-
if (left.kind === "collection" && right.kind === "entity") return sameAddress(left.at, right.at);
|
|
2249
|
-
if (left.kind === "entity" && right.kind === "collection") return sameAddress(left.at, right.at);
|
|
2250
|
-
if (left.kind === "entity" && right.kind === "entity") return sameAddress(left.at, right.at) && left.id === right.id;
|
|
2251
|
-
if (left.kind === "list" && (right.kind === "list" || right.kind === "list-item")) return sameAddress(left.at, right.at);
|
|
2252
|
-
if (right.kind === "list" && left.kind === "list-item") return sameAddress(left.at, right.at);
|
|
2253
|
-
if (left.kind === "list-item" && right.kind === "list-item") return sameAddress(left.at, right.at) && left.key === right.key;
|
|
2254
|
-
if (left.kind === "tree" && (right.kind === "tree" || right.kind === "tree-node")) return sameAddress(left.at, right.at);
|
|
2255
|
-
if (right.kind === "tree" && left.kind === "tree-node") return sameAddress(left.at, right.at);
|
|
2256
|
-
if (left.kind === "tree-node" && right.kind === "tree-node") return sameAddress(left.at, right.at) && left.id === right.id;
|
|
2257
|
-
return false;
|
|
2258
|
-
};
|
|
2259
|
-
const footprintsOverlap = (left, right) => left.some((leftTarget) => right.some((rightTarget) => targetsOverlap(leftTarget, rightTarget)));
|
|
2260
|
-
const decodedTarget = (value) => {
|
|
2261
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
2262
|
-
const record = value;
|
|
2263
|
-
const at = address(record.at);
|
|
2264
|
-
if (!at || typeof record.kind !== "string") return void 0;
|
|
2265
|
-
switch (record.kind) {
|
|
2266
|
-
case "value":
|
|
2267
|
-
case "dictionary":
|
|
2268
|
-
case "collection":
|
|
2269
|
-
case "list":
|
|
2270
|
-
case "tree": return freezeTarget({
|
|
2271
|
-
kind: record.kind,
|
|
2272
|
-
at
|
|
2273
|
-
});
|
|
2274
|
-
case "dictionary-key":
|
|
2275
|
-
case "list-item": return typeof record.key === "string" ? freezeTarget({
|
|
2276
|
-
kind: record.kind,
|
|
2277
|
-
at,
|
|
2278
|
-
key: record.key
|
|
2279
|
-
}) : void 0;
|
|
2280
|
-
case "entity":
|
|
2281
|
-
case "tree-node": return typeof record.id === "string" ? freezeTarget({
|
|
2282
|
-
kind: record.kind,
|
|
2283
|
-
at,
|
|
2284
|
-
id: record.id
|
|
2285
|
-
}) : void 0;
|
|
2286
|
-
default: return;
|
|
2287
|
-
}
|
|
2288
|
-
};
|
|
2289
|
-
const decodeCommandFootprint = (value) => {
|
|
2290
|
-
if (!Array.isArray(value)) return void 0;
|
|
2291
|
-
const targets = /* @__PURE__ */ new Map();
|
|
2292
|
-
for (const entry of value) {
|
|
2293
|
-
const target = decodedTarget(entry);
|
|
2294
|
-
if (!target) return void 0;
|
|
2295
|
-
targets.set(targetKey(target), target);
|
|
2296
|
-
}
|
|
2297
|
-
return Object.freeze(Array.from(targets.values()));
|
|
2298
|
-
};
|
|
2299
|
-
//#endregion
|
|
2300
|
-
//#region core/src/runtime/notification.ts
|
|
2301
|
-
const ROOT_BUCKET = Symbol("document-root");
|
|
2302
|
-
const notifications = /* @__PURE__ */ new WeakMap();
|
|
2303
|
-
const key = (value) => require_dependency.bucket(value) ?? ROOT_BUCKET;
|
|
2304
|
-
const createNotification = (runtime) => {
|
|
2305
|
-
const notification = {
|
|
2306
|
-
root: /* @__PURE__ */ new Set(),
|
|
2307
|
-
filtered: /* @__PURE__ */ new Set(),
|
|
2308
|
-
buckets: /* @__PURE__ */ new Map(),
|
|
2309
|
-
processors: [],
|
|
2310
|
-
candidates: /* @__PURE__ */ new Set(),
|
|
2311
|
-
rootSnapshot: [],
|
|
2312
|
-
notifying: false
|
|
2313
|
-
};
|
|
2314
|
-
notifications.set(runtime, notification);
|
|
2315
|
-
return notification;
|
|
2316
|
-
};
|
|
2317
|
-
const notificationOf = (runtime) => {
|
|
2318
|
-
const value = notifications.get(runtime);
|
|
2319
|
-
if (!value) throw new Error("Unknown Doxum runtime.");
|
|
2320
|
-
return value;
|
|
2321
|
-
};
|
|
2322
|
-
const shareNotification = (source, target) => {
|
|
2323
|
-
notifications.set(target, notificationOf(source));
|
|
2324
|
-
};
|
|
2325
|
-
const registerProcessor = (runtime, processor) => {
|
|
2326
|
-
const notification = notificationOf(runtime);
|
|
2327
|
-
const entry = {
|
|
2328
|
-
processor,
|
|
2329
|
-
active: true
|
|
2330
|
-
};
|
|
2331
|
-
notification.processors.push(entry);
|
|
2332
|
-
return () => {
|
|
2333
|
-
if (!entry.active) return;
|
|
2334
|
-
entry.active = false;
|
|
2335
|
-
if (!notification.notifying) {
|
|
2336
|
-
const index = notification.processors.indexOf(entry);
|
|
2337
|
-
if (index >= 0) notification.processors.splice(index, 1);
|
|
2338
|
-
}
|
|
2339
|
-
};
|
|
2340
|
-
};
|
|
2341
|
-
const subscribeRoot = (notification, listener) => {
|
|
2342
|
-
const entry = {
|
|
2343
|
-
listener,
|
|
2344
|
-
active: true
|
|
2345
|
-
};
|
|
2346
|
-
notification.root.add(entry);
|
|
2347
|
-
return () => {
|
|
2348
|
-
entry.active = false;
|
|
2349
|
-
if (!notification.notifying) notification.root.delete(entry);
|
|
2350
|
-
};
|
|
2351
|
-
};
|
|
2352
|
-
const subscribeTargets = (notification, targets, listener) => {
|
|
2353
|
-
const entry = {
|
|
2354
|
-
targets: Object.freeze(targets.slice()),
|
|
2355
|
-
listener,
|
|
2356
|
-
active: true
|
|
2357
|
-
};
|
|
2358
|
-
notification.filtered.add(entry);
|
|
2359
|
-
const keys = new Set(targets.map(key));
|
|
2360
|
-
keys.forEach((key) => {
|
|
2361
|
-
const bucket = notification.buckets.get(key) ?? /* @__PURE__ */ new Set();
|
|
2362
|
-
bucket.add(entry);
|
|
2363
|
-
notification.buckets.set(key, bucket);
|
|
2364
|
-
});
|
|
2365
|
-
return () => {
|
|
2366
|
-
if (!entry.active) return;
|
|
2367
|
-
entry.active = false;
|
|
2368
|
-
if (notification.notifying) return;
|
|
2369
|
-
notification.filtered.delete(entry);
|
|
2370
|
-
keys.forEach((key) => {
|
|
2371
|
-
const bucket = notification.buckets.get(key);
|
|
2372
|
-
bucket?.delete(entry);
|
|
2373
|
-
if (bucket?.size === 0) notification.buckets.delete(key);
|
|
2374
|
-
});
|
|
2375
|
-
};
|
|
2376
|
-
};
|
|
2377
|
-
const notify = (notification, commit) => {
|
|
2378
|
-
notification.notifying = true;
|
|
2379
|
-
const errors = [];
|
|
2380
|
-
const call = (listener) => {
|
|
2381
|
-
try {
|
|
2382
|
-
listener(commit);
|
|
2383
|
-
} catch (error) {
|
|
2384
|
-
errors.push(Object.freeze({
|
|
2385
|
-
phase: "listener",
|
|
2386
|
-
error
|
|
2387
|
-
}));
|
|
2388
|
-
}
|
|
2389
|
-
};
|
|
2390
|
-
try {
|
|
2391
|
-
const processorCount = notification.processors.length;
|
|
2392
|
-
for (let index = 0; index < processorCount; index += 1) {
|
|
2393
|
-
const entry = notification.processors[index];
|
|
2394
|
-
if (!entry?.active) continue;
|
|
2395
|
-
try {
|
|
2396
|
-
entry.processor.process(commit);
|
|
2397
|
-
} catch (error) {
|
|
2398
|
-
errors.push(Object.freeze({
|
|
2399
|
-
phase: "processor",
|
|
2400
|
-
error
|
|
2401
|
-
}));
|
|
2402
|
-
}
|
|
2403
|
-
}
|
|
2404
|
-
for (let index = 0; index < processorCount; index += 1) {
|
|
2405
|
-
const entry = notification.processors[index];
|
|
2406
|
-
if (!entry?.active) continue;
|
|
2407
|
-
try {
|
|
2408
|
-
entry.processor.flush();
|
|
2409
|
-
} catch (error) {
|
|
2410
|
-
errors.push(Object.freeze({
|
|
2411
|
-
phase: "flush",
|
|
2412
|
-
error
|
|
2413
|
-
}));
|
|
2414
|
-
}
|
|
2415
|
-
}
|
|
2416
|
-
const candidates = notification.candidates;
|
|
2417
|
-
candidates.clear();
|
|
2418
|
-
if (commit.impact.kind === "reset") notification.filtered.forEach((entry) => candidates.add(entry));
|
|
2419
|
-
else for (const operation of commit.operations) {
|
|
2420
|
-
const key = operation.at[0] ?? ROOT_BUCKET;
|
|
2421
|
-
notification.buckets.get(key)?.forEach((entry) => candidates.add(entry));
|
|
2422
|
-
notification.buckets.get(ROOT_BUCKET)?.forEach((entry) => candidates.add(entry));
|
|
2423
|
-
}
|
|
2424
|
-
candidates.forEach((entry) => {
|
|
2425
|
-
if (entry.active && entry.targets.some(commit.impact.affects)) call(entry.listener);
|
|
2426
|
-
});
|
|
2427
|
-
const rootSnapshot = notification.rootSnapshot;
|
|
2428
|
-
rootSnapshot.length = 0;
|
|
2429
|
-
notification.root.forEach((entry) => rootSnapshot.push(entry));
|
|
2430
|
-
for (const entry of rootSnapshot) if (entry.active) call(entry.listener);
|
|
2431
|
-
} finally {
|
|
2432
|
-
notification.notifying = false;
|
|
2433
|
-
let writeIndex = 0;
|
|
2434
|
-
for (const entry of notification.processors) if (entry.active) notification.processors[writeIndex++] = entry;
|
|
2435
|
-
notification.processors.length = writeIndex;
|
|
2436
|
-
notification.root.forEach((entry) => {
|
|
2437
|
-
if (!entry.active) notification.root.delete(entry);
|
|
2438
|
-
});
|
|
2439
|
-
notification.filtered.forEach((entry) => {
|
|
2440
|
-
if (!entry.active) notification.filtered.delete(entry);
|
|
2441
|
-
});
|
|
2442
|
-
notification.buckets.forEach((bucket, key) => {
|
|
2443
|
-
bucket.forEach((entry) => {
|
|
2444
|
-
if (!entry.active) bucket.delete(entry);
|
|
2445
|
-
});
|
|
2446
|
-
if (bucket.size === 0) notification.buckets.delete(key);
|
|
2447
|
-
});
|
|
2448
|
-
}
|
|
2449
|
-
return Object.freeze(errors);
|
|
2450
|
-
};
|
|
2451
|
-
const disposeNotification = (notification) => {
|
|
2452
|
-
notification.root.clear();
|
|
2453
|
-
notification.filtered.clear();
|
|
2454
|
-
notification.buckets.clear();
|
|
2455
|
-
notification.processors.length = 0;
|
|
2456
|
-
notification.candidates.clear();
|
|
2457
|
-
notification.rootSnapshot.length = 0;
|
|
2458
|
-
};
|
|
2459
|
-
//#endregion
|
|
2460
2166
|
//#region core/src/runtime.ts
|
|
2461
2167
|
var RejectedUpdate = class extends Error {
|
|
2462
2168
|
issues;
|
|
@@ -2468,6 +2174,7 @@ var RejectedUpdate = class extends Error {
|
|
|
2468
2174
|
const EMPTY = Object.freeze([]);
|
|
2469
2175
|
const publishDiagnostic = (value) => Object.freeze({
|
|
2470
2176
|
...value,
|
|
2177
|
+
source: "application",
|
|
2471
2178
|
...value.address === void 0 ? {} : { address: Object.freeze(value.address.slice()) }
|
|
2472
2179
|
});
|
|
2473
2180
|
const createDocument = (input) => {
|
|
@@ -2484,15 +2191,16 @@ const createDocument = (input) => {
|
|
|
2484
2191
|
let runtime;
|
|
2485
2192
|
let notification;
|
|
2486
2193
|
const assertWritable = (intent) => {
|
|
2487
|
-
if (state.disposed) throw new
|
|
2488
|
-
if (busy) throw new
|
|
2194
|
+
if (state.disposed) throw new require_runtime.DocumentDisposedError();
|
|
2195
|
+
if (busy) throw new require_runtime.DocumentReentrancyError();
|
|
2196
|
+
if (require_runtime.accessOf(runtime).projectionLocks) throw new require_runtime.DocumentReentrancyError();
|
|
2489
2197
|
require_driver.assertRuntimeWritable(runtime, intent);
|
|
2490
2198
|
};
|
|
2491
2199
|
const runTransaction = (session, run) => {
|
|
2492
2200
|
let reports;
|
|
2493
2201
|
let active = true;
|
|
2494
2202
|
const transaction = {
|
|
2495
|
-
read:
|
|
2203
|
+
read: require_runtime.documentReader(input.schema, () => state.document, () => active),
|
|
2496
2204
|
write: documentWriter(input.schema, (operation) => {
|
|
2497
2205
|
if (!active) throw new Error("Document writer is no longer active.");
|
|
2498
2206
|
const rejected = session.apply(operation);
|
|
@@ -2527,7 +2235,19 @@ const createDocument = (input) => {
|
|
|
2527
2235
|
const history = createHistory({
|
|
2528
2236
|
capacity: input.history === false ? 0 : Math.max(0, input.history?.capacity ?? 100),
|
|
2529
2237
|
revision: () => revision,
|
|
2530
|
-
apply: (operations) => applyBatch(operations, "history", false)
|
|
2238
|
+
apply: (operations) => applyBatch(operations, "history", false),
|
|
2239
|
+
assertIdle: () => {
|
|
2240
|
+
if (state.disposed) throw new require_runtime.DocumentDisposedError();
|
|
2241
|
+
if (busy || require_runtime.accessOf(runtime).projectionLocks) throw new require_runtime.DocumentReentrancyError();
|
|
2242
|
+
},
|
|
2243
|
+
notify: (run) => {
|
|
2244
|
+
busy = true;
|
|
2245
|
+
try {
|
|
2246
|
+
return run();
|
|
2247
|
+
} finally {
|
|
2248
|
+
busy = false;
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2531
2251
|
});
|
|
2532
2252
|
const publish = (batch, source, kind, recordHistory) => {
|
|
2533
2253
|
revision += 1;
|
|
@@ -2541,10 +2261,12 @@ const createDocument = (input) => {
|
|
|
2541
2261
|
});
|
|
2542
2262
|
if (kind === "replace" || source === "remote") history.invalidate();
|
|
2543
2263
|
else if (recordHistory && (source === "local" || source === "system")) history.record(batch.operations, batch.inverse);
|
|
2264
|
+
else if (source === "history") history.publish();
|
|
2265
|
+
else history.endGroup();
|
|
2544
2266
|
busy = true;
|
|
2545
2267
|
let observerErrors;
|
|
2546
2268
|
try {
|
|
2547
|
-
observerErrors = notify(notification, commit);
|
|
2269
|
+
observerErrors = require_runtime.notify(notification, commit, history.flush);
|
|
2548
2270
|
} finally {
|
|
2549
2271
|
busy = false;
|
|
2550
2272
|
}
|
|
@@ -2574,11 +2296,11 @@ const createDocument = (input) => {
|
|
|
2574
2296
|
runtime = {
|
|
2575
2297
|
schema: input.schema,
|
|
2576
2298
|
address: {
|
|
2577
|
-
resolve: (address) =>
|
|
2578
|
-
read: (address) =>
|
|
2579
|
-
contains:
|
|
2580
|
-
overlaps:
|
|
2581
|
-
debugKey:
|
|
2299
|
+
resolve: (address) => require_runtime.resolveAddress(input.schema, address, state.document),
|
|
2300
|
+
read: (address) => require_runtime.read(state.document, address),
|
|
2301
|
+
contains: require_runtime.contains,
|
|
2302
|
+
overlaps: require_runtime.overlaps,
|
|
2303
|
+
debugKey: require_runtime.debugKey
|
|
2582
2304
|
},
|
|
2583
2305
|
revision: () => revision,
|
|
2584
2306
|
update: (run, options) => {
|
|
@@ -2659,7 +2381,7 @@ const createDocument = (input) => {
|
|
|
2659
2381
|
operations: batch.operations,
|
|
2660
2382
|
inverse: batch.inverse,
|
|
2661
2383
|
impact,
|
|
2662
|
-
footprint: commandFootprint(batch.operations),
|
|
2384
|
+
footprint: require_runtime.commandFootprint(batch.operations),
|
|
2663
2385
|
reports
|
|
2664
2386
|
};
|
|
2665
2387
|
} catch (error) {
|
|
@@ -2687,7 +2409,7 @@ const createDocument = (input) => {
|
|
|
2687
2409
|
const invalidTree = invalidDocument(input.schema, document);
|
|
2688
2410
|
if (invalidTree) return {
|
|
2689
2411
|
status: "rejected",
|
|
2690
|
-
issues: [at
|
|
2412
|
+
issues: [at(invalidTree, "invalid-tree", "Document replacement contains an invalid tree.")],
|
|
2691
2413
|
revision
|
|
2692
2414
|
};
|
|
2693
2415
|
if (require_ownership.deepEqual(state.document, document)) return {
|
|
@@ -2704,28 +2426,33 @@ const createDocument = (input) => {
|
|
|
2704
2426
|
}, source, "replace", false);
|
|
2705
2427
|
},
|
|
2706
2428
|
snapshot: () => {
|
|
2707
|
-
if (state.disposed) throw new
|
|
2429
|
+
if (state.disposed) throw new require_runtime.DocumentDisposedError();
|
|
2708
2430
|
return require_ownership.cloneValue(state.document, "snapshot");
|
|
2709
2431
|
},
|
|
2710
2432
|
subscribe: ((targetOrListener, listener) => {
|
|
2711
|
-
if (state.disposed) throw new
|
|
2712
|
-
if (typeof targetOrListener === "function") return subscribeRoot(notification, targetOrListener);
|
|
2433
|
+
if (state.disposed) throw new require_runtime.DocumentDisposedError();
|
|
2434
|
+
if (typeof targetOrListener === "function") return require_runtime.subscribeRoot(notification, targetOrListener);
|
|
2713
2435
|
const targets = Array.isArray(targetOrListener) ? targetOrListener : [targetOrListener];
|
|
2714
2436
|
if (targets.length === 0 || !listener) throw new TypeError("Filtered subscribe requires at least one target and a listener.");
|
|
2715
|
-
return subscribeTargets(notification, targets, listener);
|
|
2437
|
+
return require_runtime.subscribeTargets(notification, targets, listener);
|
|
2716
2438
|
}),
|
|
2717
2439
|
history: history.api,
|
|
2718
2440
|
dispose: () => {
|
|
2719
2441
|
if (state.disposed) return;
|
|
2442
|
+
if (busy || require_runtime.accessOf(runtime).projectionLocks) throw new require_runtime.DocumentReentrancyError();
|
|
2720
2443
|
state.disposed = true;
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2444
|
+
try {
|
|
2445
|
+
require_runtime.disposeNotification(notification);
|
|
2446
|
+
} finally {
|
|
2447
|
+
history.dispose();
|
|
2448
|
+
require_driver.disposeRuntimeDriver(runtime);
|
|
2449
|
+
}
|
|
2724
2450
|
}
|
|
2725
2451
|
};
|
|
2726
|
-
|
|
2452
|
+
require_runtime.bindRuntimeAccess(runtime, state);
|
|
2727
2453
|
require_driver.bindRuntimeDriver(runtime);
|
|
2728
|
-
notification = createNotification(runtime);
|
|
2454
|
+
notification = require_runtime.createNotification(runtime);
|
|
2455
|
+
require_runtime.bindDocumentReadable(history.api, runtime);
|
|
2729
2456
|
return runtime;
|
|
2730
2457
|
};
|
|
2731
2458
|
//#endregion
|
|
@@ -2736,427 +2463,37 @@ const asReadable = (runtime) => {
|
|
|
2736
2463
|
revision: runtime.revision,
|
|
2737
2464
|
subscribe: runtime.subscribe
|
|
2738
2465
|
};
|
|
2739
|
-
|
|
2740
|
-
shareNotification(runtime, readable);
|
|
2466
|
+
require_runtime.bindRuntimeAccess(readable, require_runtime.accessOf(runtime));
|
|
2467
|
+
require_runtime.shareNotification(runtime, readable);
|
|
2741
2468
|
return Object.freeze(readable);
|
|
2742
2469
|
};
|
|
2743
2470
|
//#endregion
|
|
2744
2471
|
//#region core/src/projection/select.ts
|
|
2745
|
-
const select = (runtime, selector) =>
|
|
2746
|
-
//#endregion
|
|
2747
|
-
//#region core/src/projection/collection-view.ts
|
|
2748
|
-
const createCollectionView = (input) => {
|
|
2749
|
-
if (require_dependency.schemaOf(input.runtime) !== input.source.schema) throw new Error("Collection selector belongs to another schema.");
|
|
2750
|
-
const idsListeners = /* @__PURE__ */ new Set();
|
|
2751
|
-
const allListeners = /* @__PURE__ */ new Set();
|
|
2752
|
-
const itemListeners = /* @__PURE__ */ new Map();
|
|
2753
|
-
const itemReadables = /* @__PURE__ */ new Map();
|
|
2754
|
-
let disposed = false;
|
|
2755
|
-
const sourceNode = require_dependency.nodeAt(input.source.schema, input.source.address);
|
|
2756
|
-
const entryNode = sourceNode?.kind === "table" || sourceNode?.kind === "map" ? sourceNode.value : {
|
|
2757
|
-
kind: "object",
|
|
2758
|
-
shape: {}
|
|
2759
|
-
};
|
|
2760
|
-
const mapEntry = (document, id) => {
|
|
2761
|
-
require_ownership.profile.collectionView.mapped();
|
|
2762
|
-
const address = [...input.source.address, String(id)];
|
|
2763
|
-
let active = true;
|
|
2764
|
-
try {
|
|
2765
|
-
return input.map(id, require_dependency.readerFor(entryNode, {
|
|
2766
|
-
root: () => document,
|
|
2767
|
-
active: () => active
|
|
2768
|
-
}, address));
|
|
2769
|
-
} finally {
|
|
2770
|
-
active = false;
|
|
2771
|
-
}
|
|
2772
|
-
};
|
|
2773
|
-
const build = (previous, changed) => {
|
|
2774
|
-
const document = require_dependency.documentOf(input.runtime);
|
|
2775
|
-
const collection = require_dependency.read(document, input.source.address);
|
|
2776
|
-
const ids = collection && typeof collection === "object" && "ids" in collection && Array.isArray(collection.ids) ? [...collection.ids] : Object.keys(collection ?? {});
|
|
2777
|
-
require_ownership.profile.collectionView.idsScanned(ids.length);
|
|
2778
|
-
const values = previous && changed ? previous.values : /* @__PURE__ */ new Map();
|
|
2779
|
-
if (previous && changed) {
|
|
2780
|
-
const nextIds = new Set(ids);
|
|
2781
|
-
for (const id of previous.ids) if (!nextIds.has(id)) values.delete(id);
|
|
2782
|
-
}
|
|
2783
|
-
for (const id of ids) {
|
|
2784
|
-
if (previous && changed && previous.values.has(id) && !changed.has(id)) continue;
|
|
2785
|
-
const next = mapEntry(document, id);
|
|
2786
|
-
if (previous && changed && previous.values.has(id)) {
|
|
2787
|
-
const before = previous.values.get(id);
|
|
2788
|
-
if (input.isEqual ? input.isEqual(before, next) : Object.is(before, next)) {
|
|
2789
|
-
changed.delete(id);
|
|
2790
|
-
continue;
|
|
2791
|
-
}
|
|
2792
|
-
}
|
|
2793
|
-
values.set(id, next);
|
|
2794
|
-
}
|
|
2795
|
-
return {
|
|
2796
|
-
ids: Object.freeze(ids),
|
|
2797
|
-
values,
|
|
2798
|
-
all: void 0,
|
|
2799
|
-
allDirty: true
|
|
2800
|
-
};
|
|
2801
|
-
};
|
|
2802
|
-
let state = build();
|
|
2803
|
-
const ensureAll = () => {
|
|
2804
|
-
if (!state.allDirty && state.all) return state.all;
|
|
2805
|
-
require_ownership.profile.collectionView.arrayCopied();
|
|
2806
|
-
const all = new Array(state.ids.length);
|
|
2807
|
-
for (let index = 0; index < state.ids.length; index += 1) all[index] = state.values.get(state.ids[index]);
|
|
2808
|
-
const stable = Object.freeze(all);
|
|
2809
|
-
state.all = stable;
|
|
2810
|
-
state.allDirty = false;
|
|
2811
|
-
return stable;
|
|
2812
|
-
};
|
|
2813
|
-
const emit = (listeners) => {
|
|
2814
|
-
Array.from(listeners).forEach((listener) => listener());
|
|
2815
|
-
};
|
|
2816
|
-
const unsubscribe = input.runtime.subscribe(input.source, (commit) => {
|
|
2817
|
-
if (disposed) return;
|
|
2818
|
-
const impact = commit.impact.collection(input.source);
|
|
2819
|
-
if (impact.kind === "incremental" && impact.added.size === 0 && impact.removed.size === 0 && !impact.orderChanged) {
|
|
2820
|
-
const previous = state;
|
|
2821
|
-
const changes = [];
|
|
2822
|
-
const document = require_dependency.documentOf(input.runtime);
|
|
2823
|
-
impact.updated.forEach((id) => {
|
|
2824
|
-
if (!previous.values.has(id)) return;
|
|
2825
|
-
const before = previous.values.get(id);
|
|
2826
|
-
const after = mapEntry(document, id);
|
|
2827
|
-
if (input.isEqual ? input.isEqual(before, after) : Object.is(before, after)) return;
|
|
2828
|
-
changes.push([id, after]);
|
|
2829
|
-
});
|
|
2830
|
-
if (changes.length === 0) return;
|
|
2831
|
-
for (const [id, value] of changes) previous.values.set(id, value);
|
|
2832
|
-
previous.all = void 0;
|
|
2833
|
-
previous.allDirty = true;
|
|
2834
|
-
emit(allListeners);
|
|
2835
|
-
for (const [id] of changes) {
|
|
2836
|
-
const listeners = itemListeners.get(id);
|
|
2837
|
-
if (listeners) emit(listeners);
|
|
2838
|
-
}
|
|
2839
|
-
return;
|
|
2840
|
-
}
|
|
2841
|
-
const changed = impact.kind === "reset" ? void 0 : new Set([...impact.added, ...impact.updated]);
|
|
2842
|
-
const previous = state;
|
|
2843
|
-
const next = build(previous, changed);
|
|
2844
|
-
const changedIds = /* @__PURE__ */ new Set();
|
|
2845
|
-
if (changed) {
|
|
2846
|
-
changed.forEach((id) => changedIds.add(id));
|
|
2847
|
-
previous.ids.forEach((id) => {
|
|
2848
|
-
if (!next.values.has(id)) changedIds.add(id);
|
|
2849
|
-
});
|
|
2850
|
-
next.ids.forEach((id) => {
|
|
2851
|
-
if (!previous.values.has(id)) changedIds.add(id);
|
|
2852
|
-
});
|
|
2853
|
-
} else {
|
|
2854
|
-
previous.ids.forEach((id) => {
|
|
2855
|
-
if (!next.values.has(id)) changedIds.add(id);
|
|
2856
|
-
else if (!(input.isEqual ? input.isEqual(previous.values.get(id), next.values.get(id)) : Object.is(previous.values.get(id), next.values.get(id)))) changedIds.add(id);
|
|
2857
|
-
});
|
|
2858
|
-
next.ids.forEach((id) => {
|
|
2859
|
-
if (!previous.values.has(id)) changedIds.add(id);
|
|
2860
|
-
});
|
|
2861
|
-
}
|
|
2862
|
-
const idsChanged = impact.kind === "incremental" ? impact.added.size > 0 || impact.removed.size > 0 || impact.orderChanged : previous.ids.length !== next.ids.length || previous.ids.some((id, index) => next.ids[index] !== id);
|
|
2863
|
-
state = idsChanged || changedIds.size ? next : previous;
|
|
2864
|
-
if (idsChanged) emit(idsListeners);
|
|
2865
|
-
if (idsChanged || changedIds.size) emit(allListeners);
|
|
2866
|
-
changedIds.forEach((id) => {
|
|
2867
|
-
const listeners = itemListeners.get(id);
|
|
2868
|
-
if (listeners) emit(listeners);
|
|
2869
|
-
});
|
|
2870
|
-
});
|
|
2871
|
-
return {
|
|
2872
|
-
ids: {
|
|
2873
|
-
current: () => state.ids,
|
|
2874
|
-
revision: () => input.runtime.revision(),
|
|
2875
|
-
subscribe: (listener) => {
|
|
2876
|
-
if (disposed) return () => void 0;
|
|
2877
|
-
idsListeners.add(listener);
|
|
2878
|
-
return () => idsListeners.delete(listener);
|
|
2879
|
-
}
|
|
2880
|
-
},
|
|
2881
|
-
all: {
|
|
2882
|
-
current: ensureAll,
|
|
2883
|
-
revision: () => input.runtime.revision(),
|
|
2884
|
-
subscribe: (listener) => {
|
|
2885
|
-
if (disposed) return () => void 0;
|
|
2886
|
-
allListeners.add(listener);
|
|
2887
|
-
return () => allListeners.delete(listener);
|
|
2888
|
-
}
|
|
2889
|
-
},
|
|
2890
|
-
item: (id) => {
|
|
2891
|
-
const cached = itemReadables.get(id);
|
|
2892
|
-
if (cached) return cached;
|
|
2893
|
-
const readable = {
|
|
2894
|
-
current: () => state.values.get(id),
|
|
2895
|
-
revision: () => input.runtime.revision(),
|
|
2896
|
-
subscribe: (listener) => {
|
|
2897
|
-
if (disposed) return () => void 0;
|
|
2898
|
-
const listeners = itemListeners.get(id) ?? /* @__PURE__ */ new Set();
|
|
2899
|
-
itemListeners.set(id, listeners);
|
|
2900
|
-
listeners.add(listener);
|
|
2901
|
-
return () => {
|
|
2902
|
-
listeners.delete(listener);
|
|
2903
|
-
if (listeners.size === 0) itemListeners.delete(id);
|
|
2904
|
-
};
|
|
2905
|
-
}
|
|
2906
|
-
};
|
|
2907
|
-
itemReadables.set(id, readable);
|
|
2908
|
-
return readable;
|
|
2909
|
-
},
|
|
2910
|
-
revision: () => input.runtime.revision(),
|
|
2911
|
-
dispose: () => {
|
|
2912
|
-
if (disposed) return;
|
|
2913
|
-
disposed = true;
|
|
2914
|
-
unsubscribe();
|
|
2915
|
-
idsListeners.clear();
|
|
2916
|
-
allListeners.clear();
|
|
2917
|
-
itemListeners.clear();
|
|
2918
|
-
itemReadables.clear();
|
|
2919
|
-
state.values.clear();
|
|
2920
|
-
state = {
|
|
2921
|
-
ids: Object.freeze([]),
|
|
2922
|
-
values: /* @__PURE__ */ new Map(),
|
|
2923
|
-
all: Object.freeze([]),
|
|
2924
|
-
allDirty: false
|
|
2925
|
-
};
|
|
2926
|
-
}
|
|
2927
|
-
};
|
|
2928
|
-
};
|
|
2929
|
-
//#endregion
|
|
2930
|
-
//#region core/src/projection/materialized-view.ts
|
|
2931
|
-
const materializedMeta = /* @__PURE__ */ new WeakMap();
|
|
2932
|
-
const createMaterializedView = (runtime, spec) => {
|
|
2933
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
2934
|
-
let disposed = false;
|
|
2935
|
-
let fault;
|
|
2936
|
-
let revision = runtime.revision();
|
|
2937
|
-
let instance;
|
|
2938
|
-
let currentValue;
|
|
2939
|
-
let pendingEmit = false;
|
|
2940
|
-
const dependencies = require_dependency.createDependencyTracker();
|
|
2941
|
-
const sources = spec.sources ?? {};
|
|
2942
|
-
const sourceEntries = Object.keys(sources).map((key) => [key, sources[key]]);
|
|
2943
|
-
sourceEntries.forEach(([, source]) => {
|
|
2944
|
-
const meta = materializedMeta.get(source);
|
|
2945
|
-
if (!meta || meta.runtime !== runtime) throw new Error("Materialized sources must belong to the same runtime and be created first.");
|
|
2946
|
-
});
|
|
2947
|
-
const sourceValuesRecord = {};
|
|
2948
|
-
let sourceChanged = false;
|
|
2949
|
-
for (const [key] of sourceEntries) sourceValuesRecord[key] = {
|
|
2950
|
-
value: void 0,
|
|
2951
|
-
change: void 0
|
|
2952
|
-
};
|
|
2953
|
-
const sourceValues = (commitRevision) => {
|
|
2954
|
-
sourceChanged = false;
|
|
2955
|
-
for (const [key, source] of sourceEntries) {
|
|
2956
|
-
const meta = materializedMeta.get(source);
|
|
2957
|
-
const entry = sourceValuesRecord[key];
|
|
2958
|
-
entry.value = meta?.value ?? source.current();
|
|
2959
|
-
entry.change = meta?.change;
|
|
2960
|
-
if (commitRevision !== void 0 && meta?.changedRevision === commitRevision) {
|
|
2961
|
-
sourceChanged = true;
|
|
2962
|
-
require_ownership.profile.materialized.sourceChanged();
|
|
2963
|
-
}
|
|
2964
|
-
}
|
|
2965
|
-
return sourceValuesRecord;
|
|
2966
|
-
};
|
|
2967
|
-
let activeImpact;
|
|
2968
|
-
const assertImpact = () => {
|
|
2969
|
-
if (!activeImpact) throw new Error("Materialized impact is no longer active.");
|
|
2970
|
-
return activeImpact;
|
|
2971
|
-
};
|
|
2972
|
-
const trackedImpact = {
|
|
2973
|
-
get kind() {
|
|
2974
|
-
return assertImpact().kind;
|
|
2975
|
-
},
|
|
2976
|
-
affects: (target) => {
|
|
2977
|
-
dependencies.record(target);
|
|
2978
|
-
return assertImpact().affects(target);
|
|
2979
|
-
},
|
|
2980
|
-
collection: (selector) => {
|
|
2981
|
-
dependencies.record(selector);
|
|
2982
|
-
return assertImpact().collection(selector);
|
|
2983
|
-
},
|
|
2984
|
-
get operations() {
|
|
2985
|
-
dependencies.record({
|
|
2986
|
-
kind: "value",
|
|
2987
|
-
at: []
|
|
2988
|
-
});
|
|
2989
|
-
return assertImpact().operations;
|
|
2990
|
-
}
|
|
2991
|
-
};
|
|
2992
|
-
let view;
|
|
2993
|
-
const writeMeta = (change, value, nextRevision, changed) => {
|
|
2994
|
-
const meta = materializedMeta.get(view);
|
|
2995
|
-
if (meta) {
|
|
2996
|
-
meta.value = value;
|
|
2997
|
-
meta.change = change;
|
|
2998
|
-
meta.revision = nextRevision;
|
|
2999
|
-
if (changed) meta.changedRevision = nextRevision;
|
|
3000
|
-
} else materializedMeta.set(view, {
|
|
3001
|
-
runtime,
|
|
3002
|
-
value,
|
|
3003
|
-
change,
|
|
3004
|
-
revision: nextRevision,
|
|
3005
|
-
changedRevision: changed ? nextRevision : -1
|
|
3006
|
-
});
|
|
3007
|
-
};
|
|
3008
|
-
const build = () => {
|
|
3009
|
-
require_ownership.profile.materialized.rebuilt();
|
|
3010
|
-
dependencies.clear();
|
|
3011
|
-
let active = true;
|
|
3012
|
-
try {
|
|
3013
|
-
instance = spec.build({
|
|
3014
|
-
read: require_dependency.documentReader(require_dependency.schemaOf(runtime), () => require_dependency.documentOf(runtime), () => active),
|
|
3015
|
-
sources: sourceValues()
|
|
3016
|
-
});
|
|
3017
|
-
currentValue = instance.value;
|
|
3018
|
-
fault = void 0;
|
|
3019
|
-
revision = runtime.revision();
|
|
3020
|
-
} finally {
|
|
3021
|
-
active = false;
|
|
3022
|
-
}
|
|
3023
|
-
};
|
|
3024
|
-
build();
|
|
3025
|
-
const emit = () => {
|
|
3026
|
-
require_ownership.profile.materialized.notification();
|
|
3027
|
-
Array.from(listeners).forEach((listener) => listener());
|
|
3028
|
-
};
|
|
3029
|
-
const process = (commit) => {
|
|
3030
|
-
if (disposed) return;
|
|
3031
|
-
try {
|
|
3032
|
-
if (commit.kind === "replace" || fault) {
|
|
3033
|
-
build();
|
|
3034
|
-
writeMeta(void 0, currentValue, commit.revision, true);
|
|
3035
|
-
pendingEmit = true;
|
|
3036
|
-
return;
|
|
3037
|
-
}
|
|
3038
|
-
const sourceSnapshot = sourceValues(commit.revision);
|
|
3039
|
-
if (!sourceChanged && dependencies.size() > 0 && !dependencies.some(commit.impact.affects)) {
|
|
3040
|
-
require_ownership.profile.materialized.skipped();
|
|
3041
|
-
revision = commit.revision;
|
|
3042
|
-
writeMeta(void 0, currentValue, commit.revision, false);
|
|
3043
|
-
return;
|
|
3044
|
-
}
|
|
3045
|
-
dependencies.clear();
|
|
3046
|
-
require_ownership.profile.materialized.updated();
|
|
3047
|
-
let active = true;
|
|
3048
|
-
let result;
|
|
3049
|
-
try {
|
|
3050
|
-
activeImpact = commit.impact;
|
|
3051
|
-
result = instance.update({
|
|
3052
|
-
read: require_dependency.documentReader(require_dependency.schemaOf(runtime), () => require_dependency.documentOf(runtime), () => active),
|
|
3053
|
-
revision: commit.revision,
|
|
3054
|
-
source: commit.source,
|
|
3055
|
-
impact: trackedImpact,
|
|
3056
|
-
sources: sourceSnapshot
|
|
3057
|
-
});
|
|
3058
|
-
} finally {
|
|
3059
|
-
activeImpact = void 0;
|
|
3060
|
-
active = false;
|
|
3061
|
-
}
|
|
3062
|
-
if (result.kind === "rebuild") {
|
|
3063
|
-
build();
|
|
3064
|
-
writeMeta(void 0, currentValue, commit.revision, true);
|
|
3065
|
-
pendingEmit = true;
|
|
3066
|
-
} else if (result.kind === "changed") {
|
|
3067
|
-
currentValue = result.value;
|
|
3068
|
-
revision = commit.revision;
|
|
3069
|
-
writeMeta(result.change, currentValue, commit.revision, true);
|
|
3070
|
-
pendingEmit = true;
|
|
3071
|
-
} else {
|
|
3072
|
-
revision = commit.revision;
|
|
3073
|
-
writeMeta(void 0, currentValue, commit.revision, false);
|
|
3074
|
-
}
|
|
3075
|
-
} catch (error) {
|
|
3076
|
-
try {
|
|
3077
|
-
build();
|
|
3078
|
-
writeMeta(void 0, currentValue, commit.revision, true);
|
|
3079
|
-
pendingEmit = true;
|
|
3080
|
-
} catch (rebuildError) {
|
|
3081
|
-
fault = rebuildError;
|
|
3082
|
-
throw rebuildError;
|
|
3083
|
-
}
|
|
3084
|
-
throw error;
|
|
3085
|
-
}
|
|
3086
|
-
};
|
|
3087
|
-
view = {
|
|
3088
|
-
current: () => {
|
|
3089
|
-
if (fault) throw fault;
|
|
3090
|
-
return currentValue;
|
|
3091
|
-
},
|
|
3092
|
-
revision: () => revision,
|
|
3093
|
-
subscribe: (listener) => {
|
|
3094
|
-
listeners.add(listener);
|
|
3095
|
-
return () => listeners.delete(listener);
|
|
3096
|
-
},
|
|
3097
|
-
rebuild: () => {
|
|
3098
|
-
build();
|
|
3099
|
-
writeMeta(void 0, currentValue, runtime.revision(), true);
|
|
3100
|
-
emit();
|
|
3101
|
-
},
|
|
3102
|
-
dispose: () => {
|
|
3103
|
-
if (disposed) return;
|
|
3104
|
-
disposed = true;
|
|
3105
|
-
unregister();
|
|
3106
|
-
listeners.clear();
|
|
3107
|
-
materializedMeta.delete(view);
|
|
3108
|
-
}
|
|
3109
|
-
};
|
|
3110
|
-
materializedMeta.set(view, {
|
|
3111
|
-
runtime,
|
|
3112
|
-
value: currentValue,
|
|
3113
|
-
change: void 0,
|
|
3114
|
-
revision,
|
|
3115
|
-
changedRevision: -1
|
|
3116
|
-
});
|
|
3117
|
-
const unregister = registerProcessor(runtime, {
|
|
3118
|
-
process,
|
|
3119
|
-
flush: () => {
|
|
3120
|
-
if (!pendingEmit) return;
|
|
3121
|
-
pendingEmit = false;
|
|
3122
|
-
emit();
|
|
3123
|
-
}
|
|
3124
|
-
});
|
|
3125
|
-
return view;
|
|
3126
|
-
};
|
|
2472
|
+
const select = (runtime, selector) => require_runtime.readWith(runtime, selector);
|
|
3127
2473
|
//#endregion
|
|
3128
|
-
exports.DocumentDisposedError =
|
|
3129
|
-
exports.DocumentReentrancyError =
|
|
2474
|
+
exports.DocumentDisposedError = require_runtime.DocumentDisposedError;
|
|
2475
|
+
exports.DocumentReentrancyError = require_runtime.DocumentReentrancyError;
|
|
2476
|
+
exports.ProjectionDisposedError = require_runtime.ProjectionDisposedError;
|
|
2477
|
+
exports.ProjectionError = require_runtime.ProjectionError;
|
|
3130
2478
|
exports.asReadable = asReadable;
|
|
3131
|
-
exports.commandFootprint = commandFootprint;
|
|
3132
|
-
exports.contains = require_dependency.contains;
|
|
3133
|
-
exports.createCollectionView = createCollectionView;
|
|
3134
2479
|
exports.createDocument = createDocument;
|
|
3135
|
-
exports.
|
|
3136
|
-
exports.
|
|
3137
|
-
exports.
|
|
3138
|
-
exports.
|
|
3139
|
-
exports.
|
|
3140
|
-
exports.
|
|
3141
|
-
exports.
|
|
3142
|
-
exports.
|
|
3143
|
-
exports.object = require_dependency.object;
|
|
3144
|
-
exports.optional = require_dependency.optional;
|
|
3145
|
-
exports.overlaps = require_dependency.overlaps;
|
|
3146
|
-
exports.readAddress = require_dependency.read;
|
|
3147
|
-
exports.record = require_dependency.record;
|
|
3148
|
-
exports.resolveAddress = require_dependency.resolveAddress;
|
|
3149
|
-
exports.schema = require_dependency.schema;
|
|
2480
|
+
exports.createProjectionRuntime = require_runtime.createProjectionRuntime;
|
|
2481
|
+
exports.dict = require_runtime.dict;
|
|
2482
|
+
exports.field = require_runtime.field;
|
|
2483
|
+
exports.list = require_runtime.list;
|
|
2484
|
+
exports.map = require_runtime.map;
|
|
2485
|
+
exports.object = require_runtime.object;
|
|
2486
|
+
exports.optional = require_runtime.optional;
|
|
2487
|
+
exports.schema = require_runtime.schema;
|
|
3150
2488
|
exports.select = select;
|
|
3151
|
-
exports.
|
|
3152
|
-
exports.table = require_dependency.table;
|
|
2489
|
+
exports.table = require_runtime.table;
|
|
3153
2490
|
Object.defineProperty(exports, "target", {
|
|
3154
2491
|
enumerable: true,
|
|
3155
2492
|
get: function() {
|
|
3156
|
-
return
|
|
2493
|
+
return require_runtime.impact_target_exports;
|
|
3157
2494
|
}
|
|
3158
2495
|
});
|
|
3159
|
-
exports.tree =
|
|
3160
|
-
exports.variant =
|
|
2496
|
+
exports.tree = require_runtime.tree;
|
|
2497
|
+
exports.variant = require_runtime.variant;
|
|
3161
2498
|
|
|
3162
2499
|
//# sourceMappingURL=index.cjs.map
|