@graphrefly/ts 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/adapters/index.cjs +9015 -0
- package/dist/adapters/index.cjs.map +1 -0
- package/dist/adapters/index.d.cts +678 -0
- package/dist/adapters/index.d.ts +678 -0
- package/dist/adapters/index.js +2894 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/observe-storage.cjs +260 -0
- package/dist/adapters/observe-storage.cjs.map +1 -0
- package/dist/adapters/observe-storage.d.cts +77 -0
- package/dist/adapters/observe-storage.d.ts +77 -0
- package/dist/adapters/observe-storage.js +161 -0
- package/dist/adapters/observe-storage.js.map +1 -0
- package/dist/append-log-DisvEReb.d.cts +189 -0
- package/dist/append-log-DzKMmjxx.d.ts +189 -0
- package/dist/chunk-2ILL7HQI.js +1189 -0
- package/dist/chunk-2ILL7HQI.js.map +1 -0
- package/dist/chunk-4VLAQHZI.js +330 -0
- package/dist/chunk-4VLAQHZI.js.map +1 -0
- package/dist/chunk-6PHB5CJS.js +229 -0
- package/dist/chunk-6PHB5CJS.js.map +1 -0
- package/dist/chunk-COHO25CZ.js +2449 -0
- package/dist/chunk-COHO25CZ.js.map +1 -0
- package/dist/chunk-D6BG7U6A.js +161 -0
- package/dist/chunk-D6BG7U6A.js.map +1 -0
- package/dist/chunk-DJC4CHLQ.js +818 -0
- package/dist/chunk-DJC4CHLQ.js.map +1 -0
- package/dist/chunk-DK554R7P.js +67 -0
- package/dist/chunk-DK554R7P.js.map +1 -0
- package/dist/chunk-DKP56CSW.js +322 -0
- package/dist/chunk-DKP56CSW.js.map +1 -0
- package/dist/chunk-G4M3NHRJ.js +688 -0
- package/dist/chunk-G4M3NHRJ.js.map +1 -0
- package/dist/chunk-GAJW5I5P.js +1 -0
- package/dist/chunk-GAJW5I5P.js.map +1 -0
- package/dist/chunk-GDL26N2T.js +282 -0
- package/dist/chunk-GDL26N2T.js.map +1 -0
- package/dist/chunk-GTPCOEOZ.js +741 -0
- package/dist/chunk-GTPCOEOZ.js.map +1 -0
- package/dist/chunk-H2HTHFVN.js +1 -0
- package/dist/chunk-H2HTHFVN.js.map +1 -0
- package/dist/chunk-HDRL4VQQ.js +218 -0
- package/dist/chunk-HDRL4VQQ.js.map +1 -0
- package/dist/chunk-I3IHOHCJ.js +2267 -0
- package/dist/chunk-I3IHOHCJ.js.map +1 -0
- package/dist/chunk-JIMUDQN3.js +965 -0
- package/dist/chunk-JIMUDQN3.js.map +1 -0
- package/dist/chunk-JR4IKCR2.js +462 -0
- package/dist/chunk-JR4IKCR2.js.map +1 -0
- package/dist/chunk-K3FXTC3I.js +165 -0
- package/dist/chunk-K3FXTC3I.js.map +1 -0
- package/dist/chunk-OOEN33FB.js +65 -0
- package/dist/chunk-OOEN33FB.js.map +1 -0
- package/dist/chunk-PKVBHGBM.js +554 -0
- package/dist/chunk-PKVBHGBM.js.map +1 -0
- package/dist/chunk-RIIOUTGM.js +1857 -0
- package/dist/chunk-RIIOUTGM.js.map +1 -0
- package/dist/chunk-SCRFRCGR.js +33 -0
- package/dist/chunk-SCRFRCGR.js.map +1 -0
- package/dist/chunk-SWTLEQL6.js +53 -0
- package/dist/chunk-SWTLEQL6.js.map +1 -0
- package/dist/chunk-SZAETNNA.js +1 -0
- package/dist/chunk-SZAETNNA.js.map +1 -0
- package/dist/chunk-TEW47IVR.js +49 -0
- package/dist/chunk-TEW47IVR.js.map +1 -0
- package/dist/chunk-Y3ZLRGHC.js +1482 -0
- package/dist/chunk-Y3ZLRGHC.js.map +1 -0
- package/dist/chunk-Z2ANQ6JW.js +149 -0
- package/dist/chunk-Z2ANQ6JW.js.map +1 -0
- package/dist/codec-BB7p8fJc.d.cts +38 -0
- package/dist/codec-BB7p8fJc.d.ts +38 -0
- package/dist/composition/index.cjs +2505 -0
- package/dist/composition/index.cjs.map +1 -0
- package/dist/composition/index.d.cts +95 -0
- package/dist/composition/index.d.ts +95 -0
- package/dist/composition/index.js +19 -0
- package/dist/composition/index.js.map +1 -0
- package/dist/core/index.cjs +2475 -0
- package/dist/core/index.cjs.map +1 -0
- package/dist/core/index.d.cts +25 -0
- package/dist/core/index.d.ts +25 -0
- package/dist/core/index.js +74 -0
- package/dist/core/index.js.map +1 -0
- package/dist/cqrs/index.cjs +595 -0
- package/dist/cqrs/index.cjs.map +1 -0
- package/dist/cqrs/index.d.cts +200 -0
- package/dist/cqrs/index.d.ts +200 -0
- package/dist/cqrs/index.js +557 -0
- package/dist/cqrs/index.js.map +1 -0
- package/dist/data-structures/index.cjs +4277 -0
- package/dist/data-structures/index.cjs.map +1 -0
- package/dist/data-structures/index.d.cts +22 -0
- package/dist/data-structures/index.d.ts +22 -0
- package/dist/data-structures/index.js +31 -0
- package/dist/data-structures/index.js.map +1 -0
- package/dist/describe-BZb7AS2y.d.ts +57 -0
- package/dist/describe-Ciu8SUnN.d.cts +57 -0
- package/dist/graph/index.cjs +7832 -0
- package/dist/graph/index.cjs.map +1 -0
- package/dist/graph/index.d.cts +251 -0
- package/dist/graph/index.d.ts +251 -0
- package/dist/graph/index.js +131 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph-DfdF9zy4.d.ts +666 -0
- package/dist/graph-s23RbbFO.d.cts +666 -0
- package/dist/index-CAEmLCYF.d.cts +166 -0
- package/dist/index-SnzZu3x7.d.ts +166 -0
- package/dist/index.cjs +15409 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +23 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +582 -0
- package/dist/index.js.map +1 -0
- package/dist/messages-BZqrGGm1.d.cts +55 -0
- package/dist/messages-BZqrGGm1.d.ts +55 -0
- package/dist/messaging/index.cjs +818 -0
- package/dist/messaging/index.cjs.map +1 -0
- package/dist/messaging/index.d.cts +235 -0
- package/dist/messaging/index.d.ts +235 -0
- package/dist/messaging/index.js +767 -0
- package/dist/messaging/index.js.map +1 -0
- package/dist/observe-event-log-0SVsx7JG.d.cts +88 -0
- package/dist/observe-event-log-Dnm76owp.d.ts +88 -0
- package/dist/operators/index.cjs +3774 -0
- package/dist/operators/index.cjs.map +1 -0
- package/dist/operators/index.d.cts +308 -0
- package/dist/operators/index.d.ts +308 -0
- package/dist/operators/index.js +112 -0
- package/dist/operators/index.js.map +1 -0
- package/dist/orchestration/index.cjs +3541 -0
- package/dist/orchestration/index.cjs.map +1 -0
- package/dist/orchestration/index.d.cts +302 -0
- package/dist/orchestration/index.d.ts +302 -0
- package/dist/orchestration/index.js +1004 -0
- package/dist/orchestration/index.js.map +1 -0
- package/dist/patterns/index.cjs +1045 -0
- package/dist/patterns/index.cjs.map +1 -0
- package/dist/patterns/index.d.cts +39 -0
- package/dist/patterns/index.d.ts +39 -0
- package/dist/patterns/index.js +33 -0
- package/dist/patterns/index.js.map +1 -0
- package/dist/reactive-collection-BxBqtIOE.d.cts +344 -0
- package/dist/reactive-collection-Cb1II1Fi.d.ts +344 -0
- package/dist/reactive-collection-storage-BNiEc-Gd.d.ts +217 -0
- package/dist/reactive-collection-storage-D-KmjE0J.d.cts +217 -0
- package/dist/reactive-map-BcB4KsQR.d.ts +256 -0
- package/dist/reactive-map-D-g3dv8I.d.cts +256 -0
- package/dist/read-through-B1CYPfq_.d.cts +82 -0
- package/dist/read-through-DwyJhGs1.d.ts +82 -0
- package/dist/render/index.cjs +250 -0
- package/dist/render/index.cjs.map +1 -0
- package/dist/render/index.d.cts +58 -0
- package/dist/render/index.d.ts +58 -0
- package/dist/render/index.js +20 -0
- package/dist/render/index.js.map +1 -0
- package/dist/resilience-Dig3Q7n0.d.cts +45 -0
- package/dist/resilience-Dig3Q7n0.d.ts +45 -0
- package/dist/semantic-memory-graph-BYoIlP35.d.cts +356 -0
- package/dist/semantic-memory-graph-CxyXLms3.d.ts +356 -0
- package/dist/solutions/index.cjs +3249 -0
- package/dist/solutions/index.cjs.map +1 -0
- package/dist/solutions/index.d.cts +520 -0
- package/dist/solutions/index.d.ts +520 -0
- package/dist/solutions/index.js +31 -0
- package/dist/solutions/index.js.map +1 -0
- package/dist/sources/browser.cjs +3095 -0
- package/dist/sources/browser.cjs.map +1 -0
- package/dist/sources/browser.d.cts +39 -0
- package/dist/sources/browser.d.ts +39 -0
- package/dist/sources/browser.js +137 -0
- package/dist/sources/browser.js.map +1 -0
- package/dist/sources/index.cjs +3021 -0
- package/dist/sources/index.cjs.map +1 -0
- package/dist/sources/index.d.cts +7 -0
- package/dist/sources/index.d.ts +7 -0
- package/dist/sources/index.js +63 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/sources/node.cjs +675 -0
- package/dist/sources/node.cjs.map +1 -0
- package/dist/sources/node.d.cts +109 -0
- package/dist/sources/node.d.ts +109 -0
- package/dist/sources/node.js +639 -0
- package/dist/sources/node.js.map +1 -0
- package/dist/storage/browser.cjs +777 -0
- package/dist/storage/browser.cjs.map +1 -0
- package/dist/storage/browser.d.cts +40 -0
- package/dist/storage/browser.d.ts +40 -0
- package/dist/storage/browser.js +275 -0
- package/dist/storage/browser.js.map +1 -0
- package/dist/storage/index.cjs +1989 -0
- package/dist/storage/index.cjs.map +1 -0
- package/dist/storage/index.d.cts +92 -0
- package/dist/storage/index.d.ts +92 -0
- package/dist/storage/index.js +161 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/node.cjs +898 -0
- package/dist/storage/node.cjs.map +1 -0
- package/dist/storage/node.d.cts +66 -0
- package/dist/storage/node.d.ts +66 -0
- package/dist/storage/node.js +402 -0
- package/dist/storage/node.js.map +1 -0
- package/dist/testing/index.cjs +95 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.cts +20 -0
- package/dist/testing/index.d.ts +20 -0
- package/dist/testing/index.js +8 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/types-bNMSWKqF.d.cts +732 -0
- package/dist/types-h12mNYbq.d.ts +732 -0
- package/package.json +250 -0
|
@@ -0,0 +1,1857 @@
|
|
|
1
|
+
import {
|
|
2
|
+
timer
|
|
3
|
+
} from "./chunk-G4M3NHRJ.js";
|
|
4
|
+
import {
|
|
5
|
+
initNode,
|
|
6
|
+
registerBackendStateContributor
|
|
7
|
+
} from "./chunk-PKVBHGBM.js";
|
|
8
|
+
import {
|
|
9
|
+
Node,
|
|
10
|
+
node,
|
|
11
|
+
releaseRuntimeOfNode
|
|
12
|
+
} from "./chunk-I3IHOHCJ.js";
|
|
13
|
+
import {
|
|
14
|
+
strictCanonicalJsonBytes
|
|
15
|
+
} from "./chunk-4VLAQHZI.js";
|
|
16
|
+
import {
|
|
17
|
+
depBatch,
|
|
18
|
+
depCount,
|
|
19
|
+
depLatest,
|
|
20
|
+
depTerminal,
|
|
21
|
+
isTerminalComplete
|
|
22
|
+
} from "./chunk-SWTLEQL6.js";
|
|
23
|
+
import {
|
|
24
|
+
errorPayload
|
|
25
|
+
} from "./chunk-DK554R7P.js";
|
|
26
|
+
|
|
27
|
+
// src/graph/data-structures/core.ts
|
|
28
|
+
function validateViewCacheMaxEntries(policy) {
|
|
29
|
+
const maxEntries = policy?.maxEntries;
|
|
30
|
+
if (maxEntries === void 0) return void 0;
|
|
31
|
+
if (!Number.isInteger(maxEntries) || maxEntries < 0) {
|
|
32
|
+
throw new RangeError(`viewCache.maxEntries must be a non-negative integer (got ${maxEntries})`);
|
|
33
|
+
}
|
|
34
|
+
return maxEntries;
|
|
35
|
+
}
|
|
36
|
+
var ViewMemoCache = class {
|
|
37
|
+
maxEntries;
|
|
38
|
+
equals;
|
|
39
|
+
memo = [];
|
|
40
|
+
live = /* @__PURE__ */ new Set();
|
|
41
|
+
constructor(policy, equals = Object.is) {
|
|
42
|
+
this.maxEntries = validateViewCacheMaxEntries(policy);
|
|
43
|
+
this.equals = equals;
|
|
44
|
+
}
|
|
45
|
+
get(key) {
|
|
46
|
+
const index = this.memo.findIndex((entry2) => this.equals(entry2.key, key));
|
|
47
|
+
if (index < 0) return void 0;
|
|
48
|
+
const [entry] = this.memo.splice(index, 1);
|
|
49
|
+
if (entry === void 0) return void 0;
|
|
50
|
+
this.memo.push(entry);
|
|
51
|
+
return entry.value;
|
|
52
|
+
}
|
|
53
|
+
set(key, value) {
|
|
54
|
+
this.deleteValue(value);
|
|
55
|
+
this.live.add(value);
|
|
56
|
+
if (this.maxEntries === 0) return;
|
|
57
|
+
this.memo.push({ key, value });
|
|
58
|
+
while (this.maxEntries !== void 0 && this.memo.length > this.maxEntries) {
|
|
59
|
+
this.memo.shift();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
deleteValue(value) {
|
|
63
|
+
for (let i = this.memo.length - 1; i >= 0; i -= 1) {
|
|
64
|
+
if (this.memo[i]?.value === value) this.memo.splice(i, 1);
|
|
65
|
+
}
|
|
66
|
+
this.live.delete(value);
|
|
67
|
+
}
|
|
68
|
+
disposeAll() {
|
|
69
|
+
for (const view of [...this.live]) view.dispose();
|
|
70
|
+
this.memo.length = 0;
|
|
71
|
+
this.live.clear();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
function lightReactiveView(parentDelta, opts) {
|
|
75
|
+
const { dispatcher, factory, graph, materializeSnapshot, name, onDispose } = opts;
|
|
76
|
+
const base = dispatcher ? { dispatcher } : {};
|
|
77
|
+
const group = graph?.topologyGroup({ name: name ?? factory });
|
|
78
|
+
const deltaBody = (ctx) => {
|
|
79
|
+
for (const change of depBatch(ctx, 0) ?? []) {
|
|
80
|
+
ctx.down([["DATA", change]]);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
const delta = group ? group.node([parentDelta], deltaBody, {
|
|
84
|
+
factory: `${factory}.delta`,
|
|
85
|
+
name: name ? `${name}.delta` : void 0,
|
|
86
|
+
meta: { kind: "collection_view_delta", factory },
|
|
87
|
+
partial: true
|
|
88
|
+
}) : new Node([parentDelta], deltaBody, {
|
|
89
|
+
...base,
|
|
90
|
+
factory: `${factory}.delta`,
|
|
91
|
+
name: name ? `${name}.delta` : void 0,
|
|
92
|
+
partial: true
|
|
93
|
+
});
|
|
94
|
+
const pullId = /* @__PURE__ */ Symbol(name ? `${name}.snapshot` : `${factory}.snapshot`);
|
|
95
|
+
const snapshotBody = (ctx) => {
|
|
96
|
+
try {
|
|
97
|
+
ctx.down([["DATA", materializeSnapshot()]]);
|
|
98
|
+
} catch (e) {
|
|
99
|
+
ctx.down([["ERROR", errorPayload(e, `${factory}.snapshot materializer failed`)]]);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const snapshot = group ? group.node([delta], snapshotBody, {
|
|
103
|
+
factory: `${factory}.snapshot`,
|
|
104
|
+
name: name ? `${name}.snapshot` : void 0,
|
|
105
|
+
meta: { kind: "collection_view_snapshot", factory },
|
|
106
|
+
partial: true,
|
|
107
|
+
pullId
|
|
108
|
+
}) : new Node([delta], snapshotBody, {
|
|
109
|
+
...base,
|
|
110
|
+
factory: `${factory}.snapshot`,
|
|
111
|
+
name: name ? `${name}.snapshot` : void 0,
|
|
112
|
+
partial: true,
|
|
113
|
+
pullId
|
|
114
|
+
});
|
|
115
|
+
let disposed = false;
|
|
116
|
+
return {
|
|
117
|
+
delta,
|
|
118
|
+
snapshot,
|
|
119
|
+
pullId,
|
|
120
|
+
dispose() {
|
|
121
|
+
if (disposed) return;
|
|
122
|
+
if (group) {
|
|
123
|
+
group.release({ reason: factory });
|
|
124
|
+
} else {
|
|
125
|
+
releaseRuntimeOfNode(delta);
|
|
126
|
+
releaseRuntimeOfNode(snapshot);
|
|
127
|
+
}
|
|
128
|
+
disposed = true;
|
|
129
|
+
onDispose?.();
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function collectionCore(backend, factory, opts = {}, restore) {
|
|
134
|
+
const { name, dispatcher, graph } = opts;
|
|
135
|
+
const base = dispatcher ? { dispatcher } : {};
|
|
136
|
+
let bindSeq = 0;
|
|
137
|
+
const delta = graph ? graph.node([], null, {
|
|
138
|
+
factory: `${factory}.delta`,
|
|
139
|
+
name: name ? `${name}.delta` : void 0,
|
|
140
|
+
meta: { kind: "collection_delta", collection: factory },
|
|
141
|
+
...restore ? { restore: { ref: restore.deltaRef, config: restore.config } } : {}
|
|
142
|
+
}) : new Node([], null, {
|
|
143
|
+
...base,
|
|
144
|
+
factory: `${factory}.delta`,
|
|
145
|
+
name: name ? `${name}.delta` : void 0
|
|
146
|
+
});
|
|
147
|
+
const pullId = /* @__PURE__ */ Symbol(name ? `${name}.snapshot` : `${factory}.snapshot`);
|
|
148
|
+
const snapFn = (ctx) => {
|
|
149
|
+
ctx.down([["DATA", backend.snapshot()]]);
|
|
150
|
+
};
|
|
151
|
+
const snapshot = graph ? graph.node([delta], snapFn, {
|
|
152
|
+
pullId,
|
|
153
|
+
partial: true,
|
|
154
|
+
factory: `${factory}.snapshot`,
|
|
155
|
+
name: name ? `${name}.snapshot` : void 0,
|
|
156
|
+
meta: { kind: "collection_snapshot", collection: factory },
|
|
157
|
+
...restore ? { restore: { ref: restore.snapshotRef, config: restore.config } } : {}
|
|
158
|
+
}) : new Node([delta], snapFn, {
|
|
159
|
+
...base,
|
|
160
|
+
pullId,
|
|
161
|
+
partial: true,
|
|
162
|
+
factory: `${factory}.snapshot`,
|
|
163
|
+
name: name ? `${name}.snapshot` : void 0
|
|
164
|
+
});
|
|
165
|
+
if (restore !== void 0) {
|
|
166
|
+
registerBackendStateContributor(delta, restore.backendState);
|
|
167
|
+
}
|
|
168
|
+
function emit(change) {
|
|
169
|
+
delta.down([["DATA", change]]);
|
|
170
|
+
}
|
|
171
|
+
function bindSource(src, apply) {
|
|
172
|
+
if (graph === void 0)
|
|
173
|
+
throw new Error(
|
|
174
|
+
"collectionCore.bindSource requires options.graph so the input fold is describe-visible (D61)"
|
|
175
|
+
);
|
|
176
|
+
const op = {
|
|
177
|
+
factory: `${factory}.bindSource`,
|
|
178
|
+
body: (ctx) => {
|
|
179
|
+
const b = depBatch(ctx, 0);
|
|
180
|
+
try {
|
|
181
|
+
if (b) for (const v of b) apply(v);
|
|
182
|
+
} catch (e) {
|
|
183
|
+
ctx.down([["ERROR", errorPayload(e, "collectionCore.bindSource failed")]]);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
const folder = graph.initNode(op, [src], {
|
|
188
|
+
name: name ? `${name}.bind#${bindSeq++}` : void 0,
|
|
189
|
+
meta: { kind: "collection_bind_source", collection: factory }
|
|
190
|
+
});
|
|
191
|
+
return graph.retain(folder, { reason: `${factory}.bindSource` });
|
|
192
|
+
}
|
|
193
|
+
return { delta, snapshot, pullId, emit, bindSource };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/graph/data-structures/reactive-index.ts
|
|
197
|
+
function cmpOrd(a, b) {
|
|
198
|
+
if (a === b) return 0;
|
|
199
|
+
const ta = typeof a;
|
|
200
|
+
if (ta === typeof b && (ta === "number" || ta === "string" || ta === "boolean" || ta === "bigint")) {
|
|
201
|
+
const ax = a;
|
|
202
|
+
const bx = b;
|
|
203
|
+
return ax < bx ? -1 : ax > bx ? 1 : 0;
|
|
204
|
+
}
|
|
205
|
+
return String(a).localeCompare(String(b));
|
|
206
|
+
}
|
|
207
|
+
function compareRows(a, b) {
|
|
208
|
+
const c = cmpOrd(a.secondary, b.secondary);
|
|
209
|
+
return c !== 0 ? c : cmpOrd(a.primary, b.primary);
|
|
210
|
+
}
|
|
211
|
+
function bisectLeft(rows, row) {
|
|
212
|
+
let lo = 0;
|
|
213
|
+
let hi = rows.length;
|
|
214
|
+
while (lo < hi) {
|
|
215
|
+
const mid = lo + hi >> 1;
|
|
216
|
+
if (compareRows(rows[mid], row) < 0) lo = mid + 1;
|
|
217
|
+
else hi = mid;
|
|
218
|
+
}
|
|
219
|
+
return lo;
|
|
220
|
+
}
|
|
221
|
+
var IndexBackend = class {
|
|
222
|
+
_version = 0;
|
|
223
|
+
buf = [];
|
|
224
|
+
byKey = /* @__PURE__ */ new Map();
|
|
225
|
+
trackLru;
|
|
226
|
+
constructor(trackLru, initialRows = []) {
|
|
227
|
+
this.trackLru = trackLru;
|
|
228
|
+
for (const row of initialRows) {
|
|
229
|
+
this.upsert(row.primary, row.secondary, row.value);
|
|
230
|
+
}
|
|
231
|
+
this._version = 0;
|
|
232
|
+
}
|
|
233
|
+
get version() {
|
|
234
|
+
return this._version;
|
|
235
|
+
}
|
|
236
|
+
get size() {
|
|
237
|
+
return this.buf.length;
|
|
238
|
+
}
|
|
239
|
+
has(primary) {
|
|
240
|
+
const row = this.byKey.get(primary);
|
|
241
|
+
if (row === void 0) return false;
|
|
242
|
+
this.touchLru(row);
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
get(primary) {
|
|
246
|
+
const row = this.byKey.get(primary);
|
|
247
|
+
if (row === void 0) return void 0;
|
|
248
|
+
this.touchLru(row);
|
|
249
|
+
return row.value;
|
|
250
|
+
}
|
|
251
|
+
touchLru(row) {
|
|
252
|
+
if (!this.trackLru) return;
|
|
253
|
+
this.byKey.delete(row.primary);
|
|
254
|
+
this.byKey.set(row.primary, row);
|
|
255
|
+
}
|
|
256
|
+
removeRow(row) {
|
|
257
|
+
const start = bisectLeft(this.buf, row);
|
|
258
|
+
for (let i = start; i < this.buf.length && compareRows(this.buf[i], row) === 0; i++) {
|
|
259
|
+
if (this.buf[i] === row) {
|
|
260
|
+
this.buf.splice(i, 1);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const fallback = this.buf.indexOf(row);
|
|
265
|
+
if (fallback >= 0) {
|
|
266
|
+
this.buf.splice(fallback, 1);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
throw new Error("reactiveIndex: internal row index desynchronized");
|
|
270
|
+
}
|
|
271
|
+
upsert(primary, secondary, value) {
|
|
272
|
+
const existing = this.byKey.get(primary);
|
|
273
|
+
const row = { primary, secondary, value };
|
|
274
|
+
if (existing !== void 0) {
|
|
275
|
+
this.removeRow(existing);
|
|
276
|
+
this.byKey.delete(primary);
|
|
277
|
+
}
|
|
278
|
+
this.buf.splice(bisectLeft(this.buf, row), 0, row);
|
|
279
|
+
this.byKey.set(primary, row);
|
|
280
|
+
this._version += 1;
|
|
281
|
+
return existing === void 0;
|
|
282
|
+
}
|
|
283
|
+
delete(primary) {
|
|
284
|
+
const existing = this.byKey.get(primary);
|
|
285
|
+
if (existing === void 0) return false;
|
|
286
|
+
this.removeRow(existing);
|
|
287
|
+
this.byKey.delete(primary);
|
|
288
|
+
this._version += 1;
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
clear() {
|
|
292
|
+
const n = this.buf.length;
|
|
293
|
+
if (n === 0) return 0;
|
|
294
|
+
this.buf.length = 0;
|
|
295
|
+
this.byKey.clear();
|
|
296
|
+
this._version += 1;
|
|
297
|
+
return n;
|
|
298
|
+
}
|
|
299
|
+
rangeByPrimary(start, end) {
|
|
300
|
+
if (cmpOrd(start, end) >= 0) return [];
|
|
301
|
+
const rows = [...this.byKey.entries()].filter(
|
|
302
|
+
([p]) => cmpOrd(p, start) >= 0 && cmpOrd(p, end) < 0
|
|
303
|
+
);
|
|
304
|
+
rows.sort(([a], [b]) => cmpOrd(a, b));
|
|
305
|
+
return rows.map(([, r]) => r.value);
|
|
306
|
+
}
|
|
307
|
+
evictOneForCapacity(order, maxSize) {
|
|
308
|
+
if (maxSize === void 0) return void 0;
|
|
309
|
+
if (!Number.isInteger(maxSize) || maxSize < 1)
|
|
310
|
+
throw new RangeError(`reactiveIndex: maxSize must be a positive integer (got ${maxSize})`);
|
|
311
|
+
const overflow = this.buf.length - maxSize;
|
|
312
|
+
if (overflow <= 0) return void 0;
|
|
313
|
+
switch (order) {
|
|
314
|
+
case "secondary": {
|
|
315
|
+
const row = this.buf[0];
|
|
316
|
+
if (row === void 0) return void 0;
|
|
317
|
+
this.buf.shift();
|
|
318
|
+
this.byKey.delete(row.primary);
|
|
319
|
+
this._version += 1;
|
|
320
|
+
return row.primary;
|
|
321
|
+
}
|
|
322
|
+
case "primary": {
|
|
323
|
+
let victim;
|
|
324
|
+
for (const key of this.byKey.keys()) {
|
|
325
|
+
if (victim === void 0 || cmpOrd(key, victim) < 0) victim = key;
|
|
326
|
+
}
|
|
327
|
+
if (victim === void 0) return void 0;
|
|
328
|
+
const row = this.byKey.get(victim);
|
|
329
|
+
if (row !== void 0) this.removeRow(row);
|
|
330
|
+
this.byKey.delete(victim);
|
|
331
|
+
this._version += 1;
|
|
332
|
+
return victim;
|
|
333
|
+
}
|
|
334
|
+
case "lru": {
|
|
335
|
+
const oldest = this.byKey.keys().next().value;
|
|
336
|
+
if (oldest === void 0) return void 0;
|
|
337
|
+
const row = this.byKey.get(oldest);
|
|
338
|
+
if (row !== void 0) this.removeRow(row);
|
|
339
|
+
this.byKey.delete(oldest);
|
|
340
|
+
this._version += 1;
|
|
341
|
+
return oldest;
|
|
342
|
+
}
|
|
343
|
+
default: {
|
|
344
|
+
throw new Error(`reactiveIndex: unknown capacity order '${String(order)}'`);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
snapshot() {
|
|
349
|
+
return [...this.buf];
|
|
350
|
+
}
|
|
351
|
+
toPrimaryMap() {
|
|
352
|
+
const m = /* @__PURE__ */ new Map();
|
|
353
|
+
for (const r of this.buf) m.set(r.primary, r.value);
|
|
354
|
+
return m;
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
function assertCheckpointableIndexRows(rows) {
|
|
358
|
+
for (const [i, row] of rows.entries()) {
|
|
359
|
+
const primary = row.primary;
|
|
360
|
+
if (primary === null || typeof primary === "string" || typeof primary === "number" || typeof primary === "boolean") {
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
throw new TypeError(
|
|
364
|
+
`reactiveIndex checkpoint backendState[${i}].primary must be a JSON primitive primary key for D160 restore`
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
function reactiveIndex(options = {}) {
|
|
369
|
+
return createReactiveIndex(options);
|
|
370
|
+
}
|
|
371
|
+
function restoreReactiveIndexFromBackendState(initialRows, options = {}) {
|
|
372
|
+
return createReactiveIndex(options, initialRows);
|
|
373
|
+
}
|
|
374
|
+
function createReactiveIndex(options = {}, initialRows = []) {
|
|
375
|
+
const { capacity, graph, dispatcher, name } = options;
|
|
376
|
+
const lruEnabled = capacity?.order === "lru";
|
|
377
|
+
const backend = new IndexBackend(lruEnabled, initialRows);
|
|
378
|
+
const core = collectionCore(
|
|
379
|
+
backend,
|
|
380
|
+
"reactiveIndex",
|
|
381
|
+
options,
|
|
382
|
+
graph !== void 0 && name !== void 0 && capacity === void 0 ? {
|
|
383
|
+
deltaRef: "reactiveIndex.delta",
|
|
384
|
+
snapshotRef: "reactiveIndex.snapshot",
|
|
385
|
+
backendState: () => {
|
|
386
|
+
const rows = backend.snapshot();
|
|
387
|
+
assertCheckpointableIndexRows(rows);
|
|
388
|
+
return rows;
|
|
389
|
+
}
|
|
390
|
+
} : void 0
|
|
391
|
+
);
|
|
392
|
+
const binds = [];
|
|
393
|
+
const base = dispatcher ? { dispatcher } : {};
|
|
394
|
+
const bindDeps = /* @__PURE__ */ new WeakSet();
|
|
395
|
+
const rangeMemo = new ViewMemoCache(options.viewCache, ([aStart, aEnd], [bStart, bEnd]) => {
|
|
396
|
+
return cmpOrd(aStart, bStart) === 0 && cmpOrd(aEnd, bEnd) === 0;
|
|
397
|
+
});
|
|
398
|
+
let bindSeq = 0;
|
|
399
|
+
let rangeSeq = 0;
|
|
400
|
+
let capacityPolicy;
|
|
401
|
+
let apply;
|
|
402
|
+
let releaseApply = () => {
|
|
403
|
+
};
|
|
404
|
+
function isNodeOpt(x) {
|
|
405
|
+
return x instanceof Node;
|
|
406
|
+
}
|
|
407
|
+
function validateMaxSize(v) {
|
|
408
|
+
if (!Number.isFinite(v) || !Number.isInteger(v) || v < 1)
|
|
409
|
+
throw new RangeError(`reactiveIndex: maxSize must be a positive integer (got ${v})`);
|
|
410
|
+
return v;
|
|
411
|
+
}
|
|
412
|
+
function enforceCapacity() {
|
|
413
|
+
if (currentCapacityOrder === void 0) return;
|
|
414
|
+
for (; ; ) {
|
|
415
|
+
const primary = backend.evictOneForCapacity(currentCapacityOrder, currentMaxSize);
|
|
416
|
+
if (primary === void 0) return;
|
|
417
|
+
core.emit({ kind: "delete", primary });
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
const applyBody = (ctx) => {
|
|
421
|
+
const deps = apply?.deps ?? [];
|
|
422
|
+
for (let i = 0; i < depCount(ctx); i++) {
|
|
423
|
+
const dep = deps[i];
|
|
424
|
+
if (dep === capacityPolicy) {
|
|
425
|
+
const latest = depLatest(ctx, i);
|
|
426
|
+
if (latest !== void 0) currentMaxSize = validateMaxSize(latest);
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
if (dep && bindDeps.has(dep)) {
|
|
430
|
+
for (const r of depBatch(ctx, i) ?? []) {
|
|
431
|
+
backend.upsert(r.primary, r.secondary, r.value);
|
|
432
|
+
core.emit({ kind: "upsert", primary: r.primary, secondary: r.secondary, value: r.value });
|
|
433
|
+
enforceCapacity();
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
enforceCapacity();
|
|
438
|
+
};
|
|
439
|
+
function ensureApply() {
|
|
440
|
+
if (apply !== void 0) return apply;
|
|
441
|
+
const op = {
|
|
442
|
+
factory: "reactiveIndex.capacityPolicy",
|
|
443
|
+
body: applyBody,
|
|
444
|
+
opts: { partial: true }
|
|
445
|
+
};
|
|
446
|
+
const deps = capacityPolicy ? [capacityPolicy] : [];
|
|
447
|
+
apply = graph ? graph.initNode(op, deps, {
|
|
448
|
+
name: name ? `${name}.capacityPolicy` : void 0,
|
|
449
|
+
meta: { kind: "collection_policy_apply", collection: "reactiveIndex" }
|
|
450
|
+
}) : new Node(deps, op.body, {
|
|
451
|
+
...base,
|
|
452
|
+
factory: "reactiveIndex.capacityPolicy",
|
|
453
|
+
partial: true,
|
|
454
|
+
name: name ? `${name}.capacityPolicy` : void 0
|
|
455
|
+
});
|
|
456
|
+
releaseApply = graph ? graph.retain(apply, { reason: "reactiveIndex.capacityPolicy" }) : apply.subscribe(() => {
|
|
457
|
+
});
|
|
458
|
+
return apply;
|
|
459
|
+
}
|
|
460
|
+
let currentMaxSize;
|
|
461
|
+
const currentCapacityOrder = capacity?.order;
|
|
462
|
+
if (capacity !== void 0) {
|
|
463
|
+
if (currentCapacityOrder !== "secondary" && currentCapacityOrder !== "primary" && currentCapacityOrder !== "lru") {
|
|
464
|
+
throw new Error("reactiveIndex: capacity.order must be one of secondary|primary|lru (D73)");
|
|
465
|
+
}
|
|
466
|
+
const maxSize = capacity.maxSize;
|
|
467
|
+
if (isNodeOpt(maxSize) && graph === void 0) {
|
|
468
|
+
throw new Error(
|
|
469
|
+
"reactiveIndex capacity.maxSize Node option requires options.graph so the policy edge is describe-visible (D73)"
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
capacityPolicy = isNodeOpt(maxSize) ? maxSize : graph ? graph.initNode(
|
|
473
|
+
{
|
|
474
|
+
factory: "reactiveIndex.maxSizePolicy",
|
|
475
|
+
body: () => {
|
|
476
|
+
},
|
|
477
|
+
opts: { initial: validateMaxSize(maxSize) }
|
|
478
|
+
},
|
|
479
|
+
[],
|
|
480
|
+
{
|
|
481
|
+
name: name ? `${name}.maxSizePolicy` : void 0,
|
|
482
|
+
meta: { kind: "collection_policy", collection: "reactiveIndex", policy: "maxSize" }
|
|
483
|
+
}
|
|
484
|
+
) : void 0;
|
|
485
|
+
if (!isNodeOpt(maxSize)) currentMaxSize = validateMaxSize(maxSize);
|
|
486
|
+
if (capacityPolicy instanceof Node) ensureApply();
|
|
487
|
+
}
|
|
488
|
+
let byPrimaryNode;
|
|
489
|
+
function getByPrimary() {
|
|
490
|
+
if (byPrimaryNode === void 0) {
|
|
491
|
+
byPrimaryNode = node(
|
|
492
|
+
[core.delta],
|
|
493
|
+
(ctx) => {
|
|
494
|
+
ctx.down([["DATA", backend.toPrimaryMap()]]);
|
|
495
|
+
},
|
|
496
|
+
{ factory: "reactiveIndex.byPrimary", partial: true }
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
return byPrimaryNode;
|
|
500
|
+
}
|
|
501
|
+
function getRange(start, end) {
|
|
502
|
+
const key = [start, end];
|
|
503
|
+
const hit = rangeMemo.get(key);
|
|
504
|
+
if (hit !== void 0) return hit;
|
|
505
|
+
const materialize = () => backend.rangeByPrimary(start, end);
|
|
506
|
+
let view;
|
|
507
|
+
view = lightReactiveView(core.delta, {
|
|
508
|
+
...options,
|
|
509
|
+
factory: "reactiveIndex.range",
|
|
510
|
+
name: name ? `${name}.range#${rangeSeq++}` : void 0,
|
|
511
|
+
materializeSnapshot: materialize,
|
|
512
|
+
onDispose: () => {
|
|
513
|
+
rangeMemo.deleteValue(view);
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
rangeMemo.set(key, view);
|
|
517
|
+
return view;
|
|
518
|
+
}
|
|
519
|
+
return {
|
|
520
|
+
delta: core.delta,
|
|
521
|
+
snapshot: core.snapshot,
|
|
522
|
+
pullId: core.pullId,
|
|
523
|
+
get size() {
|
|
524
|
+
return backend.size;
|
|
525
|
+
},
|
|
526
|
+
has(primary) {
|
|
527
|
+
return backend.has(primary);
|
|
528
|
+
},
|
|
529
|
+
get(primary) {
|
|
530
|
+
return backend.get(primary);
|
|
531
|
+
},
|
|
532
|
+
rangeByPrimary(start, end) {
|
|
533
|
+
return backend.rangeByPrimary(start, end);
|
|
534
|
+
},
|
|
535
|
+
range(start, end) {
|
|
536
|
+
return getRange(start, end);
|
|
537
|
+
},
|
|
538
|
+
toArray() {
|
|
539
|
+
return backend.snapshot();
|
|
540
|
+
},
|
|
541
|
+
toPrimaryMap() {
|
|
542
|
+
return backend.toPrimaryMap();
|
|
543
|
+
},
|
|
544
|
+
get byPrimary() {
|
|
545
|
+
return getByPrimary();
|
|
546
|
+
},
|
|
547
|
+
upsert(primary, secondary, value) {
|
|
548
|
+
const inserted = backend.upsert(primary, secondary, value);
|
|
549
|
+
core.emit({ kind: "upsert", primary, secondary, value });
|
|
550
|
+
enforceCapacity();
|
|
551
|
+
return inserted;
|
|
552
|
+
},
|
|
553
|
+
upsertMany(rows) {
|
|
554
|
+
for (const r of rows) {
|
|
555
|
+
backend.upsert(r.primary, r.secondary, r.value);
|
|
556
|
+
core.emit({ kind: "upsert", primary: r.primary, secondary: r.secondary, value: r.value });
|
|
557
|
+
enforceCapacity();
|
|
558
|
+
}
|
|
559
|
+
},
|
|
560
|
+
delete(primary) {
|
|
561
|
+
if (backend.delete(primary)) core.emit({ kind: "delete", primary });
|
|
562
|
+
},
|
|
563
|
+
deleteMany(primaries) {
|
|
564
|
+
const removed = [];
|
|
565
|
+
for (const p of primaries) if (backend.delete(p)) removed.push(p);
|
|
566
|
+
if (removed.length > 0) core.emit({ kind: "deleteMany", primaries: removed });
|
|
567
|
+
},
|
|
568
|
+
clear() {
|
|
569
|
+
const count = backend.clear();
|
|
570
|
+
if (count > 0) core.emit({ kind: "clear", count });
|
|
571
|
+
},
|
|
572
|
+
upsertFrom(src) {
|
|
573
|
+
if (graph === void 0)
|
|
574
|
+
throw new Error(
|
|
575
|
+
"reactiveIndex.upsertFrom requires options.graph so the input fold is describe-visible (D61)"
|
|
576
|
+
);
|
|
577
|
+
const op = {
|
|
578
|
+
factory: "reactiveIndex.bindSource",
|
|
579
|
+
body: (ctx) => {
|
|
580
|
+
try {
|
|
581
|
+
for (const r of depBatch(ctx, 0) ?? []) {
|
|
582
|
+
ctx.down([["DATA", r]]);
|
|
583
|
+
}
|
|
584
|
+
} catch (e) {
|
|
585
|
+
ctx.down([["ERROR", errorPayload(e, "reactiveIndex.bindSource failed")]]);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
const folder = graph.initNode(op, [src], {
|
|
590
|
+
name: name ? `${name}.bind#${bindSeq++}` : void 0,
|
|
591
|
+
meta: { kind: "collection_bind_source", collection: "reactiveIndex" }
|
|
592
|
+
});
|
|
593
|
+
bindDeps.add(folder);
|
|
594
|
+
const applyNode = ensureApply();
|
|
595
|
+
applyNode.subscribeDep(folder, applyBody);
|
|
596
|
+
let active = true;
|
|
597
|
+
const dispose = () => {
|
|
598
|
+
if (!active) return;
|
|
599
|
+
active = false;
|
|
600
|
+
applyNode.unsubscribeDep(folder, applyBody);
|
|
601
|
+
};
|
|
602
|
+
binds.push(dispose);
|
|
603
|
+
return dispose;
|
|
604
|
+
},
|
|
605
|
+
dispose() {
|
|
606
|
+
for (const d of binds) d();
|
|
607
|
+
binds.length = 0;
|
|
608
|
+
releaseApply();
|
|
609
|
+
rangeMemo.disposeAll();
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// src/graph/policies/collection.ts
|
|
615
|
+
var PolicyInputs = class {
|
|
616
|
+
deps;
|
|
617
|
+
constructor(initial = []) {
|
|
618
|
+
this.deps = [...initial];
|
|
619
|
+
}
|
|
620
|
+
add(node2) {
|
|
621
|
+
if (node2 === void 0) return missingPolicyReader();
|
|
622
|
+
const index = this.deps.push(node2) - 1;
|
|
623
|
+
return policyReader(index);
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
function missingPolicyReader() {
|
|
627
|
+
return {
|
|
628
|
+
index: -1,
|
|
629
|
+
read: (_ctx, current) => current
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
function policyReader(index) {
|
|
633
|
+
return {
|
|
634
|
+
index,
|
|
635
|
+
read(ctx, current) {
|
|
636
|
+
const latest = depLatest(ctx, index);
|
|
637
|
+
return latest === void 0 ? current : latest;
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
function lruKeys(keys) {
|
|
642
|
+
return {
|
|
643
|
+
keys: () => keys
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
function trimHeadOverflow(items, config) {
|
|
647
|
+
const { maxSize } = config;
|
|
648
|
+
if (maxSize === void 0) return [];
|
|
649
|
+
if (!Number.isInteger(maxSize) || maxSize < 1)
|
|
650
|
+
throw new RangeError(`maxSize must be a positive integer (got ${maxSize})`);
|
|
651
|
+
const size = "size" in config ? config.size : Array.isArray(items) ? items.length : void 0;
|
|
652
|
+
if (size === void 0) throw new Error("trimHeadOverflow requires size for non-array iterables");
|
|
653
|
+
const overflow = size - maxSize;
|
|
654
|
+
if (overflow <= 0) return [];
|
|
655
|
+
if (Array.isArray(items) && !("size" in config)) return items.splice(0, overflow);
|
|
656
|
+
const victims = [];
|
|
657
|
+
for (const item of items) {
|
|
658
|
+
victims.push(item);
|
|
659
|
+
if (victims.length === overflow) break;
|
|
660
|
+
}
|
|
661
|
+
return victims;
|
|
662
|
+
}
|
|
663
|
+
function deadlines() {
|
|
664
|
+
return new MinDeadlineHeap();
|
|
665
|
+
}
|
|
666
|
+
var MinDeadlineHeap = class {
|
|
667
|
+
items = [];
|
|
668
|
+
get size() {
|
|
669
|
+
return this.items.length;
|
|
670
|
+
}
|
|
671
|
+
push(item) {
|
|
672
|
+
this.items.push(item);
|
|
673
|
+
this.up(this.items.length - 1);
|
|
674
|
+
}
|
|
675
|
+
peek() {
|
|
676
|
+
return this.items[0];
|
|
677
|
+
}
|
|
678
|
+
pop() {
|
|
679
|
+
const top = this.items[0];
|
|
680
|
+
const last = this.items.pop();
|
|
681
|
+
if (top !== void 0 && last !== void 0 && this.items.length > 0) {
|
|
682
|
+
this.items[0] = last;
|
|
683
|
+
this.down(0);
|
|
684
|
+
}
|
|
685
|
+
return top;
|
|
686
|
+
}
|
|
687
|
+
up(i) {
|
|
688
|
+
while (i > 0) {
|
|
689
|
+
const p = i - 1 >> 1;
|
|
690
|
+
if (this.items[p].expiresAt <= this.items[i].expiresAt)
|
|
691
|
+
return;
|
|
692
|
+
[this.items[p], this.items[i]] = [
|
|
693
|
+
this.items[i],
|
|
694
|
+
this.items[p]
|
|
695
|
+
];
|
|
696
|
+
i = p;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
down(i) {
|
|
700
|
+
for (; ; ) {
|
|
701
|
+
const left = i * 2 + 1;
|
|
702
|
+
const right = left + 1;
|
|
703
|
+
let smallest = i;
|
|
704
|
+
if (left < this.items.length && this.expiresAt(left) < this.expiresAt(smallest))
|
|
705
|
+
smallest = left;
|
|
706
|
+
if (right < this.items.length && this.expiresAt(right) < this.expiresAt(smallest))
|
|
707
|
+
smallest = right;
|
|
708
|
+
if (smallest === i) return;
|
|
709
|
+
[this.items[i], this.items[smallest]] = [
|
|
710
|
+
this.items[smallest],
|
|
711
|
+
this.items[i]
|
|
712
|
+
];
|
|
713
|
+
i = smallest;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
expiresAt(i) {
|
|
717
|
+
return this.items[i].expiresAt;
|
|
718
|
+
}
|
|
719
|
+
};
|
|
720
|
+
function selectRetentionVictims(scoredEntries, config) {
|
|
721
|
+
const { maxSize } = config;
|
|
722
|
+
if (maxSize === void 0) return [];
|
|
723
|
+
if (!Number.isInteger(maxSize) || maxSize < 0)
|
|
724
|
+
throw new RangeError(`retention maxSize must be a non-negative integer (got ${maxSize})`);
|
|
725
|
+
const overflow = scoredEntries.length - maxSize;
|
|
726
|
+
if (overflow <= 0) return [];
|
|
727
|
+
return scoredEntries.map((item, index) => {
|
|
728
|
+
if (!Number.isFinite(item.score))
|
|
729
|
+
throw new RangeError(`retention score must be finite (got ${item.score})`);
|
|
730
|
+
return { ...item, index };
|
|
731
|
+
}).sort((a, b) => a.score - b.score || a.index - b.index).slice(0, overflow).map((item) => item.entry);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// src/graph/data-structures/reactive-list.ts
|
|
735
|
+
var ListBackend = class {
|
|
736
|
+
_version = 0;
|
|
737
|
+
buf;
|
|
738
|
+
constructor(initial, maxSize) {
|
|
739
|
+
this.buf = initial ? [...initial] : [];
|
|
740
|
+
trimHeadOverflow(this.buf, { maxSize });
|
|
741
|
+
}
|
|
742
|
+
get version() {
|
|
743
|
+
return this._version;
|
|
744
|
+
}
|
|
745
|
+
get size() {
|
|
746
|
+
return this.buf.length;
|
|
747
|
+
}
|
|
748
|
+
at(index) {
|
|
749
|
+
if (!Number.isInteger(index)) return void 0;
|
|
750
|
+
const i = index >= 0 ? index : this.buf.length + index;
|
|
751
|
+
return i < 0 || i >= this.buf.length ? void 0 : this.buf[i];
|
|
752
|
+
}
|
|
753
|
+
snapshot() {
|
|
754
|
+
return [...this.buf];
|
|
755
|
+
}
|
|
756
|
+
append(value) {
|
|
757
|
+
this.buf.push(value);
|
|
758
|
+
this._version += 1;
|
|
759
|
+
}
|
|
760
|
+
appendMany(values) {
|
|
761
|
+
if (values.length === 0) return;
|
|
762
|
+
for (const v of values) this.buf.push(v);
|
|
763
|
+
this._version += 1;
|
|
764
|
+
}
|
|
765
|
+
insert(index, value) {
|
|
766
|
+
if (!Number.isInteger(index) || index < 0 || index > this.buf.length)
|
|
767
|
+
throw new RangeError(`insert: index ${index} out of range [0, ${this.buf.length}]`);
|
|
768
|
+
this.buf.splice(index, 0, value);
|
|
769
|
+
this._version += 1;
|
|
770
|
+
}
|
|
771
|
+
insertMany(index, values) {
|
|
772
|
+
if (!Number.isInteger(index) || index < 0 || index > this.buf.length)
|
|
773
|
+
throw new RangeError(`insertMany: index ${index} out of range [0, ${this.buf.length}]`);
|
|
774
|
+
if (values.length === 0) return;
|
|
775
|
+
this.buf.splice(index, 0, ...values);
|
|
776
|
+
this._version += 1;
|
|
777
|
+
}
|
|
778
|
+
pop(index) {
|
|
779
|
+
if (this.buf.length === 0) throw new RangeError("pop from empty list");
|
|
780
|
+
if (!Number.isInteger(index)) throw new RangeError(`pop: index ${index} must be an integer`);
|
|
781
|
+
const i = index >= 0 ? index : this.buf.length + index;
|
|
782
|
+
if (i < 0 || i >= this.buf.length) throw new RangeError(`pop: index ${index} out of range`);
|
|
783
|
+
const [v] = this.buf.splice(i, 1);
|
|
784
|
+
this._version += 1;
|
|
785
|
+
return v;
|
|
786
|
+
}
|
|
787
|
+
clear() {
|
|
788
|
+
const n = this.buf.length;
|
|
789
|
+
if (n === 0) return 0;
|
|
790
|
+
this.buf.length = 0;
|
|
791
|
+
this._version += 1;
|
|
792
|
+
return n;
|
|
793
|
+
}
|
|
794
|
+
enforceMaxSize(maxSize) {
|
|
795
|
+
const removed = trimHeadOverflow(this.buf, { maxSize }).length;
|
|
796
|
+
if (removed > 0) this._version += 1;
|
|
797
|
+
return removed;
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
function reactiveList(initial, options = {}) {
|
|
801
|
+
const { maxSize, graph, dispatcher } = options;
|
|
802
|
+
const base = dispatcher ? { dispatcher } : {};
|
|
803
|
+
function isNodeOpt(x) {
|
|
804
|
+
return x instanceof Node;
|
|
805
|
+
}
|
|
806
|
+
function validateMaxSize(v) {
|
|
807
|
+
if (!Number.isFinite(v) || !Number.isInteger(v) || v < 1)
|
|
808
|
+
throw new RangeError(`reactiveList: maxSize must be a positive integer (got ${v})`);
|
|
809
|
+
return v;
|
|
810
|
+
}
|
|
811
|
+
const initialMaxSize = isNodeOpt(maxSize) ? void 0 : maxSize;
|
|
812
|
+
const backend = new ListBackend(
|
|
813
|
+
initial,
|
|
814
|
+
initialMaxSize === void 0 ? void 0 : validateMaxSize(initialMaxSize)
|
|
815
|
+
);
|
|
816
|
+
const restorable = graph !== void 0 && options.name !== void 0 && maxSize === void 0;
|
|
817
|
+
const core = collectionCore(
|
|
818
|
+
backend,
|
|
819
|
+
"reactiveList",
|
|
820
|
+
options,
|
|
821
|
+
restorable ? {
|
|
822
|
+
deltaRef: "reactiveList.delta",
|
|
823
|
+
snapshotRef: "reactiveList.snapshot",
|
|
824
|
+
backendState: () => backend.snapshot()
|
|
825
|
+
} : void 0
|
|
826
|
+
);
|
|
827
|
+
const binds = [];
|
|
828
|
+
const bindDeps = /* @__PURE__ */ new WeakSet();
|
|
829
|
+
let bindSeq = 0;
|
|
830
|
+
let capacityPolicy;
|
|
831
|
+
let apply;
|
|
832
|
+
let releaseApply = () => {
|
|
833
|
+
};
|
|
834
|
+
let currentMaxSize = initialMaxSize;
|
|
835
|
+
function emitTrimmed(n) {
|
|
836
|
+
if (n > 0) core.emit({ kind: "trimHead", n });
|
|
837
|
+
}
|
|
838
|
+
function enforceCapacity() {
|
|
839
|
+
emitTrimmed(backend.enforceMaxSize(currentMaxSize));
|
|
840
|
+
}
|
|
841
|
+
const applyBody = (ctx) => {
|
|
842
|
+
const deps = apply?.deps ?? [];
|
|
843
|
+
for (let i = 0; i < depCount(ctx); i++) {
|
|
844
|
+
const dep = deps[i];
|
|
845
|
+
if (dep === capacityPolicy) {
|
|
846
|
+
const latest = depLatest(ctx, i);
|
|
847
|
+
if (latest !== void 0) currentMaxSize = validateMaxSize(latest);
|
|
848
|
+
continue;
|
|
849
|
+
}
|
|
850
|
+
if (dep && bindDeps.has(dep)) {
|
|
851
|
+
for (const value of depBatch(ctx, i) ?? []) {
|
|
852
|
+
backend.append(value);
|
|
853
|
+
core.emit({ kind: "append", value });
|
|
854
|
+
enforceCapacity();
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
enforceCapacity();
|
|
859
|
+
};
|
|
860
|
+
function ensureApply() {
|
|
861
|
+
if (apply !== void 0) return apply;
|
|
862
|
+
const op = {
|
|
863
|
+
factory: "reactiveList.capacityPolicy",
|
|
864
|
+
body: applyBody,
|
|
865
|
+
opts: { partial: true }
|
|
866
|
+
};
|
|
867
|
+
const deps = capacityPolicy ? [capacityPolicy] : [];
|
|
868
|
+
apply = graph ? graph.initNode(op, deps, {
|
|
869
|
+
name: options.name ? `${options.name}.capacityPolicy` : void 0,
|
|
870
|
+
meta: { kind: "collection_policy_apply", collection: "reactiveList" }
|
|
871
|
+
}) : new Node(deps, op.body, {
|
|
872
|
+
...base,
|
|
873
|
+
factory: "reactiveList.capacityPolicy",
|
|
874
|
+
partial: true,
|
|
875
|
+
name: options.name ? `${options.name}.capacityPolicy` : void 0
|
|
876
|
+
});
|
|
877
|
+
releaseApply = graph ? graph.retain(apply, { reason: "reactiveList.capacityPolicy" }) : apply.subscribe(() => {
|
|
878
|
+
});
|
|
879
|
+
return apply;
|
|
880
|
+
}
|
|
881
|
+
function constPolicyNode(value) {
|
|
882
|
+
const op = {
|
|
883
|
+
factory: "reactiveList.maxSizePolicy",
|
|
884
|
+
body: () => {
|
|
885
|
+
},
|
|
886
|
+
opts: { initial: value }
|
|
887
|
+
};
|
|
888
|
+
if (graph) {
|
|
889
|
+
return graph.initNode(op, [], {
|
|
890
|
+
name: options.name ? `${options.name}.maxSizePolicy` : void 0,
|
|
891
|
+
meta: { kind: "collection_policy", collection: "reactiveList", policy: "maxSize" }
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
return new Node([], null, {
|
|
895
|
+
...base,
|
|
896
|
+
initial: value,
|
|
897
|
+
factory: "reactiveList.maxSizePolicy",
|
|
898
|
+
name: options.name ? `${options.name}.maxSizePolicy` : void 0
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
if (maxSize !== void 0) {
|
|
902
|
+
if (isNodeOpt(maxSize) && graph === void 0)
|
|
903
|
+
throw new Error(
|
|
904
|
+
"reactiveList maxSize Node option requires options.graph so the policy edge is describe-visible (D72)"
|
|
905
|
+
);
|
|
906
|
+
capacityPolicy = isNodeOpt(maxSize) ? maxSize : graph ? constPolicyNode(validateMaxSize(maxSize)) : void 0;
|
|
907
|
+
if (capacityPolicy !== void 0) ensureApply();
|
|
908
|
+
}
|
|
909
|
+
return {
|
|
910
|
+
delta: core.delta,
|
|
911
|
+
snapshot: core.snapshot,
|
|
912
|
+
pullId: core.pullId,
|
|
913
|
+
get size() {
|
|
914
|
+
return backend.size;
|
|
915
|
+
},
|
|
916
|
+
at(index) {
|
|
917
|
+
return backend.at(index);
|
|
918
|
+
},
|
|
919
|
+
toArray() {
|
|
920
|
+
return backend.snapshot();
|
|
921
|
+
},
|
|
922
|
+
append(value) {
|
|
923
|
+
backend.append(value);
|
|
924
|
+
core.emit({ kind: "append", value });
|
|
925
|
+
enforceCapacity();
|
|
926
|
+
},
|
|
927
|
+
appendMany(values) {
|
|
928
|
+
if (values.length === 0) return;
|
|
929
|
+
const copy = [...values];
|
|
930
|
+
backend.appendMany(copy);
|
|
931
|
+
core.emit({ kind: "appendMany", values: copy });
|
|
932
|
+
enforceCapacity();
|
|
933
|
+
},
|
|
934
|
+
insert(index, value) {
|
|
935
|
+
backend.insert(index, value);
|
|
936
|
+
core.emit({ kind: "insert", index, value });
|
|
937
|
+
enforceCapacity();
|
|
938
|
+
},
|
|
939
|
+
insertMany(index, values) {
|
|
940
|
+
if (values.length === 0) {
|
|
941
|
+
backend.insertMany(index, values);
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
const copy = [...values];
|
|
945
|
+
backend.insertMany(index, copy);
|
|
946
|
+
core.emit({ kind: "insertMany", index, values: copy });
|
|
947
|
+
enforceCapacity();
|
|
948
|
+
},
|
|
949
|
+
pop(index = -1) {
|
|
950
|
+
const resolved = index < 0 ? backend.size + index : index;
|
|
951
|
+
const value = backend.pop(index);
|
|
952
|
+
core.emit({ kind: "pop", index: resolved, value });
|
|
953
|
+
return value;
|
|
954
|
+
},
|
|
955
|
+
clear() {
|
|
956
|
+
const count = backend.clear();
|
|
957
|
+
if (count > 0) core.emit({ kind: "clear", count });
|
|
958
|
+
},
|
|
959
|
+
appendFrom(src) {
|
|
960
|
+
if (graph === void 0)
|
|
961
|
+
throw new Error(
|
|
962
|
+
"reactiveList.appendFrom requires options.graph so the input fold is describe-visible (D61)"
|
|
963
|
+
);
|
|
964
|
+
const op = {
|
|
965
|
+
factory: "reactiveList.bindSource",
|
|
966
|
+
body: (ctx) => {
|
|
967
|
+
try {
|
|
968
|
+
for (const value of depBatch(ctx, 0) ?? []) {
|
|
969
|
+
ctx.down([["DATA", value]]);
|
|
970
|
+
}
|
|
971
|
+
} catch (e) {
|
|
972
|
+
ctx.down([["ERROR", errorPayload(e, "reactiveList.bindSource failed")]]);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
};
|
|
976
|
+
const folder = graph.initNode(op, [src], {
|
|
977
|
+
name: options.name ? `${options.name}.bind#${bindSeq++}` : void 0,
|
|
978
|
+
meta: { kind: "collection_bind_source", collection: "reactiveList" }
|
|
979
|
+
});
|
|
980
|
+
bindDeps.add(folder);
|
|
981
|
+
const applyNode = ensureApply();
|
|
982
|
+
applyNode.subscribeDep(folder, applyBody);
|
|
983
|
+
let active = true;
|
|
984
|
+
const dispose = () => {
|
|
985
|
+
if (!active) return;
|
|
986
|
+
active = false;
|
|
987
|
+
applyNode.unsubscribeDep(folder, applyBody);
|
|
988
|
+
};
|
|
989
|
+
binds.push(dispose);
|
|
990
|
+
return dispose;
|
|
991
|
+
},
|
|
992
|
+
dispose() {
|
|
993
|
+
for (const d of binds) d();
|
|
994
|
+
binds.length = 0;
|
|
995
|
+
releaseApply();
|
|
996
|
+
}
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
// src/graph/data-structures/reactive-log.ts
|
|
1001
|
+
var LogBackend = class {
|
|
1002
|
+
_version = 0;
|
|
1003
|
+
buf;
|
|
1004
|
+
maxSize;
|
|
1005
|
+
constructor(initial, maxSize) {
|
|
1006
|
+
if (maxSize !== void 0 && maxSize < 1)
|
|
1007
|
+
throw new RangeError("reactiveLog: maxSize must be >= 1");
|
|
1008
|
+
this.maxSize = maxSize;
|
|
1009
|
+
this.buf = initial ? [...initial] : [];
|
|
1010
|
+
trimHeadOverflow(this.buf, { maxSize });
|
|
1011
|
+
}
|
|
1012
|
+
get version() {
|
|
1013
|
+
return this._version;
|
|
1014
|
+
}
|
|
1015
|
+
get size() {
|
|
1016
|
+
return this.buf.length;
|
|
1017
|
+
}
|
|
1018
|
+
at(index) {
|
|
1019
|
+
if (!Number.isInteger(index)) return void 0;
|
|
1020
|
+
const i = index >= 0 ? index : this.buf.length + index;
|
|
1021
|
+
return i < 0 || i >= this.buf.length ? void 0 : this.buf[i];
|
|
1022
|
+
}
|
|
1023
|
+
snapshot() {
|
|
1024
|
+
return [...this.buf];
|
|
1025
|
+
}
|
|
1026
|
+
append(value) {
|
|
1027
|
+
this.buf.push(value);
|
|
1028
|
+
trimHeadOverflow(this.buf, { maxSize: this.maxSize });
|
|
1029
|
+
this._version += 1;
|
|
1030
|
+
}
|
|
1031
|
+
appendMany(values) {
|
|
1032
|
+
if (values.length === 0) return;
|
|
1033
|
+
for (const v of values) this.buf.push(v);
|
|
1034
|
+
trimHeadOverflow(this.buf, { maxSize: this.maxSize });
|
|
1035
|
+
this._version += 1;
|
|
1036
|
+
}
|
|
1037
|
+
clear() {
|
|
1038
|
+
const n = this.buf.length;
|
|
1039
|
+
if (n === 0) return 0;
|
|
1040
|
+
this.buf.length = 0;
|
|
1041
|
+
this._version += 1;
|
|
1042
|
+
return n;
|
|
1043
|
+
}
|
|
1044
|
+
trimHead(n) {
|
|
1045
|
+
if (!Number.isInteger(n) || n < 0)
|
|
1046
|
+
throw new RangeError(`trimHead: n must be a non-negative integer (got ${n})`);
|
|
1047
|
+
if (n === 0 || this.buf.length === 0) return 0;
|
|
1048
|
+
const removed = Math.min(n, this.buf.length);
|
|
1049
|
+
this.buf.splice(0, removed);
|
|
1050
|
+
this._version += 1;
|
|
1051
|
+
return removed;
|
|
1052
|
+
}
|
|
1053
|
+
};
|
|
1054
|
+
function rejectUndefined(value, ctx) {
|
|
1055
|
+
if (value === void 0)
|
|
1056
|
+
throw new TypeError(
|
|
1057
|
+
`${ctx}: undefined is the substrate SENTINEL, not a valid value \u2014 use null`
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1060
|
+
function reactiveLog(initial, options = {}) {
|
|
1061
|
+
const { maxSize, viewCache, ...coreOpts } = options;
|
|
1062
|
+
const base = coreOpts.dispatcher ? { dispatcher: coreOpts.dispatcher } : {};
|
|
1063
|
+
const backend = new LogBackend(initial, maxSize);
|
|
1064
|
+
const restoreConfig = coreOpts.graph !== void 0 && coreOpts.name !== void 0 ? {
|
|
1065
|
+
...maxSize !== void 0 ? { maxSize } : {}
|
|
1066
|
+
} : void 0;
|
|
1067
|
+
const core = collectionCore(
|
|
1068
|
+
backend,
|
|
1069
|
+
"reactiveLog",
|
|
1070
|
+
coreOpts,
|
|
1071
|
+
restoreConfig !== void 0 ? {
|
|
1072
|
+
deltaRef: "reactiveLog.delta",
|
|
1073
|
+
snapshotRef: "reactiveLog.snapshot",
|
|
1074
|
+
config: restoreConfig,
|
|
1075
|
+
backendState: () => backend.snapshot()
|
|
1076
|
+
} : void 0
|
|
1077
|
+
);
|
|
1078
|
+
const binds = [];
|
|
1079
|
+
const tailMemo = /* @__PURE__ */ new Map();
|
|
1080
|
+
const sliceMemo = /* @__PURE__ */ new Map();
|
|
1081
|
+
const pageMemo = new ViewMemoCache(viewCache);
|
|
1082
|
+
let pageSeq = 0;
|
|
1083
|
+
return {
|
|
1084
|
+
delta: core.delta,
|
|
1085
|
+
snapshot: core.snapshot,
|
|
1086
|
+
pullId: core.pullId,
|
|
1087
|
+
get size() {
|
|
1088
|
+
return backend.size;
|
|
1089
|
+
},
|
|
1090
|
+
at(index) {
|
|
1091
|
+
return backend.at(index);
|
|
1092
|
+
},
|
|
1093
|
+
toArray() {
|
|
1094
|
+
return backend.snapshot();
|
|
1095
|
+
},
|
|
1096
|
+
append(value) {
|
|
1097
|
+
rejectUndefined(value, "reactiveLog.append");
|
|
1098
|
+
backend.append(value);
|
|
1099
|
+
core.emit({ kind: "append", value });
|
|
1100
|
+
},
|
|
1101
|
+
appendMany(values) {
|
|
1102
|
+
if (values.length === 0) return;
|
|
1103
|
+
for (const v of values) rejectUndefined(v, "reactiveLog.appendMany");
|
|
1104
|
+
const copy = [...values];
|
|
1105
|
+
backend.appendMany(copy);
|
|
1106
|
+
core.emit({ kind: "appendMany", values: copy });
|
|
1107
|
+
},
|
|
1108
|
+
clear() {
|
|
1109
|
+
const count = backend.clear();
|
|
1110
|
+
if (count > 0) core.emit({ kind: "clear", count });
|
|
1111
|
+
},
|
|
1112
|
+
trimHead(n) {
|
|
1113
|
+
const removed = backend.trimHead(n);
|
|
1114
|
+
if (removed > 0) core.emit({ kind: "trimHead", n: removed });
|
|
1115
|
+
},
|
|
1116
|
+
tail(n) {
|
|
1117
|
+
if (!Number.isInteger(n) || n < 0)
|
|
1118
|
+
throw new RangeError(`tail: n must be a non-negative integer (got ${n})`);
|
|
1119
|
+
const hit = tailMemo.get(n);
|
|
1120
|
+
if (hit !== void 0) return hit;
|
|
1121
|
+
const tnode = node(
|
|
1122
|
+
[core.delta],
|
|
1123
|
+
(ctx) => {
|
|
1124
|
+
const all = backend.snapshot();
|
|
1125
|
+
ctx.down([["DATA", n === 0 ? [] : all.slice(Math.max(0, all.length - n))]]);
|
|
1126
|
+
},
|
|
1127
|
+
{ ...base, factory: "reactiveLog.tail", partial: true }
|
|
1128
|
+
);
|
|
1129
|
+
tailMemo.set(n, tnode);
|
|
1130
|
+
return tnode;
|
|
1131
|
+
},
|
|
1132
|
+
slice(start, stop) {
|
|
1133
|
+
if (!Number.isInteger(start) || start < 0) {
|
|
1134
|
+
throw new RangeError(`slice: start must be a non-negative integer (got ${start})`);
|
|
1135
|
+
}
|
|
1136
|
+
if (stop !== void 0 && (!Number.isInteger(stop) || stop < 0)) {
|
|
1137
|
+
throw new RangeError(`slice: stop must be a non-negative integer (got ${stop})`);
|
|
1138
|
+
}
|
|
1139
|
+
const key = `${start}:${stop ?? ""}`;
|
|
1140
|
+
const hit = sliceMemo.get(key);
|
|
1141
|
+
if (hit !== void 0) return hit;
|
|
1142
|
+
const snode = node(
|
|
1143
|
+
[core.delta],
|
|
1144
|
+
(ctx) => {
|
|
1145
|
+
ctx.down([["DATA", backend.snapshot().slice(start, stop)]]);
|
|
1146
|
+
},
|
|
1147
|
+
{ ...base, factory: "reactiveLog.slice", partial: true }
|
|
1148
|
+
);
|
|
1149
|
+
sliceMemo.set(key, snode);
|
|
1150
|
+
return snode;
|
|
1151
|
+
},
|
|
1152
|
+
page(offset, limit) {
|
|
1153
|
+
if (!Number.isInteger(offset) || offset < 0) {
|
|
1154
|
+
throw new RangeError(`page: offset must be a non-negative integer (got ${offset})`);
|
|
1155
|
+
}
|
|
1156
|
+
if (!Number.isInteger(limit) || limit < 0) {
|
|
1157
|
+
throw new RangeError(`page: limit must be a non-negative integer (got ${limit})`);
|
|
1158
|
+
}
|
|
1159
|
+
const key = `${offset}:${limit}`;
|
|
1160
|
+
const hit = pageMemo.get(key);
|
|
1161
|
+
if (hit !== void 0) return hit;
|
|
1162
|
+
const materialize = () => backend.snapshot().slice(offset, offset + limit);
|
|
1163
|
+
let view;
|
|
1164
|
+
view = lightReactiveView(core.delta, {
|
|
1165
|
+
...coreOpts,
|
|
1166
|
+
factory: "reactiveLog.page",
|
|
1167
|
+
name: coreOpts.name ? `${coreOpts.name}.page#${pageSeq++}` : void 0,
|
|
1168
|
+
materializeSnapshot: materialize,
|
|
1169
|
+
onDispose: () => {
|
|
1170
|
+
pageMemo.deleteValue(view);
|
|
1171
|
+
}
|
|
1172
|
+
});
|
|
1173
|
+
pageMemo.set(key, view);
|
|
1174
|
+
return view;
|
|
1175
|
+
},
|
|
1176
|
+
scan(initial2, step) {
|
|
1177
|
+
return node(
|
|
1178
|
+
[core.delta],
|
|
1179
|
+
(ctx) => {
|
|
1180
|
+
const st = ctx.state.get() ?? {
|
|
1181
|
+
acc: initial2,
|
|
1182
|
+
processed: 0
|
|
1183
|
+
};
|
|
1184
|
+
const all = backend.snapshot();
|
|
1185
|
+
if (all.length < st.processed || maxSize !== void 0 && all.length <= st.processed) {
|
|
1186
|
+
let acc = initial2;
|
|
1187
|
+
for (const v of all) acc = step(acc, v);
|
|
1188
|
+
st.acc = acc;
|
|
1189
|
+
st.processed = all.length;
|
|
1190
|
+
} else {
|
|
1191
|
+
for (let i = st.processed; i < all.length; i++) st.acc = step(st.acc, all[i]);
|
|
1192
|
+
st.processed = all.length;
|
|
1193
|
+
}
|
|
1194
|
+
ctx.state.set(st);
|
|
1195
|
+
ctx.down([["DATA", st.acc]]);
|
|
1196
|
+
},
|
|
1197
|
+
{ ...base, factory: "reactiveLog.scan", partial: true }
|
|
1198
|
+
);
|
|
1199
|
+
},
|
|
1200
|
+
attach(src) {
|
|
1201
|
+
const dispose = core.bindSource(src, (value) => {
|
|
1202
|
+
rejectUndefined(value, "reactiveLog.attach");
|
|
1203
|
+
backend.append(value);
|
|
1204
|
+
core.emit({ kind: "append", value });
|
|
1205
|
+
});
|
|
1206
|
+
binds.push(dispose);
|
|
1207
|
+
return dispose;
|
|
1208
|
+
},
|
|
1209
|
+
dispose() {
|
|
1210
|
+
for (const d of binds) d();
|
|
1211
|
+
binds.length = 0;
|
|
1212
|
+
tailMemo.clear();
|
|
1213
|
+
sliceMemo.clear();
|
|
1214
|
+
pageMemo.disposeAll();
|
|
1215
|
+
}
|
|
1216
|
+
};
|
|
1217
|
+
}
|
|
1218
|
+
function mergeReactiveLogs(logs) {
|
|
1219
|
+
const deps = logs.map((l) => l.delta);
|
|
1220
|
+
return node(
|
|
1221
|
+
deps,
|
|
1222
|
+
(ctx) => {
|
|
1223
|
+
for (let i = 0; i < depCount(ctx); i++) {
|
|
1224
|
+
const b = depBatch(ctx, i);
|
|
1225
|
+
if (b) for (const c of b) ctx.down([["DATA", c]]);
|
|
1226
|
+
}
|
|
1227
|
+
},
|
|
1228
|
+
{ factory: "mergeReactiveLogs", partial: true }
|
|
1229
|
+
);
|
|
1230
|
+
}
|
|
1231
|
+
function scanLog(log, initial, step) {
|
|
1232
|
+
return log.scan(initial, step);
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
// src/graph/data-structures/reactive-map.ts
|
|
1236
|
+
function strictJsonIdentity(value) {
|
|
1237
|
+
return Array.from(strictCanonicalJsonBytes(value)).join(",");
|
|
1238
|
+
}
|
|
1239
|
+
var MapBackend = class {
|
|
1240
|
+
_version = 0;
|
|
1241
|
+
store = /* @__PURE__ */ new Map();
|
|
1242
|
+
now;
|
|
1243
|
+
constructor(opts) {
|
|
1244
|
+
this.now = opts.now ?? Date.now;
|
|
1245
|
+
}
|
|
1246
|
+
get version() {
|
|
1247
|
+
return this._version;
|
|
1248
|
+
}
|
|
1249
|
+
get size() {
|
|
1250
|
+
return this.store.size;
|
|
1251
|
+
}
|
|
1252
|
+
nowMs() {
|
|
1253
|
+
return this.now();
|
|
1254
|
+
}
|
|
1255
|
+
expiresAtOf(key) {
|
|
1256
|
+
return this.store.get(key)?.expiresAt;
|
|
1257
|
+
}
|
|
1258
|
+
isExpired(e) {
|
|
1259
|
+
return e.expiresAt !== void 0 && this.now() >= e.expiresAt;
|
|
1260
|
+
}
|
|
1261
|
+
resolveExpiresAt(ttl) {
|
|
1262
|
+
if (ttl === void 0) return void 0;
|
|
1263
|
+
if (!Number.isFinite(ttl) || ttl <= 0)
|
|
1264
|
+
throw new RangeError(`reactiveMap: ttl must be a positive finite number (got ${ttl})`);
|
|
1265
|
+
return this.now() + ttl;
|
|
1266
|
+
}
|
|
1267
|
+
deleteExpired(key, e) {
|
|
1268
|
+
this.store.delete(key);
|
|
1269
|
+
this._version += 1;
|
|
1270
|
+
return [[key, e.value]];
|
|
1271
|
+
}
|
|
1272
|
+
/** Read without materializing expiry. Caller routes expired deletes through the apply node (D68). */
|
|
1273
|
+
lookup(key) {
|
|
1274
|
+
const e = this.store.get(key);
|
|
1275
|
+
if (e === void 0) return { found: false };
|
|
1276
|
+
if (this.isExpired(e)) return { found: false, expired: true, previous: e.value };
|
|
1277
|
+
this.store.delete(key);
|
|
1278
|
+
this.store.set(key, e);
|
|
1279
|
+
return { found: true, value: e.value };
|
|
1280
|
+
}
|
|
1281
|
+
/** Set; returns the entries evicted by LRU overflow (the caller emits their delete deltas). */
|
|
1282
|
+
set(key, value, expiresAt) {
|
|
1283
|
+
if (this.store.has(key)) this.store.delete(key);
|
|
1284
|
+
this.store.set(key, { value, expiresAt });
|
|
1285
|
+
this._version += 1;
|
|
1286
|
+
}
|
|
1287
|
+
enforceLru(maxSize) {
|
|
1288
|
+
const evicted = [];
|
|
1289
|
+
for (const oldest of trimHeadOverflow(lruKeys(this.store.keys()).keys(), {
|
|
1290
|
+
maxSize,
|
|
1291
|
+
size: this.store.size
|
|
1292
|
+
})) {
|
|
1293
|
+
const e = this.store.get(oldest);
|
|
1294
|
+
if (e !== void 0) evicted.push([oldest, e.value]);
|
|
1295
|
+
this.store.delete(oldest);
|
|
1296
|
+
}
|
|
1297
|
+
if (evicted.length > 0) this._version += 1;
|
|
1298
|
+
return evicted;
|
|
1299
|
+
}
|
|
1300
|
+
enforceRetention(policy) {
|
|
1301
|
+
if (policy === void 0 || policy.maxSize === void 0) return [];
|
|
1302
|
+
const scored = [];
|
|
1303
|
+
for (const [key, entry] of this.store) {
|
|
1304
|
+
if (!this.isExpired(entry)) {
|
|
1305
|
+
scored.push({
|
|
1306
|
+
entry: [key, entry.value],
|
|
1307
|
+
score: policy.score({ key, value: entry.value })
|
|
1308
|
+
});
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
const archived = selectRetentionVictims(scored, { maxSize: policy.maxSize });
|
|
1312
|
+
for (const [key] of archived) this.store.delete(key);
|
|
1313
|
+
if (archived.length > 0) this._version += 1;
|
|
1314
|
+
return archived.map(([key, value]) => [key, value]);
|
|
1315
|
+
}
|
|
1316
|
+
delete(key) {
|
|
1317
|
+
const e = this.store.get(key);
|
|
1318
|
+
if (e === void 0) return { found: false };
|
|
1319
|
+
this.store.delete(key);
|
|
1320
|
+
this._version += 1;
|
|
1321
|
+
return { found: true, value: e.value };
|
|
1322
|
+
}
|
|
1323
|
+
clear() {
|
|
1324
|
+
const n = this.store.size;
|
|
1325
|
+
if (n === 0) return 0;
|
|
1326
|
+
this.store.clear();
|
|
1327
|
+
this._version += 1;
|
|
1328
|
+
return n;
|
|
1329
|
+
}
|
|
1330
|
+
pruneExpired() {
|
|
1331
|
+
const removed = [];
|
|
1332
|
+
for (const [k, e] of this.store) {
|
|
1333
|
+
if (this.isExpired(e)) {
|
|
1334
|
+
this.store.delete(k);
|
|
1335
|
+
removed.push([k, e.value]);
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
if (removed.length > 0) this._version += 1;
|
|
1339
|
+
return removed;
|
|
1340
|
+
}
|
|
1341
|
+
pruneKeyIfExpired(key) {
|
|
1342
|
+
const e = this.store.get(key);
|
|
1343
|
+
if (e === void 0 || !this.isExpired(e)) return [];
|
|
1344
|
+
return this.deleteExpired(key, e);
|
|
1345
|
+
}
|
|
1346
|
+
/** Fresh snapshot of live entries. Does not prune; callers choose whether to materialize expiry. */
|
|
1347
|
+
snapshot() {
|
|
1348
|
+
const out = /* @__PURE__ */ new Map();
|
|
1349
|
+
for (const [k, e] of this.store) if (!this.isExpired(e)) out.set(k, e.value);
|
|
1350
|
+
return out;
|
|
1351
|
+
}
|
|
1352
|
+
/** D160 checkpoint payload: exact restorable map entries, excluding TTL-bearing state. */
|
|
1353
|
+
checkpointEntries() {
|
|
1354
|
+
const out = [];
|
|
1355
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1356
|
+
for (const [key, entry] of this.store) {
|
|
1357
|
+
if (entry.expiresAt !== void 0) {
|
|
1358
|
+
throw new TypeError(
|
|
1359
|
+
"reactiveMap checkpoint backendState cannot preserve per-entry TTL; persist the map externally or clear TTL state before graph checkpoint (D160)"
|
|
1360
|
+
);
|
|
1361
|
+
}
|
|
1362
|
+
const stableKey = strictJsonIdentity(key);
|
|
1363
|
+
if (seen.has(stableKey)) {
|
|
1364
|
+
throw new TypeError(
|
|
1365
|
+
"reactiveMap checkpoint backendState contains duplicate strict-JSON keys (D160)"
|
|
1366
|
+
);
|
|
1367
|
+
}
|
|
1368
|
+
seen.add(stableKey);
|
|
1369
|
+
out.push([key, entry.value]);
|
|
1370
|
+
}
|
|
1371
|
+
return out;
|
|
1372
|
+
}
|
|
1373
|
+
};
|
|
1374
|
+
function reactiveMap(options = {}) {
|
|
1375
|
+
return createReactiveMap(options);
|
|
1376
|
+
}
|
|
1377
|
+
function restoreReactiveMapFromBackendState(initialEntries, options = {}) {
|
|
1378
|
+
return createReactiveMap(options, initialEntries);
|
|
1379
|
+
}
|
|
1380
|
+
function createReactiveMap(options = {}, initialEntries = []) {
|
|
1381
|
+
const { maxSize, defaultTtl, retention, viewCache, now, name, dispatcher, graph } = options;
|
|
1382
|
+
const backend = new MapBackend({ now });
|
|
1383
|
+
for (const [key, value] of initialEntries) backend.set(key, value);
|
|
1384
|
+
const base = dispatcher ? { dispatcher } : {};
|
|
1385
|
+
const restorable = graph !== void 0 && name !== void 0 && maxSize === void 0 && defaultTtl === void 0 && retention === void 0;
|
|
1386
|
+
function isNodeOpt(x) {
|
|
1387
|
+
return x instanceof Node;
|
|
1388
|
+
}
|
|
1389
|
+
function validateMaxSize(v) {
|
|
1390
|
+
if (!Number.isFinite(v) || !Number.isInteger(v) || v < 1)
|
|
1391
|
+
throw new RangeError(`reactiveMap: maxSize must be a positive integer (got ${v})`);
|
|
1392
|
+
return v;
|
|
1393
|
+
}
|
|
1394
|
+
function validateTtl(v) {
|
|
1395
|
+
if (!Number.isFinite(v) || v <= 0)
|
|
1396
|
+
throw new RangeError(`reactiveMap: defaultTtl must be a positive finite number (got ${v})`);
|
|
1397
|
+
return v;
|
|
1398
|
+
}
|
|
1399
|
+
function validateRetentionMaxSize(v) {
|
|
1400
|
+
if (!Number.isFinite(v) || !Number.isInteger(v) || v < 0)
|
|
1401
|
+
throw new RangeError(
|
|
1402
|
+
`reactiveMap: retention.maxSize must be a non-negative integer (got ${v})`
|
|
1403
|
+
);
|
|
1404
|
+
return v;
|
|
1405
|
+
}
|
|
1406
|
+
if (retention !== void 0 && typeof retention.score !== "function")
|
|
1407
|
+
throw new TypeError("reactiveMap: retention.score must be a function");
|
|
1408
|
+
function constPolicyNode(label, value) {
|
|
1409
|
+
const op = {
|
|
1410
|
+
factory: `reactiveMap.${label}`,
|
|
1411
|
+
body: () => {
|
|
1412
|
+
},
|
|
1413
|
+
opts: { initial: value }
|
|
1414
|
+
};
|
|
1415
|
+
if (graph) {
|
|
1416
|
+
return graph.initNode(op, [], {
|
|
1417
|
+
name: name ? `${name}.${label}` : void 0,
|
|
1418
|
+
meta: { kind: "collection_policy", collection: "reactiveMap", policy: label }
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
return new Node([], null, {
|
|
1422
|
+
...base,
|
|
1423
|
+
initial: value,
|
|
1424
|
+
factory: `reactiveMap.${label}`,
|
|
1425
|
+
name: name ? `${name}.${label}` : void 0
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1428
|
+
function policyNode(label, opt, validate) {
|
|
1429
|
+
if (opt === void 0) return void 0;
|
|
1430
|
+
if (isNodeOpt(opt)) {
|
|
1431
|
+
if (graph === void 0)
|
|
1432
|
+
throw new Error(
|
|
1433
|
+
`reactiveMap ${label} Node option requires options.graph so the policy edge is describe-visible (${label === "retentionPolicy" ? "D72" : "D68"})`
|
|
1434
|
+
);
|
|
1435
|
+
return opt;
|
|
1436
|
+
}
|
|
1437
|
+
return constPolicyNode(label, validate(opt));
|
|
1438
|
+
}
|
|
1439
|
+
const intentOp = {
|
|
1440
|
+
factory: "reactiveMap.intent",
|
|
1441
|
+
body: () => {
|
|
1442
|
+
}
|
|
1443
|
+
};
|
|
1444
|
+
const intent = graph ? graph.initNode(intentOp, [], {
|
|
1445
|
+
name: name ? `${name}.intent` : void 0,
|
|
1446
|
+
meta: { kind: "collection_intent", collection: "reactiveMap" },
|
|
1447
|
+
...restorable ? { restore: { ref: "reactiveMap.intent" } } : {}
|
|
1448
|
+
}) : new Node([], null, {
|
|
1449
|
+
...base,
|
|
1450
|
+
factory: "reactiveMap.intent",
|
|
1451
|
+
name: name ? `${name}.intent` : void 0
|
|
1452
|
+
});
|
|
1453
|
+
const lruPolicy = policyNode("lruPolicy", maxSize, validateMaxSize);
|
|
1454
|
+
const ttlPolicy = policyNode("ttlPolicy", defaultTtl, validateTtl);
|
|
1455
|
+
const retentionPolicy = policyNode(
|
|
1456
|
+
"retentionPolicy",
|
|
1457
|
+
retention?.maxSize,
|
|
1458
|
+
validateRetentionMaxSize
|
|
1459
|
+
);
|
|
1460
|
+
let currentMaxSize = isNodeOpt(maxSize) ? void 0 : maxSize;
|
|
1461
|
+
let currentDefaultTtl = isNodeOpt(defaultTtl) ? void 0 : defaultTtl;
|
|
1462
|
+
let currentRetentionMaxSize = isNodeOpt(retention?.maxSize) ? void 0 : retention?.maxSize === void 0 ? void 0 : validateRetentionMaxSize(retention.maxSize);
|
|
1463
|
+
const ttlHeap = deadlines();
|
|
1464
|
+
let ttlTimer = null;
|
|
1465
|
+
let ttlTimerDue;
|
|
1466
|
+
const bindDeps = /* @__PURE__ */ new WeakSet();
|
|
1467
|
+
let bindSeq = 0;
|
|
1468
|
+
let apply;
|
|
1469
|
+
const selectMemo = new ViewMemoCache(viewCache);
|
|
1470
|
+
let selectSeq = 0;
|
|
1471
|
+
const policyInputs = new PolicyInputs([intent]);
|
|
1472
|
+
const lruReader = policyInputs.add(lruPolicy);
|
|
1473
|
+
const ttlReader = policyInputs.add(ttlPolicy);
|
|
1474
|
+
const retentionReader = policyInputs.add(retentionPolicy);
|
|
1475
|
+
function emitExpired(ctx, entries) {
|
|
1476
|
+
for (const [key, previous] of entries)
|
|
1477
|
+
ctx.down([["DATA", { kind: "delete", key, previous, reason: "expired" }]]);
|
|
1478
|
+
}
|
|
1479
|
+
function emitLruEvicted(ctx, entries) {
|
|
1480
|
+
for (const [key, previous] of entries)
|
|
1481
|
+
ctx.down([["DATA", { kind: "delete", key, previous, reason: "lru-evict" }]]);
|
|
1482
|
+
}
|
|
1483
|
+
function emitArchived(ctx, entries) {
|
|
1484
|
+
for (const [key, previous] of entries)
|
|
1485
|
+
ctx.down([["DATA", { kind: "delete", key, previous, reason: "archived" }]]);
|
|
1486
|
+
}
|
|
1487
|
+
function nextValidExpiry() {
|
|
1488
|
+
for (; ; ) {
|
|
1489
|
+
const top = ttlHeap.peek();
|
|
1490
|
+
if (top === void 0) return void 0;
|
|
1491
|
+
if (backend.expiresAtOf(top.key) === top.expiresAt) return top;
|
|
1492
|
+
ttlHeap.pop();
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
function scheduleTtl(ctx, body) {
|
|
1496
|
+
for (; ; ) {
|
|
1497
|
+
const next = nextValidExpiry();
|
|
1498
|
+
if (next === void 0) {
|
|
1499
|
+
if (ttlTimer) ctx.rewireNext.unsubscribeDep(ttlTimer, body);
|
|
1500
|
+
ttlTimer = null;
|
|
1501
|
+
ttlTimerDue = void 0;
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1504
|
+
if (next.expiresAt <= backend.nowMs()) {
|
|
1505
|
+
emitExpired(ctx, backend.pruneExpired());
|
|
1506
|
+
continue;
|
|
1507
|
+
}
|
|
1508
|
+
if (ttlTimerDue === next.expiresAt) return;
|
|
1509
|
+
if (ttlTimer) ctx.rewireNext.unsubscribeDep(ttlTimer, body);
|
|
1510
|
+
ttlTimerDue = next.expiresAt;
|
|
1511
|
+
ttlTimer = initNode(timer(Math.max(0, next.expiresAt - backend.nowMs())), [], base);
|
|
1512
|
+
ctx.rewireNext.subscribeDep(ttlTimer, body);
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
function applyIntent(ctx, intentValue) {
|
|
1517
|
+
if (intentValue.kind === "set") {
|
|
1518
|
+
const ttl = intentValue.ttl ?? currentDefaultTtl;
|
|
1519
|
+
const expiresAt = backend.resolveExpiresAt(ttl);
|
|
1520
|
+
backend.set(intentValue.key, intentValue.value, expiresAt);
|
|
1521
|
+
if (expiresAt !== void 0) ttlHeap.push({ key: intentValue.key, expiresAt });
|
|
1522
|
+
ctx.down([["DATA", { kind: "set", key: intentValue.key, value: intentValue.value }]]);
|
|
1523
|
+
emitLruEvicted(ctx, backend.enforceLru(currentMaxSize));
|
|
1524
|
+
emitArchived(
|
|
1525
|
+
ctx,
|
|
1526
|
+
backend.enforceRetention(
|
|
1527
|
+
retention ? { maxSize: currentRetentionMaxSize, score: retention.score } : void 0
|
|
1528
|
+
)
|
|
1529
|
+
);
|
|
1530
|
+
return;
|
|
1531
|
+
}
|
|
1532
|
+
if (intentValue.kind === "delete") {
|
|
1533
|
+
const previous = backend.delete(intentValue.key);
|
|
1534
|
+
if (previous.found)
|
|
1535
|
+
ctx.down([
|
|
1536
|
+
[
|
|
1537
|
+
"DATA",
|
|
1538
|
+
{ kind: "delete", key: intentValue.key, previous: previous.value, reason: "explicit" }
|
|
1539
|
+
]
|
|
1540
|
+
]);
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
if (intentValue.kind === "clear") {
|
|
1544
|
+
const count = backend.clear();
|
|
1545
|
+
if (count > 0) ctx.down([["DATA", { kind: "clear", count }]]);
|
|
1546
|
+
return;
|
|
1547
|
+
}
|
|
1548
|
+
if (intentValue.kind === "pruneExpired") {
|
|
1549
|
+
emitExpired(ctx, backend.pruneExpired());
|
|
1550
|
+
return;
|
|
1551
|
+
}
|
|
1552
|
+
emitExpired(ctx, backend.pruneKeyIfExpired(intentValue.key));
|
|
1553
|
+
}
|
|
1554
|
+
const applyBody = (ctx) => {
|
|
1555
|
+
const nextMaxSize = lruReader.read(ctx, currentMaxSize);
|
|
1556
|
+
currentMaxSize = nextMaxSize === void 0 ? void 0 : validateMaxSize(nextMaxSize);
|
|
1557
|
+
const nextTtl = ttlReader.read(ctx, currentDefaultTtl);
|
|
1558
|
+
currentDefaultTtl = nextTtl === void 0 ? void 0 : validateTtl(nextTtl);
|
|
1559
|
+
const nextRetentionMaxSize = retentionReader.read(ctx, currentRetentionMaxSize);
|
|
1560
|
+
currentRetentionMaxSize = nextRetentionMaxSize === void 0 ? void 0 : validateRetentionMaxSize(nextRetentionMaxSize);
|
|
1561
|
+
for (const item of depBatch(ctx, 0) ?? []) {
|
|
1562
|
+
applyIntent(ctx, item);
|
|
1563
|
+
}
|
|
1564
|
+
const deps = apply.deps;
|
|
1565
|
+
for (let i = 1; i < depCount(ctx); i++) {
|
|
1566
|
+
if (i === lruReader.index || i === ttlReader.index || i === retentionReader.index) continue;
|
|
1567
|
+
const dep = deps[i];
|
|
1568
|
+
if (dep && bindDeps.has(dep)) {
|
|
1569
|
+
for (const item of depBatch(ctx, i) ?? []) {
|
|
1570
|
+
applyIntent(ctx, item);
|
|
1571
|
+
}
|
|
1572
|
+
continue;
|
|
1573
|
+
}
|
|
1574
|
+
if (dep === ttlTimer && ((depBatch(ctx, i)?.length ?? 0) > 0 || isTerminalComplete(depTerminal(ctx, i)))) {
|
|
1575
|
+
if (ttlTimer) ctx.rewireNext.unsubscribeDep(ttlTimer, applyBody);
|
|
1576
|
+
ttlTimer = null;
|
|
1577
|
+
ttlTimerDue = void 0;
|
|
1578
|
+
emitExpired(ctx, backend.pruneExpired());
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
emitLruEvicted(ctx, backend.enforceLru(currentMaxSize));
|
|
1582
|
+
emitArchived(
|
|
1583
|
+
ctx,
|
|
1584
|
+
backend.enforceRetention(
|
|
1585
|
+
retention ? { maxSize: currentRetentionMaxSize, score: retention.score } : void 0
|
|
1586
|
+
)
|
|
1587
|
+
);
|
|
1588
|
+
scheduleTtl(ctx, applyBody);
|
|
1589
|
+
};
|
|
1590
|
+
const applyOp = {
|
|
1591
|
+
factory: "reactiveMap.apply",
|
|
1592
|
+
body: applyBody,
|
|
1593
|
+
opts: { partial: true }
|
|
1594
|
+
};
|
|
1595
|
+
apply = graph ? graph.initNode(applyOp, policyInputs.deps, {
|
|
1596
|
+
name: name ? `${name}.apply` : void 0,
|
|
1597
|
+
meta: { kind: "collection_policy_apply", collection: "reactiveMap" },
|
|
1598
|
+
...restorable ? { restore: { ref: "reactiveMap.apply" } } : {}
|
|
1599
|
+
}) : initNode(applyOp, policyInputs.deps, {
|
|
1600
|
+
...base,
|
|
1601
|
+
name: name ? `${name}.apply` : void 0
|
|
1602
|
+
});
|
|
1603
|
+
const pullId = /* @__PURE__ */ Symbol(name ? `${name}.snapshot` : "reactiveMap.snapshot");
|
|
1604
|
+
const snapshotPrepOp = {
|
|
1605
|
+
factory: "reactiveMap.snapshotPrep",
|
|
1606
|
+
body: (ctx) => {
|
|
1607
|
+
const expired = backend.pruneExpired().map(
|
|
1608
|
+
([key, previous]) => ({
|
|
1609
|
+
kind: "delete",
|
|
1610
|
+
key,
|
|
1611
|
+
previous,
|
|
1612
|
+
reason: "expired"
|
|
1613
|
+
})
|
|
1614
|
+
);
|
|
1615
|
+
ctx.down([["DATA", { snapshot: backend.snapshot(), expired }]]);
|
|
1616
|
+
},
|
|
1617
|
+
opts: {
|
|
1618
|
+
...base,
|
|
1619
|
+
pullId,
|
|
1620
|
+
partial: true
|
|
1621
|
+
}
|
|
1622
|
+
};
|
|
1623
|
+
const snapshotPrep = graph ? graph.initNode(snapshotPrepOp, [apply], {
|
|
1624
|
+
name: name ? `${name}.snapshotPrep` : void 0,
|
|
1625
|
+
meta: { kind: "collection_snapshot_prep", collection: "reactiveMap" },
|
|
1626
|
+
...restorable ? { restore: { ref: "reactiveMap.snapshotPrep" } } : {}
|
|
1627
|
+
}) : initNode(snapshotPrepOp, [apply], {
|
|
1628
|
+
...base,
|
|
1629
|
+
name: name ? `${name}.snapshotPrep` : void 0
|
|
1630
|
+
});
|
|
1631
|
+
const deltaOp = {
|
|
1632
|
+
factory: "reactiveMap.delta",
|
|
1633
|
+
body: (ctx) => {
|
|
1634
|
+
for (const change of depBatch(ctx, 0) ?? []) {
|
|
1635
|
+
ctx.down([["DATA", change]]);
|
|
1636
|
+
}
|
|
1637
|
+
for (const prep of depBatch(ctx, 1) ?? []) {
|
|
1638
|
+
for (const change of prep.expired) ctx.down([["DATA", change]]);
|
|
1639
|
+
}
|
|
1640
|
+
},
|
|
1641
|
+
opts: { partial: true }
|
|
1642
|
+
};
|
|
1643
|
+
const delta = graph ? graph.initNode(deltaOp, [apply, snapshotPrep], {
|
|
1644
|
+
name: name ? `${name}.delta` : void 0,
|
|
1645
|
+
meta: { kind: "collection_delta", collection: "reactiveMap" },
|
|
1646
|
+
...restorable ? { restore: { ref: "reactiveMap.delta" } } : {}
|
|
1647
|
+
}) : initNode(deltaOp, [apply, snapshotPrep], {
|
|
1648
|
+
...base,
|
|
1649
|
+
name: name ? `${name}.delta` : void 0
|
|
1650
|
+
});
|
|
1651
|
+
const snapshotOp = {
|
|
1652
|
+
factory: "reactiveMap.snapshot",
|
|
1653
|
+
body: (ctx) => {
|
|
1654
|
+
for (const prep of depBatch(ctx, 0) ?? []) {
|
|
1655
|
+
ctx.down([["DATA", prep.snapshot]]);
|
|
1656
|
+
}
|
|
1657
|
+
},
|
|
1658
|
+
opts: { partial: true }
|
|
1659
|
+
};
|
|
1660
|
+
const snapshot = graph ? graph.initNode(snapshotOp, [snapshotPrep], {
|
|
1661
|
+
name: name ? `${name}.snapshot` : void 0,
|
|
1662
|
+
meta: { kind: "collection_snapshot", collection: "reactiveMap" },
|
|
1663
|
+
...restorable ? { restore: { ref: "reactiveMap.snapshot" } } : {}
|
|
1664
|
+
}) : initNode(snapshotOp, [snapshotPrep], {
|
|
1665
|
+
...base,
|
|
1666
|
+
name: name ? `${name}.snapshot` : void 0
|
|
1667
|
+
});
|
|
1668
|
+
if (restorable) {
|
|
1669
|
+
registerBackendStateContributor(intent, () => backend.checkpointEntries());
|
|
1670
|
+
}
|
|
1671
|
+
const releaseApply = graph ? graph.retain(apply, { reason: "reactiveMap.apply" }) : apply.subscribe(() => {
|
|
1672
|
+
});
|
|
1673
|
+
const binds = [];
|
|
1674
|
+
function doSet(key, value, ttl) {
|
|
1675
|
+
if (ttl !== void 0) validateTtl(ttl);
|
|
1676
|
+
intent.down([
|
|
1677
|
+
["DATA", ttl === void 0 ? { kind: "set", key, value } : { kind: "set", key, value, ttl }]
|
|
1678
|
+
]);
|
|
1679
|
+
}
|
|
1680
|
+
function read(key) {
|
|
1681
|
+
const r = backend.lookup(key);
|
|
1682
|
+
if (!r.found && r.expired) intent.down([["DATA", { kind: "pruneKey", key }]]);
|
|
1683
|
+
return r;
|
|
1684
|
+
}
|
|
1685
|
+
function selectedSnapshot(predicate) {
|
|
1686
|
+
const out = /* @__PURE__ */ new Map();
|
|
1687
|
+
for (const [key, value] of backend.snapshot()) {
|
|
1688
|
+
if (predicate(value, key)) out.set(key, value);
|
|
1689
|
+
}
|
|
1690
|
+
return out;
|
|
1691
|
+
}
|
|
1692
|
+
function select(predicate) {
|
|
1693
|
+
if (typeof predicate !== "function")
|
|
1694
|
+
throw new TypeError("reactiveMap.select: predicate must be a function");
|
|
1695
|
+
const cached = selectMemo.get(predicate);
|
|
1696
|
+
if (cached !== void 0) return cached;
|
|
1697
|
+
let view;
|
|
1698
|
+
view = lightReactiveView(delta, {
|
|
1699
|
+
dispatcher,
|
|
1700
|
+
graph,
|
|
1701
|
+
factory: "reactiveMap.select",
|
|
1702
|
+
name: name ? `${name}.select#${selectSeq++}` : void 0,
|
|
1703
|
+
materializeSnapshot: () => selectedSnapshot(predicate),
|
|
1704
|
+
onDispose: () => {
|
|
1705
|
+
selectMemo.deleteValue(view);
|
|
1706
|
+
}
|
|
1707
|
+
});
|
|
1708
|
+
selectMemo.set(predicate, view);
|
|
1709
|
+
return view;
|
|
1710
|
+
}
|
|
1711
|
+
return {
|
|
1712
|
+
delta,
|
|
1713
|
+
snapshot,
|
|
1714
|
+
pullId,
|
|
1715
|
+
get size() {
|
|
1716
|
+
return backend.size;
|
|
1717
|
+
},
|
|
1718
|
+
get(key) {
|
|
1719
|
+
const r = read(key);
|
|
1720
|
+
return r.found ? r.value : void 0;
|
|
1721
|
+
},
|
|
1722
|
+
has(key) {
|
|
1723
|
+
return read(key).found;
|
|
1724
|
+
},
|
|
1725
|
+
toMap() {
|
|
1726
|
+
intent.down([["DATA", { kind: "pruneExpired" }]]);
|
|
1727
|
+
return backend.snapshot();
|
|
1728
|
+
},
|
|
1729
|
+
select,
|
|
1730
|
+
set(key, value, opts) {
|
|
1731
|
+
doSet(key, value, opts?.ttl);
|
|
1732
|
+
},
|
|
1733
|
+
setMany(entries, opts) {
|
|
1734
|
+
for (const [k, v] of entries) doSet(k, v, opts?.ttl);
|
|
1735
|
+
},
|
|
1736
|
+
delete(key) {
|
|
1737
|
+
intent.down([["DATA", { kind: "delete", key }]]);
|
|
1738
|
+
},
|
|
1739
|
+
deleteMany(keys) {
|
|
1740
|
+
for (const k of keys) {
|
|
1741
|
+
intent.down([["DATA", { kind: "delete", key: k }]]);
|
|
1742
|
+
}
|
|
1743
|
+
},
|
|
1744
|
+
clear() {
|
|
1745
|
+
intent.down([["DATA", { kind: "clear" }]]);
|
|
1746
|
+
},
|
|
1747
|
+
pruneExpired() {
|
|
1748
|
+
intent.down([["DATA", { kind: "pruneExpired" }]]);
|
|
1749
|
+
},
|
|
1750
|
+
setFrom(src) {
|
|
1751
|
+
if (graph === void 0)
|
|
1752
|
+
throw new Error(
|
|
1753
|
+
"reactiveMap.setFrom requires options.graph so the input fold is describe-visible (D61)"
|
|
1754
|
+
);
|
|
1755
|
+
const op = {
|
|
1756
|
+
factory: "reactiveMap.bindSource",
|
|
1757
|
+
body: (ctx) => {
|
|
1758
|
+
try {
|
|
1759
|
+
for (const [k, v] of depBatch(ctx, 0) ?? []) {
|
|
1760
|
+
ctx.down([["DATA", { kind: "set", key: k, value: v }]]);
|
|
1761
|
+
}
|
|
1762
|
+
} catch (e) {
|
|
1763
|
+
ctx.down([["ERROR", errorPayload(e, "reactiveMap.bindSource failed")]]);
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
};
|
|
1767
|
+
const folder = graph.initNode(op, [src], {
|
|
1768
|
+
name: name ? `${name}.bind#${bindSeq++}` : void 0,
|
|
1769
|
+
meta: { kind: "collection_bind_source", collection: "reactiveMap" }
|
|
1770
|
+
});
|
|
1771
|
+
bindDeps.add(folder);
|
|
1772
|
+
apply.subscribeDep(folder, applyBody);
|
|
1773
|
+
let active = true;
|
|
1774
|
+
const dispose = () => {
|
|
1775
|
+
if (!active) return;
|
|
1776
|
+
active = false;
|
|
1777
|
+
apply.unsubscribeDep(folder, applyBody);
|
|
1778
|
+
};
|
|
1779
|
+
binds.push(dispose);
|
|
1780
|
+
return dispose;
|
|
1781
|
+
},
|
|
1782
|
+
dispose() {
|
|
1783
|
+
selectMemo.disposeAll();
|
|
1784
|
+
for (const d of binds) d();
|
|
1785
|
+
binds.length = 0;
|
|
1786
|
+
releaseApply();
|
|
1787
|
+
}
|
|
1788
|
+
};
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
// src/data-structures/persistence.ts
|
|
1792
|
+
function isListRestoreState(state) {
|
|
1793
|
+
return !Array.isArray(state);
|
|
1794
|
+
}
|
|
1795
|
+
function restoreListValues(state) {
|
|
1796
|
+
if (!isListRestoreState(state)) return state;
|
|
1797
|
+
if (state.kind !== "reactiveList") throw new TypeError("restore state kind must be reactiveList");
|
|
1798
|
+
return state.state;
|
|
1799
|
+
}
|
|
1800
|
+
function isLogRestoreState(state) {
|
|
1801
|
+
return !Array.isArray(state);
|
|
1802
|
+
}
|
|
1803
|
+
function restoreLogValues(state) {
|
|
1804
|
+
if (!isLogRestoreState(state)) return state;
|
|
1805
|
+
if (state.kind !== "reactiveLog") throw new TypeError("restore state kind must be reactiveLog");
|
|
1806
|
+
return state.state;
|
|
1807
|
+
}
|
|
1808
|
+
function isMapRestoreState(state) {
|
|
1809
|
+
return !Array.isArray(state);
|
|
1810
|
+
}
|
|
1811
|
+
function restoreMapEntries(state) {
|
|
1812
|
+
if (!isMapRestoreState(state)) return state;
|
|
1813
|
+
if (state.kind !== "reactiveMap") throw new TypeError("restore state kind must be reactiveMap");
|
|
1814
|
+
return state.state;
|
|
1815
|
+
}
|
|
1816
|
+
function isIndexRestoreState(state) {
|
|
1817
|
+
return !Array.isArray(state);
|
|
1818
|
+
}
|
|
1819
|
+
function restoreIndexRows(state) {
|
|
1820
|
+
if (!isIndexRestoreState(state)) return state;
|
|
1821
|
+
if (state.kind !== "reactiveIndex") {
|
|
1822
|
+
throw new TypeError("restore state kind must be reactiveIndex");
|
|
1823
|
+
}
|
|
1824
|
+
return state.state;
|
|
1825
|
+
}
|
|
1826
|
+
function restoreReactiveList(state, options = {}) {
|
|
1827
|
+
const values = restoreListValues(state);
|
|
1828
|
+
return reactiveList(values, options);
|
|
1829
|
+
}
|
|
1830
|
+
function restoreReactiveLog(state, options = {}) {
|
|
1831
|
+
const values = restoreLogValues(state);
|
|
1832
|
+
return reactiveLog(values, options);
|
|
1833
|
+
}
|
|
1834
|
+
function restoreReactiveMap(state, options = {}) {
|
|
1835
|
+
const entries = restoreMapEntries(state);
|
|
1836
|
+
return restoreReactiveMapFromBackendState(entries, options);
|
|
1837
|
+
}
|
|
1838
|
+
function restoreReactiveIndex(state, options = {}) {
|
|
1839
|
+
const rows = restoreIndexRows(state);
|
|
1840
|
+
return restoreReactiveIndexFromBackendState(rows, options);
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1843
|
+
export {
|
|
1844
|
+
reactiveIndex,
|
|
1845
|
+
restoreReactiveIndexFromBackendState,
|
|
1846
|
+
reactiveList,
|
|
1847
|
+
reactiveLog,
|
|
1848
|
+
mergeReactiveLogs,
|
|
1849
|
+
scanLog,
|
|
1850
|
+
reactiveMap,
|
|
1851
|
+
restoreReactiveMapFromBackendState,
|
|
1852
|
+
restoreReactiveList,
|
|
1853
|
+
restoreReactiveLog,
|
|
1854
|
+
restoreReactiveMap,
|
|
1855
|
+
restoreReactiveIndex
|
|
1856
|
+
};
|
|
1857
|
+
//# sourceMappingURL=chunk-RIIOUTGM.js.map
|