@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,741 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertNonNegativeDecimalIntegerString,
|
|
3
|
+
nowNs
|
|
4
|
+
} from "./chunk-K3FXTC3I.js";
|
|
5
|
+
import {
|
|
6
|
+
strictCanonicalJsonBytes,
|
|
7
|
+
strictJsonCodecFor
|
|
8
|
+
} from "./chunk-4VLAQHZI.js";
|
|
9
|
+
|
|
10
|
+
// src/storage/content-addressed.ts
|
|
11
|
+
var ContentAddressedMissError = class extends Error {
|
|
12
|
+
key;
|
|
13
|
+
context;
|
|
14
|
+
constructor(key, context) {
|
|
15
|
+
super(`content-addressed lookup miss in read-strict mode: ${key}`);
|
|
16
|
+
this.name = "ContentAddressedMissError";
|
|
17
|
+
this.key = key;
|
|
18
|
+
this.context = context;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var SHA_256 = "SHA-256";
|
|
22
|
+
var HEX_TABLE = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
23
|
+
function bytesToHex(bytes) {
|
|
24
|
+
let out = "";
|
|
25
|
+
for (const byte of bytes) out += HEX_TABLE[byte];
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
function sha256Hex(data) {
|
|
29
|
+
const digestInput = Uint8Array.from(data);
|
|
30
|
+
return globalThis.crypto.subtle.digest(SHA_256, digestInput).then((buf) => bytesToHex(new Uint8Array(buf)));
|
|
31
|
+
}
|
|
32
|
+
function contentAddressedKv(opts) {
|
|
33
|
+
const { kv, keyContext, keyPrefix, mode = "read-write" } = opts;
|
|
34
|
+
const contextForKey = keyContext ?? ((ctx) => ctx);
|
|
35
|
+
function keyFor(ctx) {
|
|
36
|
+
let bytes;
|
|
37
|
+
try {
|
|
38
|
+
bytes = strictCanonicalJsonBytes(contextForKey(ctx));
|
|
39
|
+
} catch (err) {
|
|
40
|
+
return Promise.resolve().then(() => {
|
|
41
|
+
throw err;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return Promise.resolve().then(() => sha256Hex(bytes)).then((hex) => keyPrefix ? `${keyPrefix}:${hex}` : hex);
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
keyFor,
|
|
48
|
+
lookup(ctx) {
|
|
49
|
+
if (mode === "write") return Promise.resolve(void 0);
|
|
50
|
+
return keyFor(ctx).then(
|
|
51
|
+
(key) => kv.get(key).then((value) => {
|
|
52
|
+
if (value === void 0 && mode === "read-strict") {
|
|
53
|
+
throw new ContentAddressedMissError(key, ctx);
|
|
54
|
+
}
|
|
55
|
+
return value;
|
|
56
|
+
})
|
|
57
|
+
);
|
|
58
|
+
},
|
|
59
|
+
store(ctx, value) {
|
|
60
|
+
if (mode === "read") return Promise.resolve();
|
|
61
|
+
return keyFor(ctx).then((key) => kv.set(key, value));
|
|
62
|
+
},
|
|
63
|
+
forget(ctx) {
|
|
64
|
+
if (mode === "read" || mode === "write") return Promise.resolve();
|
|
65
|
+
return keyFor(ctx).then((key) => kv.delete(key));
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function contentAddressedStorage(opts) {
|
|
70
|
+
return contentAddressedKv(opts);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/storage/reactive-collection.ts
|
|
74
|
+
var REACTIVE_COLLECTION_SNAPSHOT_FORMAT = "graphrefly.reactive-collection.snapshot.v1";
|
|
75
|
+
var REACTIVE_COLLECTION_CHANGE_FORMAT = "graphrefly.reactive-collection.change.v1";
|
|
76
|
+
var REACTIVE_COLLECTION_FRAME_VERSION = 1;
|
|
77
|
+
function isRecord(value) {
|
|
78
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
79
|
+
}
|
|
80
|
+
function ownKeys(value) {
|
|
81
|
+
return Object.keys(value).sort();
|
|
82
|
+
}
|
|
83
|
+
function assertKeys(value, expected, label) {
|
|
84
|
+
const actual = ownKeys(value);
|
|
85
|
+
const want = [...expected].sort();
|
|
86
|
+
if (actual.length !== want.length || actual.some((key, i) => key !== want[i])) {
|
|
87
|
+
throw new TypeError(`${label}: unexpected frame fields ${actual.join(",")}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function assertSafeInteger(value, label, min = 0) {
|
|
91
|
+
if (!Number.isSafeInteger(value) || value < min) {
|
|
92
|
+
throw new TypeError(`${label} must be a safe integer >= ${min}`);
|
|
93
|
+
}
|
|
94
|
+
return value;
|
|
95
|
+
}
|
|
96
|
+
function assertKind(value, expected, label) {
|
|
97
|
+
if (value !== expected) throw new TypeError(`${label}: kind must be ${expected}`);
|
|
98
|
+
return expected;
|
|
99
|
+
}
|
|
100
|
+
function assertArray(value, label) {
|
|
101
|
+
if (!Array.isArray(value)) throw new TypeError(`${label}: snapshot must be an array`);
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
104
|
+
function strictJsonIdentity(value) {
|
|
105
|
+
return Array.from(strictCanonicalJsonBytes(value)).join(",");
|
|
106
|
+
}
|
|
107
|
+
function assertEntryArray(value, label) {
|
|
108
|
+
const entries = assertArray(value, label);
|
|
109
|
+
const seen = /* @__PURE__ */ new Set();
|
|
110
|
+
for (const [i, entry] of entries.entries()) {
|
|
111
|
+
if (!Array.isArray(entry) || entry.length !== 2) {
|
|
112
|
+
throw new TypeError(`${label}: entry ${i} must be [key,value]`);
|
|
113
|
+
}
|
|
114
|
+
const key = strictJsonIdentity(entry[0]);
|
|
115
|
+
if (seen.has(key)) throw new TypeError(`${label}: entry ${i} duplicates an earlier key`);
|
|
116
|
+
seen.add(key);
|
|
117
|
+
}
|
|
118
|
+
return entries;
|
|
119
|
+
}
|
|
120
|
+
function assertIndexRows(value, label) {
|
|
121
|
+
const rows = assertArray(value, label);
|
|
122
|
+
const seen = /* @__PURE__ */ new Set();
|
|
123
|
+
for (const [i, row] of rows.entries()) {
|
|
124
|
+
if (!isRecord(row)) throw new TypeError(`${label}: row ${i} must be an object`);
|
|
125
|
+
assertKeys(row, ["primary", "secondary", "value"], `${label} row`);
|
|
126
|
+
const primary = strictJsonIdentity(row.primary);
|
|
127
|
+
if (seen.has(primary)) {
|
|
128
|
+
throw new TypeError(`${label}: row ${i} duplicates an earlier primary`);
|
|
129
|
+
}
|
|
130
|
+
seen.add(primary);
|
|
131
|
+
}
|
|
132
|
+
return rows;
|
|
133
|
+
}
|
|
134
|
+
function collectionSnapshotKey(storagePrefix = "reactive-collection") {
|
|
135
|
+
if (storagePrefix.length === 0) throw new TypeError("storagePrefix must be non-empty");
|
|
136
|
+
return `${storagePrefix}/snapshot`;
|
|
137
|
+
}
|
|
138
|
+
function reactiveCollectionSnapshotFrame(kind, snapshot, opts = {}) {
|
|
139
|
+
const changeCursor = opts.changeCursor ?? -1;
|
|
140
|
+
if (!Number.isSafeInteger(changeCursor) || changeCursor < -1) {
|
|
141
|
+
throw new RangeError("reactive collection snapshot changeCursor must be a safe integer >= -1");
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
format: REACTIVE_COLLECTION_SNAPSHOT_FORMAT,
|
|
145
|
+
version: REACTIVE_COLLECTION_FRAME_VERSION,
|
|
146
|
+
kind,
|
|
147
|
+
changeCursor,
|
|
148
|
+
snapshot
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function reactiveCollectionChangeFrame(kind, change) {
|
|
152
|
+
return {
|
|
153
|
+
format: REACTIVE_COLLECTION_CHANGE_FORMAT,
|
|
154
|
+
version: REACTIVE_COLLECTION_FRAME_VERSION,
|
|
155
|
+
kind,
|
|
156
|
+
change
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function assertReactiveCollectionSnapshotFrame(value, expectedKind) {
|
|
160
|
+
if (!isRecord(value)) throw new TypeError("reactive collection snapshot frame must be an object");
|
|
161
|
+
assertKeys(value, ["changeCursor", "format", "kind", "snapshot", "version"], "snapshot frame");
|
|
162
|
+
if (value.format !== REACTIVE_COLLECTION_SNAPSHOT_FORMAT) {
|
|
163
|
+
throw new TypeError("snapshot frame: invalid format");
|
|
164
|
+
}
|
|
165
|
+
if (value.version !== REACTIVE_COLLECTION_FRAME_VERSION) {
|
|
166
|
+
throw new TypeError("snapshot frame: invalid version");
|
|
167
|
+
}
|
|
168
|
+
assertKind(value.kind, expectedKind, "snapshot frame");
|
|
169
|
+
assertSafeInteger(value.changeCursor, "snapshot frame changeCursor", -1);
|
|
170
|
+
strictJsonCodecFor().encode(value);
|
|
171
|
+
return value;
|
|
172
|
+
}
|
|
173
|
+
function assertReactiveCollectionChangeFrame(value, expectedKind) {
|
|
174
|
+
if (!isRecord(value)) throw new TypeError("reactive collection change frame must be an object");
|
|
175
|
+
assertKeys(value, ["change", "format", "kind", "version"], "change frame");
|
|
176
|
+
if (value.format !== REACTIVE_COLLECTION_CHANGE_FORMAT) {
|
|
177
|
+
throw new TypeError("change frame: invalid format");
|
|
178
|
+
}
|
|
179
|
+
if (value.version !== REACTIVE_COLLECTION_FRAME_VERSION) {
|
|
180
|
+
throw new TypeError("change frame: invalid version");
|
|
181
|
+
}
|
|
182
|
+
assertKind(value.kind, expectedKind, "change frame");
|
|
183
|
+
if (!Object.hasOwn(value, "change")) throw new TypeError("change frame: change is required");
|
|
184
|
+
strictJsonCodecFor().encode(value);
|
|
185
|
+
return value;
|
|
186
|
+
}
|
|
187
|
+
function reactiveCollectionSnapshotFrameCodec(kind) {
|
|
188
|
+
const codec = strictJsonCodecFor();
|
|
189
|
+
return {
|
|
190
|
+
encode(value) {
|
|
191
|
+
return codec.encode(assertReactiveCollectionSnapshotFrame(value, kind));
|
|
192
|
+
},
|
|
193
|
+
decode(bytes) {
|
|
194
|
+
return assertReactiveCollectionSnapshotFrame(codec.decode(bytes), kind);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function reactiveCollectionChangeFrameCodec(kind) {
|
|
199
|
+
const codec = strictJsonCodecFor();
|
|
200
|
+
return {
|
|
201
|
+
encode(value) {
|
|
202
|
+
return codec.encode(assertReactiveCollectionChangeFrame(value, kind));
|
|
203
|
+
},
|
|
204
|
+
decode(bytes) {
|
|
205
|
+
return assertReactiveCollectionChangeFrame(codec.decode(bytes), kind);
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function assertListChange(value) {
|
|
210
|
+
if (!isRecord(value) || typeof value.kind !== "string") {
|
|
211
|
+
throw new TypeError("reactiveList change must be an object with kind");
|
|
212
|
+
}
|
|
213
|
+
switch (value.kind) {
|
|
214
|
+
case "append":
|
|
215
|
+
if (!Object.hasOwn(value, "value")) throw new TypeError("reactiveList append.value required");
|
|
216
|
+
assertKeys(value, ["kind", "value"], "reactiveList append");
|
|
217
|
+
return value;
|
|
218
|
+
case "appendMany":
|
|
219
|
+
assertKeys(value, ["kind", "values"], "reactiveList appendMany");
|
|
220
|
+
assertArray(value.values, "reactiveList appendMany.values");
|
|
221
|
+
return value;
|
|
222
|
+
case "insert":
|
|
223
|
+
assertKeys(value, ["index", "kind", "value"], "reactiveList insert");
|
|
224
|
+
assertSafeInteger(value.index, "reactiveList insert.index", 0);
|
|
225
|
+
return value;
|
|
226
|
+
case "insertMany":
|
|
227
|
+
assertKeys(value, ["index", "kind", "values"], "reactiveList insertMany");
|
|
228
|
+
assertSafeInteger(value.index, "reactiveList insertMany.index", 0);
|
|
229
|
+
assertArray(value.values, "reactiveList insertMany.values");
|
|
230
|
+
return value;
|
|
231
|
+
case "pop":
|
|
232
|
+
assertKeys(value, ["index", "kind", "value"], "reactiveList pop");
|
|
233
|
+
assertSafeInteger(value.index, "reactiveList pop.index", 0);
|
|
234
|
+
return value;
|
|
235
|
+
case "trimHead":
|
|
236
|
+
assertKeys(value, ["kind", "n"], "reactiveList trimHead");
|
|
237
|
+
assertSafeInteger(value.n, "reactiveList trimHead.n", 0);
|
|
238
|
+
return value;
|
|
239
|
+
case "clear":
|
|
240
|
+
assertKeys(value, ["count", "kind"], "reactiveList clear");
|
|
241
|
+
assertSafeInteger(value.count, "reactiveList clear.count", 0);
|
|
242
|
+
return value;
|
|
243
|
+
default:
|
|
244
|
+
throw new TypeError(`unsupported reactiveList change kind ${value.kind}`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function assertLogChange(value) {
|
|
248
|
+
if (!isRecord(value) || typeof value.kind !== "string") {
|
|
249
|
+
throw new TypeError("reactiveLog change must be an object with kind");
|
|
250
|
+
}
|
|
251
|
+
switch (value.kind) {
|
|
252
|
+
case "append":
|
|
253
|
+
if (!Object.hasOwn(value, "value")) throw new TypeError("reactiveLog append.value required");
|
|
254
|
+
assertKeys(value, ["kind", "value"], "reactiveLog append");
|
|
255
|
+
return value;
|
|
256
|
+
case "appendMany":
|
|
257
|
+
assertKeys(value, ["kind", "values"], "reactiveLog appendMany");
|
|
258
|
+
assertArray(value.values, "reactiveLog appendMany.values");
|
|
259
|
+
return value;
|
|
260
|
+
case "trimHead":
|
|
261
|
+
assertKeys(value, ["kind", "n"], "reactiveLog trimHead");
|
|
262
|
+
assertSafeInteger(value.n, "reactiveLog trimHead.n", 0);
|
|
263
|
+
return value;
|
|
264
|
+
case "clear":
|
|
265
|
+
assertKeys(value, ["count", "kind"], "reactiveLog clear");
|
|
266
|
+
assertSafeInteger(value.count, "reactiveLog clear.count", 0);
|
|
267
|
+
return value;
|
|
268
|
+
default:
|
|
269
|
+
throw new TypeError(`unsupported reactiveLog change kind ${value.kind}`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function assertMapChange(value) {
|
|
273
|
+
if (!isRecord(value) || typeof value.kind !== "string") {
|
|
274
|
+
throw new TypeError("reactiveMap change must be an object with kind");
|
|
275
|
+
}
|
|
276
|
+
switch (value.kind) {
|
|
277
|
+
case "set":
|
|
278
|
+
if (!Object.hasOwn(value, "key")) throw new TypeError("reactiveMap set.key required");
|
|
279
|
+
if (!Object.hasOwn(value, "value")) throw new TypeError("reactiveMap set.value required");
|
|
280
|
+
assertKeys(value, ["key", "kind", "value"], "reactiveMap set");
|
|
281
|
+
return value;
|
|
282
|
+
case "delete":
|
|
283
|
+
if (!Object.hasOwn(value, "key")) throw new TypeError("reactiveMap delete.key required");
|
|
284
|
+
if (!Object.hasOwn(value, "previous")) {
|
|
285
|
+
throw new TypeError("reactiveMap delete.previous required");
|
|
286
|
+
}
|
|
287
|
+
assertKeys(value, ["key", "kind", "previous", "reason"], "reactiveMap delete");
|
|
288
|
+
if (value.reason !== "expired" && value.reason !== "lru-evict" && value.reason !== "archived" && value.reason !== "explicit") {
|
|
289
|
+
throw new TypeError("reactiveMap delete.reason is invalid");
|
|
290
|
+
}
|
|
291
|
+
return value;
|
|
292
|
+
case "clear":
|
|
293
|
+
assertKeys(value, ["count", "kind"], "reactiveMap clear");
|
|
294
|
+
assertSafeInteger(value.count, "reactiveMap clear.count", 0);
|
|
295
|
+
return value;
|
|
296
|
+
default:
|
|
297
|
+
throw new TypeError(`unsupported reactiveMap change kind ${value.kind}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
function assertIndexChange(value) {
|
|
301
|
+
if (!isRecord(value) || typeof value.kind !== "string") {
|
|
302
|
+
throw new TypeError("reactiveIndex change must be an object with kind");
|
|
303
|
+
}
|
|
304
|
+
switch (value.kind) {
|
|
305
|
+
case "upsert":
|
|
306
|
+
if (!Object.hasOwn(value, "primary")) {
|
|
307
|
+
throw new TypeError("reactiveIndex upsert.primary required");
|
|
308
|
+
}
|
|
309
|
+
if (!Object.hasOwn(value, "secondary")) {
|
|
310
|
+
throw new TypeError("reactiveIndex upsert.secondary required");
|
|
311
|
+
}
|
|
312
|
+
if (!Object.hasOwn(value, "value"))
|
|
313
|
+
throw new TypeError("reactiveIndex upsert.value required");
|
|
314
|
+
assertKeys(value, ["kind", "primary", "secondary", "value"], "reactiveIndex upsert");
|
|
315
|
+
return value;
|
|
316
|
+
case "delete":
|
|
317
|
+
if (!Object.hasOwn(value, "primary")) {
|
|
318
|
+
throw new TypeError("reactiveIndex delete.primary required");
|
|
319
|
+
}
|
|
320
|
+
assertKeys(value, ["kind", "primary"], "reactiveIndex delete");
|
|
321
|
+
return value;
|
|
322
|
+
case "deleteMany":
|
|
323
|
+
assertKeys(value, ["kind", "primaries"], "reactiveIndex deleteMany");
|
|
324
|
+
assertArray(value.primaries, "reactiveIndex deleteMany.primaries");
|
|
325
|
+
return value;
|
|
326
|
+
case "clear":
|
|
327
|
+
assertKeys(value, ["count", "kind"], "reactiveIndex clear");
|
|
328
|
+
assertSafeInteger(value.count, "reactiveIndex clear.count", 0);
|
|
329
|
+
return value;
|
|
330
|
+
default:
|
|
331
|
+
throw new TypeError(`unsupported reactiveIndex change kind ${value.kind}`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
function applyListChange(state, change) {
|
|
335
|
+
switch (change.kind) {
|
|
336
|
+
case "append":
|
|
337
|
+
state.push(change.value);
|
|
338
|
+
return;
|
|
339
|
+
case "appendMany":
|
|
340
|
+
state.push(...change.values);
|
|
341
|
+
return;
|
|
342
|
+
case "insert":
|
|
343
|
+
if (change.index > state.length)
|
|
344
|
+
throw new Error("reactiveList insert change is out of range");
|
|
345
|
+
state.splice(change.index, 0, change.value);
|
|
346
|
+
return;
|
|
347
|
+
case "insertMany":
|
|
348
|
+
if (change.index > state.length) {
|
|
349
|
+
throw new Error("reactiveList insertMany change is out of range");
|
|
350
|
+
}
|
|
351
|
+
state.splice(change.index, 0, ...change.values);
|
|
352
|
+
return;
|
|
353
|
+
case "pop":
|
|
354
|
+
if (change.index >= state.length) throw new Error("reactiveList pop change is out of range");
|
|
355
|
+
if (!strictJsonEquals(state[change.index], change.value)) {
|
|
356
|
+
throw new Error("reactiveList pop change value does not match current state");
|
|
357
|
+
}
|
|
358
|
+
state.splice(change.index, 1);
|
|
359
|
+
return;
|
|
360
|
+
case "trimHead":
|
|
361
|
+
if (change.n > state.length) throw new Error("reactiveList trimHead change is out of range");
|
|
362
|
+
state.splice(0, change.n);
|
|
363
|
+
return;
|
|
364
|
+
case "clear":
|
|
365
|
+
if (change.count !== state.length) {
|
|
366
|
+
throw new Error("reactiveList clear change count does not match current state");
|
|
367
|
+
}
|
|
368
|
+
state.length = 0;
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
function strictJsonEquals(a, b) {
|
|
373
|
+
const left = strictCanonicalJsonBytes(a);
|
|
374
|
+
const right = strictCanonicalJsonBytes(b);
|
|
375
|
+
if (left.byteLength !== right.byteLength) return false;
|
|
376
|
+
for (let i = 0; i < left.byteLength; i += 1) if (left[i] !== right[i]) return false;
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
379
|
+
function findJsonIndex(values, match, key, label) {
|
|
380
|
+
let found = -1;
|
|
381
|
+
for (let i = 0; i < values.length; i += 1) {
|
|
382
|
+
if (strictJsonEquals(match(values[i]), key)) {
|
|
383
|
+
if (found !== -1) throw new Error(`${label} duplicate JSON key in restore state`);
|
|
384
|
+
found = i;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return found;
|
|
388
|
+
}
|
|
389
|
+
function cmpOrd(a, b) {
|
|
390
|
+
if (a === b) return 0;
|
|
391
|
+
const ta = typeof a;
|
|
392
|
+
if (ta === typeof b && (ta === "number" || ta === "string" || ta === "boolean" || ta === "bigint")) {
|
|
393
|
+
const ax = a;
|
|
394
|
+
const bx = b;
|
|
395
|
+
return ax < bx ? -1 : ax > bx ? 1 : 0;
|
|
396
|
+
}
|
|
397
|
+
return String(a).localeCompare(String(b));
|
|
398
|
+
}
|
|
399
|
+
function applyLogChange(state, change) {
|
|
400
|
+
switch (change.kind) {
|
|
401
|
+
case "append":
|
|
402
|
+
state.push(change.value);
|
|
403
|
+
return;
|
|
404
|
+
case "appendMany":
|
|
405
|
+
state.push(...change.values);
|
|
406
|
+
return;
|
|
407
|
+
case "trimHead":
|
|
408
|
+
if (change.n > state.length) throw new Error("reactiveLog trimHead change is out of range");
|
|
409
|
+
state.splice(0, change.n);
|
|
410
|
+
return;
|
|
411
|
+
case "clear":
|
|
412
|
+
if (change.count !== state.length) {
|
|
413
|
+
throw new Error("reactiveLog clear change count does not match current state");
|
|
414
|
+
}
|
|
415
|
+
state.length = 0;
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
function applyMapChange(state, change) {
|
|
420
|
+
switch (change.kind) {
|
|
421
|
+
case "set": {
|
|
422
|
+
const index = findJsonIndex(state, ([key]) => key, change.key, "reactiveMap");
|
|
423
|
+
if (index === -1) state.push([change.key, change.value]);
|
|
424
|
+
else state[index] = [change.key, change.value];
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
case "delete": {
|
|
428
|
+
const index = findJsonIndex(state, ([key]) => key, change.key, "reactiveMap");
|
|
429
|
+
if (index === -1) throw new Error("reactiveMap delete change key is missing");
|
|
430
|
+
if (!strictJsonEquals(state[index]?.[1], change.previous)) {
|
|
431
|
+
throw new Error("reactiveMap delete change previous value does not match current state");
|
|
432
|
+
}
|
|
433
|
+
state.splice(index, 1);
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
case "clear":
|
|
437
|
+
if (change.count !== state.length) {
|
|
438
|
+
throw new Error("reactiveMap clear change count does not match current state");
|
|
439
|
+
}
|
|
440
|
+
state.length = 0;
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
function sortIndexRows(state) {
|
|
445
|
+
state.sort((a, b) => {
|
|
446
|
+
const bySecondary = cmpOrd(a.secondary, b.secondary);
|
|
447
|
+
return bySecondary === 0 ? cmpOrd(a.primary, b.primary) : bySecondary;
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
function applyIndexChange(state, change) {
|
|
451
|
+
switch (change.kind) {
|
|
452
|
+
case "upsert": {
|
|
453
|
+
const index = findJsonIndex(state, (row2) => row2.primary, change.primary, "reactiveIndex");
|
|
454
|
+
const row = {
|
|
455
|
+
primary: change.primary,
|
|
456
|
+
secondary: change.secondary,
|
|
457
|
+
value: change.value
|
|
458
|
+
};
|
|
459
|
+
if (index === -1) state.push(row);
|
|
460
|
+
else state[index] = row;
|
|
461
|
+
sortIndexRows(state);
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
case "delete": {
|
|
465
|
+
const index = findJsonIndex(state, (row) => row.primary, change.primary, "reactiveIndex");
|
|
466
|
+
if (index === -1) throw new Error("reactiveIndex delete change primary is missing");
|
|
467
|
+
state.splice(index, 1);
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
case "deleteMany": {
|
|
471
|
+
for (const primary of change.primaries) {
|
|
472
|
+
const index = findJsonIndex(state, (row) => row.primary, primary, "reactiveIndex");
|
|
473
|
+
if (index === -1) {
|
|
474
|
+
throw new Error("reactiveIndex deleteMany change primary is missing");
|
|
475
|
+
}
|
|
476
|
+
state.splice(index, 1);
|
|
477
|
+
}
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
case "clear":
|
|
481
|
+
if (change.count !== state.length) {
|
|
482
|
+
throw new Error("reactiveIndex clear change count does not match current state");
|
|
483
|
+
}
|
|
484
|
+
state.length = 0;
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
function finishState(kind, state, snapshotFound, snapshotCursor, applied, cursor) {
|
|
489
|
+
return {
|
|
490
|
+
kind,
|
|
491
|
+
state,
|
|
492
|
+
source: snapshotFound ? applied > 0 ? "snapshot+changes" : "snapshot" : applied > 0 ? "changes" : "empty",
|
|
493
|
+
snapshot: { found: snapshotFound, changeCursor: snapshotCursor },
|
|
494
|
+
changes: { applied, cursor }
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
function loadState(kind, opts, assertSnapshot, assertChange, applyChange) {
|
|
498
|
+
const key = opts.snapshotKey ?? collectionSnapshotKey(opts.storagePrefix);
|
|
499
|
+
return opts.snapshotStore.get(key).then((snapshotValue) => {
|
|
500
|
+
let snapshotFound = false;
|
|
501
|
+
let snapshotCursor = -1;
|
|
502
|
+
let state = [];
|
|
503
|
+
if (snapshotValue !== void 0) {
|
|
504
|
+
const frame = assertReactiveCollectionSnapshotFrame(snapshotValue, kind);
|
|
505
|
+
state = [...assertSnapshot(frame.snapshot)];
|
|
506
|
+
snapshotFound = true;
|
|
507
|
+
snapshotCursor = frame.changeCursor;
|
|
508
|
+
}
|
|
509
|
+
if (opts.changeLog === void 0) {
|
|
510
|
+
return finishState(kind, state, snapshotFound, snapshotCursor, 0, snapshotCursor);
|
|
511
|
+
}
|
|
512
|
+
return opts.changeLog.read({ after: snapshotCursor }).then((entries) => {
|
|
513
|
+
let applied = 0;
|
|
514
|
+
let cursor = snapshotCursor;
|
|
515
|
+
for (const entry of entries) {
|
|
516
|
+
const expectedSeq = cursor + 1;
|
|
517
|
+
if (!Number.isSafeInteger(entry.seq) || entry.seq !== expectedSeq) {
|
|
518
|
+
throw new Error(
|
|
519
|
+
`reactive collection change log is non-contiguous: expected seq ${expectedSeq}, got ${entry.seq}`
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
const frame = assertReactiveCollectionChangeFrame(entry.value, kind);
|
|
523
|
+
const change = assertChange(frame.change);
|
|
524
|
+
applyChange(state, change);
|
|
525
|
+
applied += 1;
|
|
526
|
+
cursor = entry.seq;
|
|
527
|
+
}
|
|
528
|
+
return finishState(kind, state, snapshotFound, snapshotCursor, applied, cursor);
|
|
529
|
+
});
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
function loadReactiveListState(opts) {
|
|
533
|
+
return loadState(
|
|
534
|
+
"reactiveList",
|
|
535
|
+
opts,
|
|
536
|
+
(value) => assertArray(value, "reactiveList snapshot"),
|
|
537
|
+
assertListChange,
|
|
538
|
+
applyListChange
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
function loadReactiveLogState(opts) {
|
|
542
|
+
return loadState(
|
|
543
|
+
"reactiveLog",
|
|
544
|
+
opts,
|
|
545
|
+
(value) => assertArray(value, "reactiveLog snapshot"),
|
|
546
|
+
assertLogChange,
|
|
547
|
+
applyLogChange
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
function loadReactiveMapState(opts) {
|
|
551
|
+
return loadState(
|
|
552
|
+
"reactiveMap",
|
|
553
|
+
opts,
|
|
554
|
+
(value) => assertEntryArray(value, "reactiveMap snapshot"),
|
|
555
|
+
assertMapChange,
|
|
556
|
+
applyMapChange
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
function loadReactiveIndexState(opts) {
|
|
560
|
+
return loadState(
|
|
561
|
+
"reactiveIndex",
|
|
562
|
+
opts,
|
|
563
|
+
(value) => assertIndexRows(value, "reactiveIndex snapshot"),
|
|
564
|
+
assertIndexChange,
|
|
565
|
+
applyIndexChange
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// src/storage/wal.ts
|
|
570
|
+
var WAL_KEY_SEGMENT = "wal";
|
|
571
|
+
var WAL_FRAME_SEQ_PAD = 20;
|
|
572
|
+
var WAL_FORMAT_VERSION = 1;
|
|
573
|
+
var SHA_2562 = "SHA-256";
|
|
574
|
+
var HEX_TABLE2 = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
575
|
+
var CHECKSUM_RE = /^[0-9a-f]{64}$/;
|
|
576
|
+
var WAL_BODY_KEYS = /* @__PURE__ */ new Set([
|
|
577
|
+
"t",
|
|
578
|
+
"lifecycle",
|
|
579
|
+
"path",
|
|
580
|
+
"change",
|
|
581
|
+
"frame_seq",
|
|
582
|
+
"frame_t_ns",
|
|
583
|
+
"format_version"
|
|
584
|
+
]);
|
|
585
|
+
var WAL_FRAME_KEYS = /* @__PURE__ */ new Set([...WAL_BODY_KEYS, "checksum"]);
|
|
586
|
+
function bytesToHex2(bytes) {
|
|
587
|
+
let out = "";
|
|
588
|
+
for (const byte of bytes) out += HEX_TABLE2[byte];
|
|
589
|
+
return out;
|
|
590
|
+
}
|
|
591
|
+
function sha256Hex2(data) {
|
|
592
|
+
const digestInput = Uint8Array.from(data);
|
|
593
|
+
return globalThis.crypto.subtle.digest(SHA_2562, digestInput).then((buf) => bytesToHex2(new Uint8Array(buf)));
|
|
594
|
+
}
|
|
595
|
+
function isRecord2(value) {
|
|
596
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
597
|
+
}
|
|
598
|
+
function isLifecycle(value) {
|
|
599
|
+
return value === "spec" || value === "data" || value === "ownership";
|
|
600
|
+
}
|
|
601
|
+
function assertOnlyKeys(value, allowed) {
|
|
602
|
+
for (const key of Object.keys(value)) {
|
|
603
|
+
if (!allowed.has(key)) throw new TypeError(`walFrameCodec: unknown field ${key}`);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
function assertFrameSeq(value, label) {
|
|
607
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
608
|
+
throw new TypeError(`${label} must be a non-negative safe integer`);
|
|
609
|
+
}
|
|
610
|
+
return value;
|
|
611
|
+
}
|
|
612
|
+
function assertWalFrameBody(value, allowedKeys = WAL_BODY_KEYS) {
|
|
613
|
+
if (!isRecord2(value)) throw new TypeError("walFrameCodec: frame must be an object");
|
|
614
|
+
assertOnlyKeys(value, allowedKeys);
|
|
615
|
+
if (value.t !== "c") throw new TypeError("walFrameCodec: t must be c");
|
|
616
|
+
if (!isLifecycle(value.lifecycle)) {
|
|
617
|
+
throw new TypeError("walFrameCodec: lifecycle must be spec, data, or ownership");
|
|
618
|
+
}
|
|
619
|
+
if (typeof value.path !== "string" || value.path.length === 0) {
|
|
620
|
+
throw new TypeError("walFrameCodec: path must be a non-empty string");
|
|
621
|
+
}
|
|
622
|
+
if (!Object.hasOwn(value, "change")) {
|
|
623
|
+
throw new TypeError("walFrameCodec: change payload is required");
|
|
624
|
+
}
|
|
625
|
+
const frameSeq = assertFrameSeq(value.frame_seq, "walFrameCodec: frame_seq");
|
|
626
|
+
const frameTimestamp = assertNonNegativeDecimalIntegerString(
|
|
627
|
+
value.frame_t_ns,
|
|
628
|
+
"walFrameCodec: frame_t_ns"
|
|
629
|
+
);
|
|
630
|
+
if (value.format_version !== WAL_FORMAT_VERSION) {
|
|
631
|
+
throw new TypeError(`walFrameCodec: format_version must be ${WAL_FORMAT_VERSION}`);
|
|
632
|
+
}
|
|
633
|
+
return {
|
|
634
|
+
t: "c",
|
|
635
|
+
lifecycle: value.lifecycle,
|
|
636
|
+
path: value.path,
|
|
637
|
+
change: value.change,
|
|
638
|
+
frame_seq: frameSeq,
|
|
639
|
+
frame_t_ns: frameTimestamp,
|
|
640
|
+
format_version: WAL_FORMAT_VERSION
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
function walFramePrefix(namespace) {
|
|
644
|
+
if (namespace.length === 0) return WAL_KEY_SEGMENT;
|
|
645
|
+
return `${namespace}/${WAL_KEY_SEGMENT}`;
|
|
646
|
+
}
|
|
647
|
+
function walFrameKey(prefix, frameSeq) {
|
|
648
|
+
if (!Number.isSafeInteger(frameSeq) || frameSeq < 0) {
|
|
649
|
+
throw new RangeError(
|
|
650
|
+
`walFrameKey: frameSeq must be a non-negative safe integer, got ${frameSeq}`
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
return `${prefix}/${frameSeq.toString().padStart(WAL_FRAME_SEQ_PAD, "0")}`;
|
|
654
|
+
}
|
|
655
|
+
function walFrameChecksum(body) {
|
|
656
|
+
let bytes;
|
|
657
|
+
try {
|
|
658
|
+
bytes = strictCanonicalJsonBytes(assertWalFrameBody(body));
|
|
659
|
+
} catch (err) {
|
|
660
|
+
return Promise.resolve().then(() => {
|
|
661
|
+
throw err;
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
return sha256Hex2(bytes);
|
|
665
|
+
}
|
|
666
|
+
function walFrame(opts) {
|
|
667
|
+
const body = {
|
|
668
|
+
t: "c",
|
|
669
|
+
lifecycle: opts.lifecycle ?? "data",
|
|
670
|
+
path: opts.path,
|
|
671
|
+
change: opts.change,
|
|
672
|
+
frame_seq: opts.frame_seq,
|
|
673
|
+
frame_t_ns: opts.frame_t_ns ?? nowNs(),
|
|
674
|
+
format_version: WAL_FORMAT_VERSION
|
|
675
|
+
};
|
|
676
|
+
return walFrameChecksum(body).then((checksum) => ({ ...body, checksum }));
|
|
677
|
+
}
|
|
678
|
+
function assertWalFrame(value) {
|
|
679
|
+
if (!isRecord2(value)) throw new TypeError("walFrameCodec: frame must be an object");
|
|
680
|
+
assertOnlyKeys(value, WAL_FRAME_KEYS);
|
|
681
|
+
const body = assertWalFrameBody(value, WAL_FRAME_KEYS);
|
|
682
|
+
const checksum = value.checksum;
|
|
683
|
+
if (typeof checksum !== "string" || !CHECKSUM_RE.test(checksum)) {
|
|
684
|
+
throw new TypeError("walFrameCodec: checksum must be a lowercase sha256 hex string");
|
|
685
|
+
}
|
|
686
|
+
return { ...body, checksum };
|
|
687
|
+
}
|
|
688
|
+
function verifyWalFrameChecksum(frame) {
|
|
689
|
+
let checked;
|
|
690
|
+
try {
|
|
691
|
+
checked = assertWalFrame(frame);
|
|
692
|
+
} catch (err) {
|
|
693
|
+
return Promise.resolve().then(() => {
|
|
694
|
+
throw err;
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
const { checksum, ...body } = checked;
|
|
698
|
+
return walFrameChecksum(body).then((expected) => expected === checksum);
|
|
699
|
+
}
|
|
700
|
+
function walFrameCodec() {
|
|
701
|
+
const codec = strictJsonCodecFor();
|
|
702
|
+
return {
|
|
703
|
+
encode(value) {
|
|
704
|
+
return codec.encode(assertWalFrame(value));
|
|
705
|
+
},
|
|
706
|
+
decode(bytes) {
|
|
707
|
+
return assertWalFrame(codec.decode(bytes));
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
export {
|
|
713
|
+
ContentAddressedMissError,
|
|
714
|
+
contentAddressedKv,
|
|
715
|
+
contentAddressedStorage,
|
|
716
|
+
REACTIVE_COLLECTION_SNAPSHOT_FORMAT,
|
|
717
|
+
REACTIVE_COLLECTION_CHANGE_FORMAT,
|
|
718
|
+
REACTIVE_COLLECTION_FRAME_VERSION,
|
|
719
|
+
collectionSnapshotKey,
|
|
720
|
+
reactiveCollectionSnapshotFrame,
|
|
721
|
+
reactiveCollectionChangeFrame,
|
|
722
|
+
assertReactiveCollectionSnapshotFrame,
|
|
723
|
+
assertReactiveCollectionChangeFrame,
|
|
724
|
+
reactiveCollectionSnapshotFrameCodec,
|
|
725
|
+
reactiveCollectionChangeFrameCodec,
|
|
726
|
+
loadReactiveListState,
|
|
727
|
+
loadReactiveLogState,
|
|
728
|
+
loadReactiveMapState,
|
|
729
|
+
loadReactiveIndexState,
|
|
730
|
+
WAL_KEY_SEGMENT,
|
|
731
|
+
WAL_FRAME_SEQ_PAD,
|
|
732
|
+
WAL_FORMAT_VERSION,
|
|
733
|
+
walFramePrefix,
|
|
734
|
+
walFrameKey,
|
|
735
|
+
walFrameChecksum,
|
|
736
|
+
walFrame,
|
|
737
|
+
assertWalFrame,
|
|
738
|
+
verifyWalFrameChecksum,
|
|
739
|
+
walFrameCodec
|
|
740
|
+
};
|
|
741
|
+
//# sourceMappingURL=chunk-GTPCOEOZ.js.map
|