@markless/runtime 0.3.2 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,441 @@
1
+ import { a as readAsyncComputedNode, c as findLastSharedReturnProperty, d as writePath, i as invalidateAsyncComputed, l as pathsIntersect, n as createRuntimeAsyncComputedNodes, o as deletePath, r as demandAsyncComputed, s as dirtyPathForGraphWrite, u as readPath } from "./graph-async-Db6SqB5x.js";
2
+ //#region src/graph-collections.ts
3
+ function applyCollectionCall(target, method, args) {
4
+ if (!isSupportedCollectionTarget(target)) throw new TypeError(`Cannot call collection method "${method}" because the graph path is not an Array, Map, Set, or Date.`);
5
+ if (!isSupportedCollectionMethod(method)) throw new TypeError(`Unsupported graph collection method "${method}".`);
6
+ const callable = target[method];
7
+ if (typeof callable !== "function") throw new TypeError(`Unsupported graph collection method "${method}".`);
8
+ return Reflect.apply(callable, target, [...args]);
9
+ }
10
+ function collectionCallMutated(method, result, beforeMutation) {
11
+ if (method === "delete") return result === true;
12
+ if (method === "clear") return beforeMutation?.type === "size" && beforeMutation.value > 0;
13
+ if (method === "pop") return beforeMutation?.type === "size" && beforeMutation.value > 0;
14
+ if (method === "shift") return beforeMutation?.type === "size" && beforeMutation.value > 0;
15
+ if (method === "push" || method === "unshift") return beforeMutation?.type !== "size" || result !== beforeMutation.value;
16
+ if (arrayContentMutationMethod(method)) return beforeMutation?.type !== "array" || !arraySlotsEqual(beforeMutation.slots, beforeMutation.target);
17
+ if (method === "add") return beforeMutation?.type !== "set-add" || !beforeMutation.hadValue;
18
+ if (method === "set") return beforeMutation?.type !== "map-set" || !beforeMutation.hadKey || beforeMutation.valueChanged;
19
+ if (dateMutationMethod(method)) return beforeMutation?.type !== "date" || !Object.is(beforeMutation.time, beforeMutation.target.getTime());
20
+ return true;
21
+ }
22
+ function collectionMutationSnapshot(target, method, args) {
23
+ if (method === "add" && target instanceof Set) return {
24
+ type: "set-add",
25
+ hadValue: target.has(args[0])
26
+ };
27
+ if (method === "set" && target instanceof Map) {
28
+ const hadKey = target.has(args[0]);
29
+ return {
30
+ type: "map-set",
31
+ hadKey,
32
+ valueChanged: !hadKey || !Object.is(target.get(args[0]), args[1])
33
+ };
34
+ }
35
+ if (target instanceof Date && dateMutationMethod(method)) return {
36
+ type: "date",
37
+ time: target.getTime(),
38
+ target
39
+ };
40
+ if (arrayContentMutationMethod(method) && Array.isArray(target)) return {
41
+ type: "array",
42
+ slots: arraySlotSnapshot(target),
43
+ target
44
+ };
45
+ if (Array.isArray(target)) return {
46
+ type: "size",
47
+ value: target.length
48
+ };
49
+ if (target instanceof Map || target instanceof Set) return {
50
+ type: "size",
51
+ value: target.size
52
+ };
53
+ return null;
54
+ }
55
+ function isSupportedCollectionMethod(name) {
56
+ return name === "add" || name === "clear" || name === "copyWithin" || name === "delete" || name === "fill" || name === "pop" || name === "push" || name === "reverse" || name === "set" || name === "shift" || name === "sort" || name === "splice" || name === "unshift" || dateMutationMethod(name);
57
+ }
58
+ function isSupportedCollectionTarget(target) {
59
+ return Array.isArray(target) || target instanceof Map || target instanceof Set || target instanceof Date;
60
+ }
61
+ function arrayContentMutationMethod(method) {
62
+ return method === "copyWithin" || method === "fill" || method === "reverse" || method === "sort" || method === "splice";
63
+ }
64
+ function dateMutationMethod(method) {
65
+ return method === "setDate" || method === "setFullYear" || method === "setHours" || method === "setMilliseconds" || method === "setMinutes" || method === "setMonth" || method === "setSeconds" || method === "setTime" || method === "setUTCDate" || method === "setUTCFullYear" || method === "setUTCHours" || method === "setUTCMilliseconds" || method === "setUTCMinutes" || method === "setUTCMonth" || method === "setUTCSeconds" || method === "setYear";
66
+ }
67
+ function arraySlotSnapshot(target) {
68
+ return Array.from({ length: target.length }, (_, index) => ({
69
+ exists: Object.prototype.hasOwnProperty.call(target, index),
70
+ value: target[index]
71
+ }));
72
+ }
73
+ function arraySlotsEqual(before, after) {
74
+ if (!Array.isArray(after)) return false;
75
+ if (before.length !== after.length) return false;
76
+ return before.every((slot, index) => {
77
+ const exists = Object.prototype.hasOwnProperty.call(after, index);
78
+ return slot.exists === exists && (!slot.exists || Object.is(slot.value, after[index]));
79
+ });
80
+ }
81
+ //#endregion
82
+ //#region src/graph-computed.ts
83
+ function createRuntimeComputedNodes(computedInput) {
84
+ const computedNodes = /* @__PURE__ */ new Map();
85
+ for (const computed of computedInput ?? []) computedNodes.set(computed.graphNodeId, {
86
+ ...computed,
87
+ dirty: true,
88
+ value: void 0
89
+ });
90
+ return computedNodes;
91
+ }
92
+ function readComputedNode(computed, readGraph, path, reconcile) {
93
+ const { compute } = computed;
94
+ if (computed.dirty && compute) {
95
+ const previous = computed.value;
96
+ computed.value = compute(readGraph);
97
+ computed.dirty = false;
98
+ reconcile?.(computed, previous);
99
+ }
100
+ return readPath(computed.value, path);
101
+ }
102
+ function markComputedDirty(input) {
103
+ if (input.visited.has(input.graphNodeId)) return;
104
+ input.visited.add(input.graphNodeId);
105
+ const computed = input.computedNodes.get(input.graphNodeId);
106
+ if (!computed?.compute) return;
107
+ computed.dirty = true;
108
+ if (input.reconcile) input.reconcile.invalidateComputed(computed);
109
+ else input.dirtyPaths.push({
110
+ graphNodeId: input.graphNodeId,
111
+ path: []
112
+ });
113
+ for (const dependent of input.computedNodes.values()) if (dependent.dependencies.some((dependency) => dependency.graphNodeId === input.graphNodeId) && dependent.compute) markComputedDirty({
114
+ ...input,
115
+ graphNodeId: dependent.graphNodeId
116
+ });
117
+ for (const dependent of input.asyncComputedNodes.values()) if (dependent.dependencies.some((dependency) => dependency.graphNodeId === input.graphNodeId)) input.invalidateAsyncComputed(dependent);
118
+ }
119
+ function markDirtyComputedDependencies(input) {
120
+ for (const computed of input.computedNodes.values()) if (computed.dependencies.some((dependency) => dependency.graphNodeId === input.graphNodeId && pathsIntersect(input.path, dependency.path ?? [])) && computed.compute) markComputedDirty({
121
+ ...input,
122
+ graphNodeId: computed.graphNodeId,
123
+ visited: /* @__PURE__ */ new Set()
124
+ });
125
+ for (const asyncComputed of input.asyncComputedNodes.values()) if (asyncComputed.dependencies.some((dependency) => dependency.graphNodeId === input.graphNodeId && pathsIntersect(input.path, dependency.path ?? []))) input.invalidateAsyncComputed(asyncComputed);
126
+ }
127
+ //#endregion
128
+ //#region src/graph-scheduler.ts
129
+ function appendJournalResult(journal, result) {
130
+ if (!result) return;
131
+ if (isDomJournalEntryArray(result)) {
132
+ journal.push(...result);
133
+ return;
134
+ }
135
+ journal.push(result);
136
+ }
137
+ function scheduleMicrotask(callback) {
138
+ if (typeof queueMicrotask === "function") {
139
+ queueMicrotask(callback);
140
+ return;
141
+ }
142
+ Promise.resolve().then(callback);
143
+ }
144
+ function isDomJournalEntryArray(result) {
145
+ return Array.isArray(result);
146
+ }
147
+ //#endregion
148
+ //#region src/graph-shared.ts
149
+ function createSharedGraphPlane(input) {
150
+ const sharedDefinitions = /* @__PURE__ */ new Map();
151
+ const sharedPatches = [];
152
+ for (const definition of input.sharedDefinitionsInput ?? []) sharedDefinitions.set(definition.id, definition);
153
+ const resolveSharedGraphPath = (definitionId, propertyName, path) => {
154
+ const definition = sharedDefinitions.get(definitionId);
155
+ if (!definition) return void 0;
156
+ const property = findLastSharedReturnProperty(definition.returnProperties, propertyName);
157
+ if (!property || property.kind !== "graph") return void 0;
158
+ return {
159
+ definition,
160
+ graphNodeId: property.graphNodeId,
161
+ graphPath: [...property.path, ...path],
162
+ exposedPath: [property.name, ...path]
163
+ };
164
+ };
165
+ const setSharedDefinitionVersion = (definition, version) => {
166
+ const nextDefinition = {
167
+ ...definition,
168
+ version
169
+ };
170
+ sharedDefinitions.set(definition.id, nextDefinition);
171
+ return nextDefinition;
172
+ };
173
+ const nextSharedDefinitionVersion = (definition) => setSharedDefinitionVersion(definition, definition.version + 1);
174
+ const applySharedPatch = (patch) => {
175
+ const definition = sharedDefinitions.get(patch.id);
176
+ if (!definition) return false;
177
+ if (patch.version <= definition.version) return false;
178
+ if (patch.scope && definition.scope && patch.scope !== definition.scope) return false;
179
+ if (patch.patch.length === 0) return false;
180
+ const resolvedPatches = [];
181
+ for (const [operation, exposedPath, value] of patch.patch) {
182
+ if (operation !== "set") return false;
183
+ const [propertyName, ...path] = exposedPath;
184
+ if (!propertyName) return false;
185
+ const resolved = resolveSharedGraphPath(patch.id, propertyName, path);
186
+ if (!resolved) return false;
187
+ resolvedPatches.push({
188
+ graphNodeId: resolved.graphNodeId,
189
+ graphPath: resolved.graphPath,
190
+ value
191
+ });
192
+ }
193
+ for (const resolved of resolvedPatches) {
194
+ const current = input.cells.get(resolved.graphNodeId);
195
+ input.cells.set(resolved.graphNodeId, writePath(current, resolved.graphPath, resolved.value));
196
+ input.markDirtyPath(resolved.graphNodeId, dirtyPathForGraphWrite(current, resolved.graphPath));
197
+ }
198
+ setSharedDefinitionVersion(definition, patch.version);
199
+ input.scheduleFlush();
200
+ return true;
201
+ };
202
+ return {
203
+ readShared(definitionId, propertyName, path = []) {
204
+ const resolved = resolveSharedGraphPath(definitionId, propertyName, path);
205
+ if (!resolved) return void 0;
206
+ return input.readGraph(resolved.graphNodeId, resolved.graphPath);
207
+ },
208
+ writeShared(write) {
209
+ const target = resolveSharedGraphPath(write.definitionId, write.propertyName, write.path ?? []);
210
+ if (!target) return false;
211
+ const current = input.cells.get(target.graphNodeId);
212
+ input.cells.set(target.graphNodeId, writePath(current, target.graphPath, write.value));
213
+ const nextDefinition = nextSharedDefinitionVersion(target.definition);
214
+ sharedPatches.push({
215
+ id: nextDefinition.id,
216
+ ...nextDefinition.scope ? { scope: nextDefinition.scope } : {},
217
+ version: nextDefinition.version,
218
+ patch: [[
219
+ "set",
220
+ target.exposedPath,
221
+ write.value
222
+ ]]
223
+ });
224
+ input.markDirtyPath(target.graphNodeId, dirtyPathForGraphWrite(current, target.graphPath));
225
+ input.scheduleFlush();
226
+ return true;
227
+ },
228
+ getSharedDefinition(definitionId) {
229
+ return sharedDefinitions.get(definitionId);
230
+ },
231
+ listSharedDefinitions() {
232
+ return [...sharedDefinitions.values()];
233
+ },
234
+ takeSharedPatches() {
235
+ return sharedPatches.splice(0);
236
+ },
237
+ applySharedPatch
238
+ };
239
+ }
240
+ //#endregion
241
+ //#region src/graph.ts
242
+ function createRuntimeGraph(input) {
243
+ const cells = /* @__PURE__ */ new Map();
244
+ const readInitializers = /* @__PURE__ */ new Map();
245
+ const computedNodes = createRuntimeComputedNodes(input.computed);
246
+ const asyncComputedNodes = createRuntimeAsyncComputedNodes(input.asyncComputed);
247
+ const subscriptions = [];
248
+ const journalListeners = [];
249
+ const dirtyPaths = [];
250
+ const journal = [];
251
+ let flushScheduled = false;
252
+ let flushing = false;
253
+ let activeFlush;
254
+ for (const cell of input.cells) {
255
+ cells.set(cell.graphNodeId, cell.value);
256
+ if (cell.readInitializer) readInitializers.set(cell.graphNodeId, cell.readInitializer);
257
+ }
258
+ const readGraph = (graphNodeId, path = []) => {
259
+ const computed = computedNodes.get(graphNodeId);
260
+ if (computed?.compute) return readComputedNode(computed, readGraph, path, plane?.reconcileComputed);
261
+ const asyncComputed = asyncComputedNodes.get(graphNodeId);
262
+ if (asyncComputed) return readAsyncComputedNode(asyncComputed, path, () => demandAsyncComputed$1(asyncComputed));
263
+ const initialize = readInitializers.get(graphNodeId);
264
+ if (initialize) {
265
+ readInitializers.delete(graphNodeId);
266
+ const current = cells.get(graphNodeId);
267
+ try {
268
+ const value = initialize();
269
+ if (!Object.is(current, value)) {
270
+ cells.set(graphNodeId, value);
271
+ markDirtyPath(graphNodeId, dirtyPathForGraphWrite(current, []));
272
+ scheduleFlush();
273
+ }
274
+ } catch {}
275
+ }
276
+ return readPath(cells.get(graphNodeId), path);
277
+ };
278
+ const markDirtyPath = (graphNodeId, path) => {
279
+ dirtyPaths.push({
280
+ graphNodeId,
281
+ path
282
+ });
283
+ plane?.recordWrite(graphNodeId, path);
284
+ markDirtyComputedDependencies({
285
+ graphNodeId,
286
+ path,
287
+ computedNodes,
288
+ asyncComputedNodes,
289
+ dirtyPaths,
290
+ reconcile: plane,
291
+ invalidateAsyncComputed: invalidateAsyncComputed$1
292
+ });
293
+ };
294
+ const scheduleFlush = () => {
295
+ if (flushScheduled || flushing) return;
296
+ flushScheduled = true;
297
+ scheduleMicrotask(() => {
298
+ flush();
299
+ });
300
+ };
301
+ const plane = input.reconcile?.({
302
+ cells,
303
+ computedNodes,
304
+ subscriptions,
305
+ dirtyPaths,
306
+ readGraph,
307
+ markDirtyPath,
308
+ scheduleFlush
309
+ });
310
+ const asyncComputedInput = () => ({
311
+ computedNodes,
312
+ asyncComputedNodes,
313
+ demandAsyncComputed: demandAsyncComputed$1,
314
+ readGraph,
315
+ markDirtyPath,
316
+ scheduleFlush,
317
+ reconcile: plane
318
+ });
319
+ const demandAsyncComputed$1 = (node) => demandAsyncComputed({
320
+ node,
321
+ ...asyncComputedInput()
322
+ });
323
+ const invalidateAsyncComputed$1 = (node) => invalidateAsyncComputed({
324
+ node,
325
+ ...asyncComputedInput()
326
+ });
327
+ const sharedGraph = createSharedGraphPlane({
328
+ cells,
329
+ sharedDefinitionsInput: input.sharedDefinitions,
330
+ readGraph,
331
+ markDirtyPath,
332
+ scheduleFlush
333
+ });
334
+ const flush = () => {
335
+ if (activeFlush) return activeFlush;
336
+ activeFlush = runFlush();
337
+ return activeFlush;
338
+ };
339
+ const runFlush = async () => {
340
+ flushScheduled = false;
341
+ flushing = true;
342
+ try {
343
+ try {
344
+ while (dirtyPaths.length > 0) {
345
+ plane?.recomputeSubscribed();
346
+ const pending = dirtyPaths.splice(0);
347
+ const ranSubscriptions = /* @__PURE__ */ new Set();
348
+ for (const subscription of subscriptions) {
349
+ const subscriptionPath = subscription.path ?? [];
350
+ if (!pending.some((path) => path.graphNodeId === subscription.graphNodeId && pathsIntersect(path.path, subscriptionPath)) || ranSubscriptions.has(subscription.id)) continue;
351
+ ranSubscriptions.add(subscription.id);
352
+ appendJournalResult(journal, await subscription.run(readGraph(subscription.graphNodeId, subscriptionPath)));
353
+ }
354
+ }
355
+ } finally {
356
+ plane?.settleBaselines();
357
+ flushing = false;
358
+ }
359
+ await notifyJournalListeners();
360
+ } finally {
361
+ activeFlush = void 0;
362
+ if (dirtyPaths.length > 0) scheduleFlush();
363
+ }
364
+ };
365
+ const notifyJournalListeners = async () => {
366
+ if (journalListeners.length === 0 || journal.length === 0) return;
367
+ const entries = journal.splice(0);
368
+ for (const listener of journalListeners) await listener(entries);
369
+ };
370
+ return {
371
+ read: readGraph,
372
+ ...typeof __MARKLESS_DEBUG_ENABLED__ !== "undefined" && __MARKLESS_DEBUG_ENABLED__ ? { peekAsyncSnapshot: (graphNodeId) => asyncComputedNodes.get(graphNodeId)?.snapshot } : {},
373
+ readShared: sharedGraph.readShared,
374
+ writeShared: sharedGraph.writeShared,
375
+ getSharedDefinition: sharedGraph.getSharedDefinition,
376
+ listSharedDefinitions: sharedGraph.listSharedDefinitions,
377
+ takeSharedPatches: sharedGraph.takeSharedPatches,
378
+ applySharedPatch: sharedGraph.applySharedPatch,
379
+ write(write) {
380
+ const path = write.path ?? [];
381
+ const current = cells.get(write.graphNodeId);
382
+ if (plane?.commitDerived(write, path)) return;
383
+ if (Object.is(readPath(current, path), write.value)) return;
384
+ cells.set(write.graphNodeId, writePath(current, path, write.value));
385
+ markDirtyPath(write.graphNodeId, dirtyPathForGraphWrite(current, path));
386
+ scheduleFlush();
387
+ },
388
+ update(update) {
389
+ const path = update.path ?? [];
390
+ const currentValue = readPath(cells.get(update.graphNodeId), path);
391
+ const nextValue = update.update(currentValue);
392
+ if (!Object.is(currentValue, nextValue)) {
393
+ const current = cells.get(update.graphNodeId);
394
+ cells.set(update.graphNodeId, writePath(current, path, nextValue));
395
+ markDirtyPath(update.graphNodeId, dirtyPathForGraphWrite(current, path));
396
+ scheduleFlush();
397
+ }
398
+ if (update.returnValue === "previous") return currentValue;
399
+ if (update.returnValue === "next") return nextValue;
400
+ },
401
+ call(call) {
402
+ const path = call.path ?? [];
403
+ const target = readPath(cells.get(call.graphNodeId), path);
404
+ const beforeMutation = collectionMutationSnapshot(target, call.method, call.args ?? []);
405
+ const result = applyCollectionCall(target, call.method, call.args ?? []);
406
+ if (collectionCallMutated(call.method, result, beforeMutation)) {
407
+ markDirtyPath(call.graphNodeId, path);
408
+ scheduleFlush();
409
+ }
410
+ return result;
411
+ },
412
+ delete(deletion) {
413
+ const outcome = deletePath(cells.get(deletion.graphNodeId), deletion.path);
414
+ if (outcome.mutated) {
415
+ markDirtyPath(deletion.graphNodeId, deletion.path);
416
+ scheduleFlush();
417
+ }
418
+ return outcome.result;
419
+ },
420
+ subscribe(subscription) {
421
+ subscriptions.push(subscription);
422
+ return () => {
423
+ const index = subscriptions.indexOf(subscription);
424
+ if (index >= 0) subscriptions.splice(index, 1);
425
+ };
426
+ },
427
+ subscribeJournal(listener) {
428
+ journalListeners.push(listener);
429
+ return () => {
430
+ const index = journalListeners.indexOf(listener);
431
+ if (index >= 0) journalListeners.splice(index, 1);
432
+ };
433
+ },
434
+ flush,
435
+ takeJournal() {
436
+ return journal.splice(0);
437
+ }
438
+ };
439
+ }
440
+ //#endregion
441
+ export { createRuntimeGraph as t };
@@ -0,0 +1,197 @@
1
+ //#region src/graph-core.ts
2
+ function findLastSharedReturnProperty(properties, propertyName) {
3
+ if (!properties) return void 0;
4
+ for (let index = properties.length - 1; index >= 0; index--) {
5
+ const property = properties[index];
6
+ if (property?.name === propertyName) return property;
7
+ }
8
+ }
9
+ function readPath(value, path) {
10
+ let current = value;
11
+ for (const segment of path) {
12
+ if (current == null) return void 0;
13
+ current = current[segment];
14
+ }
15
+ return current;
16
+ }
17
+ function writePath(value, path, nextValue) {
18
+ if (path.length === 0) return nextValue;
19
+ const root = isObject(value) ? value : {};
20
+ let current = root;
21
+ for (const segment of path.slice(0, -1)) {
22
+ const child = current[segment];
23
+ if (!isObject(child)) current[segment] = {};
24
+ current = current[segment];
25
+ }
26
+ current[path[path.length - 1]] = nextValue;
27
+ return root;
28
+ }
29
+ function dirtyPathForGraphWrite(value, path) {
30
+ if (path[path.length - 1] !== "length") return path;
31
+ const parentPath = path.slice(0, -1);
32
+ const parent = readPath(value, parentPath);
33
+ if (!Array.isArray(parent)) return path;
34
+ return parentPath;
35
+ }
36
+ function deletePath(value, path) {
37
+ if (path.length === 0) throw new TypeError("Cannot delete a graph node root. Delete a property path instead.");
38
+ let current = value;
39
+ for (const segment of path.slice(0, -1)) {
40
+ if (current == null) throw new TypeError(`Cannot delete graph path "${path.join(".")}".`);
41
+ current = current[segment];
42
+ }
43
+ if (current == null) throw new TypeError(`Cannot delete graph path "${path.join(".")}".`);
44
+ if (!isObject(current)) return {
45
+ result: true,
46
+ mutated: false
47
+ };
48
+ const key = path[path.length - 1];
49
+ const hadProperty = Object.prototype.hasOwnProperty.call(current, key);
50
+ const result = delete current[key];
51
+ return {
52
+ result,
53
+ mutated: hadProperty && result
54
+ };
55
+ }
56
+ function pathsIntersect(a, b) {
57
+ return isPrefix(a, b) || isPrefix(b, a);
58
+ }
59
+ function isPrefix(prefix, value) {
60
+ if (prefix.length > value.length) return false;
61
+ return prefix.every((segment, index) => value[index] === segment);
62
+ }
63
+ function isObject(value) {
64
+ return typeof value === "object" && value !== null;
65
+ }
66
+ //#endregion
67
+ //#region src/graph-async.ts
68
+ const ASYNC_SNAPSHOT_META_KEYS = new Set([
69
+ "status",
70
+ "version",
71
+ "key",
72
+ "error",
73
+ "value"
74
+ ]);
75
+ function createRuntimeAsyncComputedNodes(asyncComputedInput) {
76
+ const asyncComputedNodes = /* @__PURE__ */ new Map();
77
+ for (const asyncComputed of asyncComputedInput ?? []) {
78
+ const initialSnapshot = asyncComputed.initialSnapshot ?? {
79
+ status: "idle",
80
+ version: 0
81
+ };
82
+ asyncComputedNodes.set(asyncComputed.graphNodeId, {
83
+ ...asyncComputed,
84
+ gate: initialSnapshot.status === "pending" ? 1 : 0,
85
+ snapshot: initialSnapshot,
86
+ version: initialSnapshot.version
87
+ });
88
+ }
89
+ return asyncComputedNodes;
90
+ }
91
+ function readAsyncComputedNode(node, path, demand) {
92
+ demand();
93
+ const head = path[0];
94
+ if (head === void 0 || ASYNC_SNAPSHOT_META_KEYS.has(head)) return readPath(node.snapshot, path);
95
+ return readPath(node.snapshot.value, path);
96
+ }
97
+ function demandAsyncComputed(input) {
98
+ if (input.node.gate !== 1 && input.node.snapshot.status !== "idle") return;
99
+ advanceAsyncComputed(input);
100
+ }
101
+ function invalidateAsyncComputed(input) {
102
+ if (input.node.snapshot.status === "idle") return;
103
+ advanceAsyncComputed(input);
104
+ }
105
+ function advanceAsyncComputed(input) {
106
+ const visited = new Set([input.node.graphNodeId]);
107
+ let blocked;
108
+ const visit = (graphNodeId) => {
109
+ if (visited.has(graphNodeId)) return;
110
+ visited.add(graphNodeId);
111
+ const dependency = input.asyncComputedNodes.get(graphNodeId);
112
+ if (dependency) {
113
+ if (dependency.snapshot.status === "idle" || dependency.snapshot.status === "pending") {
114
+ blocked = dependency;
115
+ input.demandAsyncComputed(dependency);
116
+ } else if (!blocked && dependency.snapshot.status === "rejected") blocked = dependency;
117
+ return;
118
+ }
119
+ for (const dependency of input.computedNodes.get(graphNodeId)?.dependencies ?? []) visit(dependency.graphNodeId);
120
+ };
121
+ for (const dependency of input.node.dependencies) visit(dependency.graphNodeId);
122
+ if (blocked) {
123
+ commitDependencyBlock(input, blocked.snapshot.status === "rejected" ? "rejected" : "pending", blocked.snapshot.error);
124
+ return;
125
+ }
126
+ const nextKey = input.node.key(input.readGraph);
127
+ if (!input.node.gate && input.node.snapshot.status !== "idle" && Object.is(input.node.snapshot.key, nextKey)) return;
128
+ startAsyncComputed({
129
+ ...input,
130
+ key: nextKey
131
+ });
132
+ }
133
+ function commitDependencyBlock(input, status, error) {
134
+ if (input.node.gate === 2 && (status === "pending" || input.node.snapshot.status === "rejected" && Object.is(input.node.snapshot.error, error))) return;
135
+ input.node.controller?.abort();
136
+ input.node.controller = void 0;
137
+ input.node.gate = 2;
138
+ const version = ++input.node.version;
139
+ const key = input.node.snapshot.key;
140
+ publish(input, status === "pending" ? {
141
+ status,
142
+ version,
143
+ key,
144
+ value: input.node.snapshot.value
145
+ } : {
146
+ status,
147
+ version,
148
+ key,
149
+ error
150
+ });
151
+ }
152
+ function startAsyncComputed(input) {
153
+ input.node.controller?.abort();
154
+ input.node.gate = 0;
155
+ const controller = new AbortController();
156
+ const version = ++input.node.version;
157
+ input.node.controller = controller;
158
+ publish(input, {
159
+ status: "pending",
160
+ version,
161
+ key: input.key,
162
+ value: input.node.snapshot.value
163
+ });
164
+ const commit = (snapshot) => {
165
+ if (input.node.version !== version) return;
166
+ publish(input, snapshot);
167
+ };
168
+ const commitRejected = (error) => commit({
169
+ status: "rejected",
170
+ version,
171
+ key: input.key,
172
+ error
173
+ });
174
+ try {
175
+ Promise.resolve(input.node.run({
176
+ key: input.key,
177
+ signal: controller.signal,
178
+ read: input.readGraph
179
+ })).then((value) => commit({
180
+ status: "fulfilled",
181
+ version,
182
+ key: input.key,
183
+ value
184
+ }), commitRejected);
185
+ } catch (error) {
186
+ commitRejected(error);
187
+ }
188
+ }
189
+ function publish(input, snapshot) {
190
+ const previous = input.node.snapshot;
191
+ input.node.snapshot = snapshot;
192
+ if (input.reconcile) input.reconcile.publishAsync(input.node, previous);
193
+ else input.markDirtyPath(input.node.graphNodeId, []);
194
+ input.scheduleFlush();
195
+ }
196
+ //#endregion
197
+ export { readAsyncComputedNode as a, findLastSharedReturnProperty as c, writePath as d, invalidateAsyncComputed as i, pathsIntersect as l, createRuntimeAsyncComputedNodes as n, deletePath as o, demandAsyncComputed as r, dirtyPathForGraphWrite as s, ASYNC_SNAPSHOT_META_KEYS as t, readPath as u };