any-store-js 0.1.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/dist/lib.es.js +668 -0
- package/dist/src/any-store.d.ts +35 -0
- package/dist/src/binary-codec.d.ts +7 -0
- package/dist/src/lib.d.ts +6 -0
- package/dist/src/row.d.ts +21 -0
- package/dist/src/table.d.ts +41 -0
- package/dist/src/types.d.ts +78 -0
- package/dist/tests/binary-codec.test.d.ts +1 -0
- package/dist/tests/lib.bench.d.ts +1 -0
- package/dist/tests/lib.test.d.ts +1 -0
- package/dist/tests/smoke.browser.test.d.ts +1 -0
- package/package.json +40 -0
package/dist/lib.es.js
ADDED
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
var ASYNC_SET_HANDLER = Symbol("row.asyncSetHandler"), DELETE_HANDLER = Symbol("row.deleteHandler"), Row = class {
|
|
2
|
+
rowID;
|
|
3
|
+
fields;
|
|
4
|
+
[ASYNC_SET_HANDLER];
|
|
5
|
+
[DELETE_HANDLER];
|
|
6
|
+
constructor(C, w, T, E) {
|
|
7
|
+
this.rowID = C, this.fields = { ...w }, Object.defineProperty(this, ASYNC_SET_HANDLER, {
|
|
8
|
+
value: T,
|
|
9
|
+
enumerable: !1,
|
|
10
|
+
configurable: !1,
|
|
11
|
+
writable: !1
|
|
12
|
+
}), Object.defineProperty(this, DELETE_HANDLER, {
|
|
13
|
+
value: E,
|
|
14
|
+
enumerable: !1,
|
|
15
|
+
configurable: !1,
|
|
16
|
+
writable: !1
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
get id() {
|
|
20
|
+
return this.rowID;
|
|
21
|
+
}
|
|
22
|
+
readField(e) {
|
|
23
|
+
return this.fields[e];
|
|
24
|
+
}
|
|
25
|
+
writeField(e, S) {
|
|
26
|
+
this.fields[e] = S;
|
|
27
|
+
}
|
|
28
|
+
async setAsync(S) {
|
|
29
|
+
await this[ASYNC_SET_HANDLER](this.rowID, S);
|
|
30
|
+
}
|
|
31
|
+
delete() {
|
|
32
|
+
return this[DELETE_HANDLER](this.rowID);
|
|
33
|
+
}
|
|
34
|
+
snapshot() {
|
|
35
|
+
return {
|
|
36
|
+
id: this.rowID,
|
|
37
|
+
...this.fields
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}, Table = class {
|
|
41
|
+
RowClass;
|
|
42
|
+
nextID = 1;
|
|
43
|
+
rowsByID = /* @__PURE__ */ new Map();
|
|
44
|
+
indexesByField = /* @__PURE__ */ new Map();
|
|
45
|
+
constructor(e, S, C) {
|
|
46
|
+
this.store = e, this.name = S, this.schema = C, this.RowClass = this.createRowClass();
|
|
47
|
+
}
|
|
48
|
+
insert(e) {
|
|
49
|
+
if (!this.store._canInsertRows()) throw Error("Cannot insert rows after replication is initialized");
|
|
50
|
+
return this.insertRow(e, !0);
|
|
51
|
+
}
|
|
52
|
+
insertRow(e, S, C, w) {
|
|
53
|
+
this.validateInput(e);
|
|
54
|
+
let T = this.tryUpsertUniqueIndexRow(e, S, w);
|
|
55
|
+
if (T) return T;
|
|
56
|
+
let E = typeof C == "number" ? C : this.nextID, D = this.createRow(E, e);
|
|
57
|
+
return this.nextID = Math.max(this.nextID, D.id + 1), this.rowsByID.set(D.id, D), this.indexRow(D), S && this.store._emitChange(this.store._buildChange({
|
|
58
|
+
kind: "row:insert",
|
|
59
|
+
tableName: this.name,
|
|
60
|
+
rowID: D.id,
|
|
61
|
+
fields: { ...e }
|
|
62
|
+
}, w)), D;
|
|
63
|
+
}
|
|
64
|
+
addIndexToField(e, S) {
|
|
65
|
+
if (!(e in this.schema)) throw TypeError(`Unknown field ${this.name}.${e}`);
|
|
66
|
+
if (this.indexesByField.has(e)) throw Error(`Index for field ${this.name}.${e} already exists`);
|
|
67
|
+
if (S.kind !== "hashmap") throw TypeError(`Unsupported index kind ${S.kind}`);
|
|
68
|
+
let C = {
|
|
69
|
+
kind: "hashmap",
|
|
70
|
+
unique: S.unique ?? !1,
|
|
71
|
+
rowIDsByEncodedValue: /* @__PURE__ */ new Map()
|
|
72
|
+
};
|
|
73
|
+
this.indexesByField.set(e, C);
|
|
74
|
+
for (let S of this.rowsByID.values()) this.indexRowField(S, e, C);
|
|
75
|
+
}
|
|
76
|
+
getByIndex(e, S) {
|
|
77
|
+
let C = this.indexesByField.get(e);
|
|
78
|
+
if (!C) throw Error(`Index for field ${this.name}.${e} does not exist`);
|
|
79
|
+
let w = this.encodeIndexValue(S), T = C.rowIDsByEncodedValue.get(w);
|
|
80
|
+
if (!T || T.size === 0) return null;
|
|
81
|
+
for (let e of T) {
|
|
82
|
+
let S = this.rowsByID.get(e);
|
|
83
|
+
if (S) return S;
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
get(e) {
|
|
88
|
+
return this.rowsByID.get(e) ?? null;
|
|
89
|
+
}
|
|
90
|
+
all() {
|
|
91
|
+
return Array.from(this.rowsByID.values());
|
|
92
|
+
}
|
|
93
|
+
values() {
|
|
94
|
+
return this.rowsByID.values();
|
|
95
|
+
}
|
|
96
|
+
filter(e) {
|
|
97
|
+
let S = [];
|
|
98
|
+
for (let C of this.rowsByID.values()) e(C) && S.push(C);
|
|
99
|
+
return S;
|
|
100
|
+
}
|
|
101
|
+
count() {
|
|
102
|
+
return this.rowsByID.size;
|
|
103
|
+
}
|
|
104
|
+
getByID(e) {
|
|
105
|
+
return this.get(e);
|
|
106
|
+
}
|
|
107
|
+
update(e, S) {
|
|
108
|
+
let C = this.rowsByID.get(e);
|
|
109
|
+
if (C) return this.validateInput(S, !0), Object.assign(C, S), C;
|
|
110
|
+
}
|
|
111
|
+
delete(e) {
|
|
112
|
+
if (!this.store._canSynchronouslyMutateRows()) throw Error("Replica rows cannot be modified synchronously; use setAsync instead");
|
|
113
|
+
return this.deleteByID(e, !0);
|
|
114
|
+
}
|
|
115
|
+
deleteByID(e, S) {
|
|
116
|
+
let C = this.rowsByID.get(e);
|
|
117
|
+
return C ? (this.unindexRow(C), this.rowsByID.delete(e), S && this.store._emitChange(this.store._buildChange({
|
|
118
|
+
kind: "row:delete",
|
|
119
|
+
tableName: this.name,
|
|
120
|
+
rowID: e
|
|
121
|
+
})), !0) : !1;
|
|
122
|
+
}
|
|
123
|
+
clear() {
|
|
124
|
+
this.rowsByID.clear();
|
|
125
|
+
for (let e of this.indexesByField.values()) e.rowIDsByEncodedValue.clear();
|
|
126
|
+
this.nextID = 1;
|
|
127
|
+
}
|
|
128
|
+
serialize() {
|
|
129
|
+
let e = {};
|
|
130
|
+
for (let S of Object.keys(this.schema)) e[S] = { kind: "key" };
|
|
131
|
+
return {
|
|
132
|
+
name: this.name,
|
|
133
|
+
schema: e,
|
|
134
|
+
indexes: Array.from(this.indexesByField.entries()).map(([e, S]) => ({
|
|
135
|
+
field: e,
|
|
136
|
+
kind: "hashmap",
|
|
137
|
+
unique: S.unique
|
|
138
|
+
})),
|
|
139
|
+
rows: Array.from(this.rowsByID.values(), (e) => e.snapshot())
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
_hydrate(e) {
|
|
143
|
+
this.clear();
|
|
144
|
+
for (let S of e) {
|
|
145
|
+
let { id: e, ...C } = S;
|
|
146
|
+
this.validateInput(C), this.insertRow(C, !1, e);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
_applyChange(e) {
|
|
150
|
+
if (e.tableName !== this.name) return;
|
|
151
|
+
if (e.kind === "row:delete") {
|
|
152
|
+
this.store._runWithoutBroadcast(() => {
|
|
153
|
+
this.deleteByID(e.rowID, !1);
|
|
154
|
+
});
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (e.kind === "row:insert") {
|
|
158
|
+
this.store._runWithoutBroadcast(() => {
|
|
159
|
+
this.insertRow(e.fields, !1, e.rowID, {
|
|
160
|
+
requestId: e.requestId,
|
|
161
|
+
sourceStoreId: e.sourceStoreId,
|
|
162
|
+
timestamp: e.timestamp,
|
|
163
|
+
version: e.version
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (e.kind !== "row:update") return;
|
|
169
|
+
let S = this.rowsByID.get(e.rowID);
|
|
170
|
+
S && this.store._runWithoutBroadcast(() => {
|
|
171
|
+
this.setRowField(S, e.field, e.value, !1);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
_processChangeRequest(e) {
|
|
175
|
+
if (e.kind !== "row:set-async" || e.tableName !== this.name) return;
|
|
176
|
+
let S = this.rowsByID.get(e.rowID);
|
|
177
|
+
if (!S) throw Error(`Row ${this.name}.${e.rowID} does not exist`);
|
|
178
|
+
let C = e.patch;
|
|
179
|
+
this.validateInput(C, !0);
|
|
180
|
+
for (let [C, w] of Object.entries(e.patch)) this.setRowField(S, C, w, !0, {
|
|
181
|
+
requestId: e.requestId,
|
|
182
|
+
sourceStoreId: e.sourceStoreId
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
createRow(e, S) {
|
|
186
|
+
let C = new this.RowClass(e, S);
|
|
187
|
+
return Object.preventExtensions(C), C;
|
|
188
|
+
}
|
|
189
|
+
createRowClass() {
|
|
190
|
+
let e = this;
|
|
191
|
+
class S extends Row {
|
|
192
|
+
constructor(S, C) {
|
|
193
|
+
super(S, C, async (S, C) => {
|
|
194
|
+
let w = e.store._buildChangeRequest({
|
|
195
|
+
kind: "row:set-async",
|
|
196
|
+
tableName: e.name,
|
|
197
|
+
rowID: S,
|
|
198
|
+
patch: C
|
|
199
|
+
});
|
|
200
|
+
await e.store.requestChange(e.store._encodeChangeRequest(w));
|
|
201
|
+
}, (S) => e.delete(S));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
for (let C of Object.keys(this.schema)) Object.defineProperty(S.prototype, C, {
|
|
205
|
+
enumerable: !0,
|
|
206
|
+
configurable: !1,
|
|
207
|
+
get() {
|
|
208
|
+
return this.readField(C);
|
|
209
|
+
},
|
|
210
|
+
set(S) {
|
|
211
|
+
if (!e.store._canSynchronouslyMutateRows()) throw Error("Replica rows cannot be modified synchronously; use setAsync instead");
|
|
212
|
+
e.setRowField(this, C, S, !0);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
return S;
|
|
216
|
+
}
|
|
217
|
+
setRowField(e, S, C, w, T) {
|
|
218
|
+
if (S === "id") throw TypeError("Row ID is immutable");
|
|
219
|
+
if (!(S in this.schema)) throw TypeError(`Unknown field ${this.name}.${S}`);
|
|
220
|
+
let E = this.toStoredFieldValue(S, C), D = this.indexesByField.get(S);
|
|
221
|
+
if (D) {
|
|
222
|
+
let C = e.readField(S);
|
|
223
|
+
this.unindexRowField(e, S, D, C);
|
|
224
|
+
}
|
|
225
|
+
e.writeField(S, E), D && this.indexRowField(e, S, D), w && this.store._emitChange(this.store._buildChange({
|
|
226
|
+
kind: "row:update",
|
|
227
|
+
tableName: this.name,
|
|
228
|
+
rowID: e.id,
|
|
229
|
+
field: S,
|
|
230
|
+
value: E
|
|
231
|
+
}, T));
|
|
232
|
+
}
|
|
233
|
+
validateInput(e, S = !1) {
|
|
234
|
+
for (let C in this.schema) {
|
|
235
|
+
if (!(C in e)) {
|
|
236
|
+
if (S) continue;
|
|
237
|
+
throw TypeError(`Missing required field ${this.name}.${C}`);
|
|
238
|
+
}
|
|
239
|
+
e[C];
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
toStoredFieldValue(e, S) {
|
|
243
|
+
return S;
|
|
244
|
+
}
|
|
245
|
+
indexRow(e) {
|
|
246
|
+
for (let [S, C] of this.indexesByField.entries()) this.indexRowField(e, S, C);
|
|
247
|
+
}
|
|
248
|
+
unindexRow(e) {
|
|
249
|
+
for (let [S, C] of this.indexesByField.entries()) this.unindexRowField(e, S, C);
|
|
250
|
+
}
|
|
251
|
+
indexRowField(e, S, C) {
|
|
252
|
+
let w = e.readField(S), T = this.encodeIndexValue(w), E = C.rowIDsByEncodedValue.get(T);
|
|
253
|
+
if (E || (E = /* @__PURE__ */ new Set(), C.rowIDsByEncodedValue.set(T, E)), C.unique && E.size > 0 && !E.has(e.id)) throw Error(`Unique index violation for field ${this.name}.${S} value ${T}`);
|
|
254
|
+
E.add(e.id);
|
|
255
|
+
}
|
|
256
|
+
tryUpsertUniqueIndexRow(e, S, C) {
|
|
257
|
+
let w = null;
|
|
258
|
+
for (let [S, C] of this.indexesByField.entries()) {
|
|
259
|
+
if (!C.unique || !(S in e)) continue;
|
|
260
|
+
let T = this.getIndexedRow(S, e[S]);
|
|
261
|
+
if (T) {
|
|
262
|
+
if (w && w.id !== T.id) throw Error(`Unique index conflict for insert into ${this.name}: indexes point to different existing rows`);
|
|
263
|
+
w = T;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (!w) return null;
|
|
267
|
+
for (let [T, E] of Object.entries(e)) this.setRowField(w, T, E, S, C);
|
|
268
|
+
return w;
|
|
269
|
+
}
|
|
270
|
+
getIndexedRow(e, S) {
|
|
271
|
+
let C = this.indexesByField.get(e);
|
|
272
|
+
if (!C) return null;
|
|
273
|
+
let w = this.encodeIndexValue(S), T = C.rowIDsByEncodedValue.get(w);
|
|
274
|
+
if (!T || T.size === 0) return null;
|
|
275
|
+
for (let e of T) {
|
|
276
|
+
let S = this.rowsByID.get(e);
|
|
277
|
+
if (S) return S;
|
|
278
|
+
}
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
unindexRowField(e, S, C, w) {
|
|
282
|
+
let T = w ?? e.readField(S), E = this.encodeIndexValue(T), D = C.rowIDsByEncodedValue.get(E);
|
|
283
|
+
D && (D.delete(e.id), D.size === 0 && C.rowIDsByEncodedValue.delete(E));
|
|
284
|
+
}
|
|
285
|
+
encodeIndexValue(e) {
|
|
286
|
+
if (e === null) return "null";
|
|
287
|
+
let S = typeof e;
|
|
288
|
+
return S === "string" ? `s:${e}` : S === "number" ? `n:${e}` : S === "boolean" ? `b:${e}` : `j:${JSON.stringify(e)}`;
|
|
289
|
+
}
|
|
290
|
+
}, OP_CHANGE = 1, OP_CHANGE_REQUEST = 2, OP_CHANGE_BATCH = 3, CHANGE_ROW_INSERT = 1, CHANGE_ROW_UPDATE = 2, CHANGE_ROW_DELETE = 3, VALUE_NULL = 0, VALUE_STRING = 1, VALUE_NUMBER = 2, VALUE_BOOLEAN = 3, VALUE_ARRAY = 4, VALUE_OBJECT = 5, BinaryWriter = class {
|
|
291
|
+
buffer;
|
|
292
|
+
view;
|
|
293
|
+
bytes;
|
|
294
|
+
offset = 0;
|
|
295
|
+
constructor(e = 256) {
|
|
296
|
+
this.buffer = new ArrayBuffer(e), this.view = new DataView(this.buffer), this.bytes = new Uint8Array(this.buffer);
|
|
297
|
+
}
|
|
298
|
+
ensureCapacity(e) {
|
|
299
|
+
let S = this.offset + e;
|
|
300
|
+
if (S <= this.buffer.byteLength) return;
|
|
301
|
+
let C = this.buffer.byteLength;
|
|
302
|
+
for (; C < S;) C *= 2;
|
|
303
|
+
let w = new ArrayBuffer(C), T = new Uint8Array(w);
|
|
304
|
+
T.set(this.bytes.subarray(0, this.offset)), this.buffer = w, this.bytes = T, this.view = new DataView(w);
|
|
305
|
+
}
|
|
306
|
+
writeByte(e) {
|
|
307
|
+
this.ensureCapacity(1), this.bytes[this.offset] = e & 255, this.offset += 1;
|
|
308
|
+
}
|
|
309
|
+
writeFloat64(e) {
|
|
310
|
+
this.ensureCapacity(8), this.view.setFloat64(this.offset, e, !0), this.offset += 8;
|
|
311
|
+
}
|
|
312
|
+
writeUint32(e) {
|
|
313
|
+
this.ensureCapacity(4), this.view.setUint32(this.offset, e, !0), this.offset += 4;
|
|
314
|
+
}
|
|
315
|
+
writeString(e) {
|
|
316
|
+
let S = new TextEncoder().encode(e);
|
|
317
|
+
this.writeUint32(S.length), this.ensureCapacity(S.length), this.bytes.set(S, this.offset), this.offset += S.length;
|
|
318
|
+
}
|
|
319
|
+
writeValue(e) {
|
|
320
|
+
if (e === null) {
|
|
321
|
+
this.writeByte(VALUE_NULL);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (typeof e == "string") {
|
|
325
|
+
this.writeByte(VALUE_STRING), this.writeString(e);
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
if (typeof e == "number") {
|
|
329
|
+
this.writeByte(VALUE_NUMBER), this.writeFloat64(e);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (typeof e == "boolean") {
|
|
333
|
+
this.writeByte(VALUE_BOOLEAN), this.writeByte(e ? 1 : 0);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
if (Array.isArray(e)) {
|
|
337
|
+
this.writeByte(VALUE_ARRAY), this.writeUint32(e.length);
|
|
338
|
+
for (let S of e) this.writeValue(S);
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
this.writeByte(VALUE_OBJECT);
|
|
342
|
+
let S = Object.entries(e);
|
|
343
|
+
this.writeUint32(S.length);
|
|
344
|
+
for (let [e, C] of S) this.writeString(e), this.writeValue(C);
|
|
345
|
+
}
|
|
346
|
+
toUint8Array() {
|
|
347
|
+
return this.bytes.slice(0, this.offset);
|
|
348
|
+
}
|
|
349
|
+
}, BinaryReader = class {
|
|
350
|
+
offset = 0;
|
|
351
|
+
constructor(e) {
|
|
352
|
+
this.input = e;
|
|
353
|
+
}
|
|
354
|
+
readByte() {
|
|
355
|
+
this.ensureAvailable(1);
|
|
356
|
+
let e = this.input[this.offset];
|
|
357
|
+
return this.offset += 1, e;
|
|
358
|
+
}
|
|
359
|
+
readFloat64() {
|
|
360
|
+
this.ensureAvailable(8);
|
|
361
|
+
let e = new DataView(this.input.buffer, this.input.byteOffset + this.offset, 8).getFloat64(0, !0);
|
|
362
|
+
return this.offset += 8, e;
|
|
363
|
+
}
|
|
364
|
+
readUint32() {
|
|
365
|
+
this.ensureAvailable(4);
|
|
366
|
+
let e = new DataView(this.input.buffer, this.input.byteOffset + this.offset, 4).getUint32(0, !0);
|
|
367
|
+
return this.offset += 4, e;
|
|
368
|
+
}
|
|
369
|
+
readString() {
|
|
370
|
+
let e = this.readUint32();
|
|
371
|
+
this.ensureAvailable(e);
|
|
372
|
+
let S = new TextDecoder().decode(this.input.subarray(this.offset, this.offset + e));
|
|
373
|
+
return this.offset += e, S;
|
|
374
|
+
}
|
|
375
|
+
readValue() {
|
|
376
|
+
let e = this.readByte();
|
|
377
|
+
if (e === VALUE_NULL) return null;
|
|
378
|
+
if (e === VALUE_STRING) return this.readString();
|
|
379
|
+
if (e === VALUE_NUMBER) return this.readFloat64();
|
|
380
|
+
if (e === VALUE_BOOLEAN) return this.readByte() === 1;
|
|
381
|
+
if (e === VALUE_ARRAY) {
|
|
382
|
+
let e = this.readUint32(), S = [];
|
|
383
|
+
for (let C = 0; C < e; C += 1) S.push(this.readValue());
|
|
384
|
+
return S;
|
|
385
|
+
}
|
|
386
|
+
if (e === VALUE_OBJECT) {
|
|
387
|
+
let e = this.readUint32(), S = {};
|
|
388
|
+
for (let C = 0; C < e; C += 1) {
|
|
389
|
+
let e = this.readString();
|
|
390
|
+
S[e] = this.readValue();
|
|
391
|
+
}
|
|
392
|
+
return S;
|
|
393
|
+
}
|
|
394
|
+
throw Error(`Unknown value kind ${e}`);
|
|
395
|
+
}
|
|
396
|
+
assertFullyRead() {
|
|
397
|
+
if (this.offset !== this.input.length) throw Error("Unexpected trailing bytes");
|
|
398
|
+
}
|
|
399
|
+
ensureAvailable(e) {
|
|
400
|
+
if (this.offset + e > this.input.length) throw Error("Unexpected end of binary payload");
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
function writeMeta(e, S) {
|
|
404
|
+
e.writeString(S.requestId), e.writeString(S.sourceStoreId), e.writeFloat64(S.timestamp), e.writeByte(typeof S.version == "number" ? 1 : 0), typeof S.version == "number" && e.writeFloat64(S.version);
|
|
405
|
+
}
|
|
406
|
+
function readMeta(e) {
|
|
407
|
+
let S = e.readString(), C = e.readString(), w = e.readFloat64(), T = e.readByte() === 1 ? e.readFloat64() : void 0;
|
|
408
|
+
return typeof T == "number" ? {
|
|
409
|
+
requestId: S,
|
|
410
|
+
sourceStoreId: C,
|
|
411
|
+
timestamp: w,
|
|
412
|
+
version: T
|
|
413
|
+
} : {
|
|
414
|
+
requestId: S,
|
|
415
|
+
sourceStoreId: C,
|
|
416
|
+
timestamp: w
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
function writeStoreChangeBody(e, S) {
|
|
420
|
+
if (S.kind === "row:insert" ? e.writeByte(CHANGE_ROW_INSERT) : S.kind === "row:update" ? e.writeByte(CHANGE_ROW_UPDATE) : e.writeByte(CHANGE_ROW_DELETE), e.writeString(S.tableName), e.writeFloat64(S.rowID), S.kind === "row:insert") {
|
|
421
|
+
let C = Object.entries(S.fields);
|
|
422
|
+
e.writeUint32(C.length);
|
|
423
|
+
for (let [S, w] of C) e.writeString(S), e.writeValue(w);
|
|
424
|
+
}
|
|
425
|
+
S.kind === "row:update" && (e.writeString(S.field), e.writeValue(S.value)), writeMeta(e, S);
|
|
426
|
+
}
|
|
427
|
+
function readStoreChangeBody(e) {
|
|
428
|
+
let S = e.readByte(), C = e.readString(), w = e.readFloat64();
|
|
429
|
+
if (S === CHANGE_ROW_INSERT) {
|
|
430
|
+
let S = e.readUint32(), T = {};
|
|
431
|
+
for (let C = 0; C < S; C += 1) {
|
|
432
|
+
let S = e.readString();
|
|
433
|
+
T[S] = e.readValue();
|
|
434
|
+
}
|
|
435
|
+
return {
|
|
436
|
+
kind: "row:insert",
|
|
437
|
+
tableName: C,
|
|
438
|
+
rowID: w,
|
|
439
|
+
fields: T,
|
|
440
|
+
...readMeta(e)
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
if (S === CHANGE_ROW_DELETE) return {
|
|
444
|
+
kind: "row:delete",
|
|
445
|
+
tableName: C,
|
|
446
|
+
rowID: w,
|
|
447
|
+
...readMeta(e)
|
|
448
|
+
};
|
|
449
|
+
if (S !== CHANGE_ROW_UPDATE) throw Error(`Unknown change kind ${S}`);
|
|
450
|
+
return {
|
|
451
|
+
kind: "row:update",
|
|
452
|
+
tableName: C,
|
|
453
|
+
rowID: w,
|
|
454
|
+
field: e.readString(),
|
|
455
|
+
value: e.readValue(),
|
|
456
|
+
...readMeta(e)
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
function encodeStoreChange(e) {
|
|
460
|
+
let S = new BinaryWriter();
|
|
461
|
+
return S.writeByte(OP_CHANGE), writeStoreChangeBody(S, e), S.toUint8Array();
|
|
462
|
+
}
|
|
463
|
+
function encodeStoreChanges(e) {
|
|
464
|
+
let S = new BinaryWriter();
|
|
465
|
+
S.writeByte(OP_CHANGE_BATCH), S.writeUint32(e.length);
|
|
466
|
+
for (let C of e) writeStoreChangeBody(S, C);
|
|
467
|
+
return S.toUint8Array();
|
|
468
|
+
}
|
|
469
|
+
function decodeStoreChange(e) {
|
|
470
|
+
let S = new BinaryReader(e), C = S.readByte();
|
|
471
|
+
if (C !== OP_CHANGE) throw Error(`Unexpected operation kind ${C}, expected change`);
|
|
472
|
+
let w = readStoreChangeBody(S);
|
|
473
|
+
return S.assertFullyRead(), w;
|
|
474
|
+
}
|
|
475
|
+
function decodeStoreChanges(e) {
|
|
476
|
+
let S = new BinaryReader(e), C = S.readByte();
|
|
477
|
+
if (C === OP_CHANGE) {
|
|
478
|
+
let e = readStoreChangeBody(S);
|
|
479
|
+
return S.assertFullyRead(), [e];
|
|
480
|
+
}
|
|
481
|
+
if (C !== OP_CHANGE_BATCH) throw Error(`Unexpected operation kind ${C}, expected change batch`);
|
|
482
|
+
let w = S.readUint32(), E = [];
|
|
483
|
+
for (let e = 0; e < w; e += 1) E.push(readStoreChangeBody(S));
|
|
484
|
+
return S.assertFullyRead(), E;
|
|
485
|
+
}
|
|
486
|
+
function encodeStoreChangeRequest(e) {
|
|
487
|
+
let S = new BinaryWriter();
|
|
488
|
+
S.writeByte(OP_CHANGE_REQUEST), S.writeString(e.tableName), S.writeFloat64(e.rowID);
|
|
489
|
+
let C = Object.entries(e.patch);
|
|
490
|
+
S.writeUint32(C.length);
|
|
491
|
+
for (let [e, w] of C) S.writeString(e), S.writeValue(w);
|
|
492
|
+
return writeMeta(S, e), S.toUint8Array();
|
|
493
|
+
}
|
|
494
|
+
function decodeStoreChangeRequest(e) {
|
|
495
|
+
let S = new BinaryReader(e), C = S.readByte();
|
|
496
|
+
if (C !== OP_CHANGE_REQUEST) throw Error(`Unexpected operation kind ${C}, expected request`);
|
|
497
|
+
let w = S.readString(), T = S.readFloat64(), D = S.readUint32(), O = {};
|
|
498
|
+
for (let e = 0; e < D; e += 1) {
|
|
499
|
+
let e = S.readString();
|
|
500
|
+
O[e] = S.readValue();
|
|
501
|
+
}
|
|
502
|
+
let k = readMeta(S);
|
|
503
|
+
return S.assertFullyRead(), {
|
|
504
|
+
kind: "row:set-async",
|
|
505
|
+
tableName: w,
|
|
506
|
+
rowID: T,
|
|
507
|
+
patch: O,
|
|
508
|
+
...k
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
var AnyStore = class e {
|
|
512
|
+
static nextStoreNumber = 1;
|
|
513
|
+
static nextRequestNumber = 1;
|
|
514
|
+
tables = /* @__PURE__ */ new Map();
|
|
515
|
+
listeners = /* @__PURE__ */ new Set();
|
|
516
|
+
requestListeners = /* @__PURE__ */ new Set();
|
|
517
|
+
storeID = `store-${e.nextStoreNumber++}`;
|
|
518
|
+
rowsLocked = !1;
|
|
519
|
+
muted = !1;
|
|
520
|
+
version = 0;
|
|
521
|
+
pendingChanges = [];
|
|
522
|
+
changeFlushScheduled = !1;
|
|
523
|
+
constructor(e) {
|
|
524
|
+
this.rowsLocked = e;
|
|
525
|
+
}
|
|
526
|
+
static create() {
|
|
527
|
+
return e.createPrimary();
|
|
528
|
+
}
|
|
529
|
+
static createPrimary() {
|
|
530
|
+
return new e(!1);
|
|
531
|
+
}
|
|
532
|
+
static replica(S) {
|
|
533
|
+
return e.createReplica(S);
|
|
534
|
+
}
|
|
535
|
+
static createReplica(S) {
|
|
536
|
+
let C = new e(!0);
|
|
537
|
+
for (let w of S.tables) {
|
|
538
|
+
let S = C.createTable(w.name, e._fromSerializedSchema(w.schema)), T = w.indexes ?? w.indexedFields?.map((e) => ({
|
|
539
|
+
field: e,
|
|
540
|
+
kind: "hashmap",
|
|
541
|
+
unique: !1
|
|
542
|
+
})) ?? [];
|
|
543
|
+
for (let e of T) S.addIndexToField(e.field, {
|
|
544
|
+
kind: e.kind,
|
|
545
|
+
unique: e.unique
|
|
546
|
+
});
|
|
547
|
+
S._hydrate(w.rows);
|
|
548
|
+
}
|
|
549
|
+
return C;
|
|
550
|
+
}
|
|
551
|
+
static key() {
|
|
552
|
+
return { kind: "key" };
|
|
553
|
+
}
|
|
554
|
+
createTable(e, S) {
|
|
555
|
+
if (this.tables.has(e)) throw Error(`Table ${e} already exists`);
|
|
556
|
+
let C = new Table(this, e, S);
|
|
557
|
+
return this.tables.set(e, C), C;
|
|
558
|
+
}
|
|
559
|
+
getTable(e) {
|
|
560
|
+
let S = this.tables.get(e);
|
|
561
|
+
if (!S) throw Error(`Table ${e} does not exist`);
|
|
562
|
+
return S;
|
|
563
|
+
}
|
|
564
|
+
hasTable(e) {
|
|
565
|
+
return this.tables.has(e);
|
|
566
|
+
}
|
|
567
|
+
dropTable(e) {
|
|
568
|
+
return this.tables.delete(e);
|
|
569
|
+
}
|
|
570
|
+
clear() {
|
|
571
|
+
this.tables.clear();
|
|
572
|
+
}
|
|
573
|
+
serialize() {
|
|
574
|
+
return this.pendingChanges.length > 0 && this.flushPendingChanges(), { tables: Array.from(this.tables.values()).map((e) => e.serialize()) };
|
|
575
|
+
}
|
|
576
|
+
applyChange(e) {
|
|
577
|
+
let S = decodeStoreChanges(e);
|
|
578
|
+
for (let e of S) {
|
|
579
|
+
let S = this.tables.get(e.tableName);
|
|
580
|
+
S && S._applyChange(e);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
onChange(e) {
|
|
584
|
+
return this.listeners.add(e), () => {
|
|
585
|
+
this.listeners.delete(e);
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
onChangeRequest(e) {
|
|
589
|
+
return this.requestListeners.add(e), () => {
|
|
590
|
+
this.requestListeners.delete(e);
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
async requestChange(e) {
|
|
594
|
+
if (!this.rowsLocked) {
|
|
595
|
+
this.processChangeRequest(e);
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
if (this.requestListeners.size === 0) throw Error("No change-request listeners are registered");
|
|
599
|
+
await Promise.all(Array.from(this.requestListeners, (S) => S(e)));
|
|
600
|
+
}
|
|
601
|
+
processChangeRequest(e) {
|
|
602
|
+
let S = decodeStoreChangeRequest(e), C = this.tables.get(S.tableName);
|
|
603
|
+
if (!C) throw Error(`Table ${S.tableName} does not exist`);
|
|
604
|
+
C._processChangeRequest(S);
|
|
605
|
+
}
|
|
606
|
+
_canInsertRows() {
|
|
607
|
+
return !this.rowsLocked;
|
|
608
|
+
}
|
|
609
|
+
_canSynchronouslyMutateRows() {
|
|
610
|
+
return !this.rowsLocked;
|
|
611
|
+
}
|
|
612
|
+
_buildChange(e, S) {
|
|
613
|
+
return this.version += 1, {
|
|
614
|
+
...e,
|
|
615
|
+
requestId: S?.requestId ?? this.nextRequestID(),
|
|
616
|
+
sourceStoreId: S?.sourceStoreId ?? this.storeID,
|
|
617
|
+
timestamp: S?.timestamp ?? Date.now(),
|
|
618
|
+
version: S?.version ?? this.version
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
_buildChangeRequest(e, S) {
|
|
622
|
+
return {
|
|
623
|
+
...e,
|
|
624
|
+
requestId: S?.requestId ?? this.nextRequestID(),
|
|
625
|
+
sourceStoreId: S?.sourceStoreId ?? this.storeID,
|
|
626
|
+
timestamp: S?.timestamp ?? Date.now(),
|
|
627
|
+
version: S?.version
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
_encodeChangeRequest(e) {
|
|
631
|
+
return encodeStoreChangeRequest(e);
|
|
632
|
+
}
|
|
633
|
+
_emitChange(e) {
|
|
634
|
+
this.muted || (typeof e.version == "number" && (this.version = Math.max(this.version, e.version)), this.pendingChanges.push(e), !this.changeFlushScheduled && (this.changeFlushScheduled = !0, queueMicrotask(() => {
|
|
635
|
+
this.flushPendingChanges();
|
|
636
|
+
})));
|
|
637
|
+
}
|
|
638
|
+
_runWithoutBroadcast(e) {
|
|
639
|
+
this.muted = !0;
|
|
640
|
+
try {
|
|
641
|
+
e();
|
|
642
|
+
} finally {
|
|
643
|
+
this.muted = !1;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
nextRequestID() {
|
|
647
|
+
return `req-${e.nextRequestNumber++}`;
|
|
648
|
+
}
|
|
649
|
+
flushPendingChanges() {
|
|
650
|
+
if (this.changeFlushScheduled = !1, this.pendingChanges.length === 0) return;
|
|
651
|
+
let e = this.pendingChanges;
|
|
652
|
+
this.pendingChanges = [];
|
|
653
|
+
let S = encodeStoreChanges(e);
|
|
654
|
+
for (let e of this.listeners) e(S);
|
|
655
|
+
}
|
|
656
|
+
static _fromSerializedSchema(S) {
|
|
657
|
+
let C = {};
|
|
658
|
+
for (let [w, T] of Object.entries(S)) {
|
|
659
|
+
if (T.kind !== "key") throw Error(`Unsupported serialized schema kind ${T.kind} for field ${w}`);
|
|
660
|
+
C[w] = e.key();
|
|
661
|
+
}
|
|
662
|
+
return C;
|
|
663
|
+
}
|
|
664
|
+
};
|
|
665
|
+
function identity(e) {
|
|
666
|
+
return e;
|
|
667
|
+
}
|
|
668
|
+
export { AnyStore, Row, Table, decodeStoreChange, decodeStoreChangeRequest, decodeStoreChanges, encodeStoreChange, encodeStoreChangeRequest, encodeStoreChanges, identity };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Table } from './table';
|
|
2
|
+
import { BinaryStoreChange, BinaryStoreChangeRequest, KeyFieldDefinition, PrimitiveFieldValue, SerializedStore, TableSchema } from './types';
|
|
3
|
+
export declare class AnyStore {
|
|
4
|
+
private static nextStoreNumber;
|
|
5
|
+
private static nextRequestNumber;
|
|
6
|
+
private readonly tables;
|
|
7
|
+
private readonly listeners;
|
|
8
|
+
private readonly requestListeners;
|
|
9
|
+
private readonly storeID;
|
|
10
|
+
private rowsLocked;
|
|
11
|
+
private muted;
|
|
12
|
+
private version;
|
|
13
|
+
private pendingChanges;
|
|
14
|
+
private changeFlushScheduled;
|
|
15
|
+
private constructor();
|
|
16
|
+
static create(): AnyStore;
|
|
17
|
+
static createPrimary(): AnyStore;
|
|
18
|
+
static replica(state: SerializedStore): AnyStore;
|
|
19
|
+
static createReplica(state: SerializedStore): AnyStore;
|
|
20
|
+
static key<TValue extends PrimitiveFieldValue>(): KeyFieldDefinition<TValue>;
|
|
21
|
+
createTable<Name extends string, const Schema extends TableSchema>(name: Name, schema: Schema): Table<Schema>;
|
|
22
|
+
getTable<Schema extends TableSchema = TableSchema>(name: string): Table<Schema>;
|
|
23
|
+
hasTable(name: string): boolean;
|
|
24
|
+
dropTable(name: string): boolean;
|
|
25
|
+
clear(): void;
|
|
26
|
+
serialize(): SerializedStore;
|
|
27
|
+
applyChange(change: BinaryStoreChange): void;
|
|
28
|
+
onChange(listener: (change: BinaryStoreChange) => void): () => void;
|
|
29
|
+
onChangeRequest(listener: (request: BinaryStoreChangeRequest) => void | Promise<void>): () => void;
|
|
30
|
+
requestChange(request: BinaryStoreChangeRequest): Promise<void>;
|
|
31
|
+
processChangeRequest(request: BinaryStoreChangeRequest): void;
|
|
32
|
+
private nextRequestID;
|
|
33
|
+
private flushPendingChanges;
|
|
34
|
+
private static _fromSerializedSchema;
|
|
35
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { StoreChange, StoreChangeRequest } from './types';
|
|
2
|
+
export declare function encodeStoreChange(change: StoreChange): Uint8Array;
|
|
3
|
+
export declare function encodeStoreChanges(changes: readonly StoreChange[]): Uint8Array;
|
|
4
|
+
export declare function decodeStoreChange(payload: Uint8Array): StoreChange;
|
|
5
|
+
export declare function decodeStoreChanges(payload: Uint8Array): StoreChange[];
|
|
6
|
+
export declare function encodeStoreChangeRequest(request: StoreChangeRequest): Uint8Array;
|
|
7
|
+
export declare function decodeStoreChangeRequest(payload: Uint8Array): StoreChangeRequest;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function identity<T>(value: T): T;
|
|
2
|
+
export { Row } from './row';
|
|
3
|
+
export { AnyStore } from './any-store';
|
|
4
|
+
export { Table } from './table';
|
|
5
|
+
export { decodeStoreChange, decodeStoreChanges, decodeStoreChangeRequest, encodeStoreChange, encodeStoreChanges, encodeStoreChangeRequest, } from './binary-codec';
|
|
6
|
+
export type { BinaryStoreChange, BinaryStoreChangeRequest, SerializedStore, StoreChange, StoreChangeRequest, TableRow, TableSchema, InsertInput, UpdateInput, PrimitiveFieldValue, } from './types';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { PrimitiveFieldValue } from './types';
|
|
2
|
+
type AsyncSetHandler = (rowID: number, patch: Record<string, PrimitiveFieldValue>) => Promise<void>;
|
|
3
|
+
type DeleteHandler = (rowID: number) => boolean;
|
|
4
|
+
declare const ASYNC_SET_HANDLER: unique symbol;
|
|
5
|
+
declare const DELETE_HANDLER: unique symbol;
|
|
6
|
+
export declare class Row {
|
|
7
|
+
private readonly rowID;
|
|
8
|
+
private readonly fields;
|
|
9
|
+
private readonly [ASYNC_SET_HANDLER];
|
|
10
|
+
private readonly [DELETE_HANDLER];
|
|
11
|
+
constructor(id: number, fields: Record<string, PrimitiveFieldValue>, asyncSetHandler: AsyncSetHandler, deleteHandler: DeleteHandler);
|
|
12
|
+
get id(): number;
|
|
13
|
+
readField(field: string): PrimitiveFieldValue;
|
|
14
|
+
writeField(field: string, value: PrimitiveFieldValue): void;
|
|
15
|
+
setAsync(patch: Record<string, PrimitiveFieldValue>): Promise<void>;
|
|
16
|
+
delete(): boolean;
|
|
17
|
+
snapshot(): Record<string, PrimitiveFieldValue> & {
|
|
18
|
+
id: number;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { InsertInput, SerializedTable, TableRow, TableSchema, UpdateInput } from './types';
|
|
2
|
+
export declare class Table<Schema extends TableSchema> {
|
|
3
|
+
private readonly store;
|
|
4
|
+
private readonly name;
|
|
5
|
+
private readonly schema;
|
|
6
|
+
private readonly RowClass;
|
|
7
|
+
private nextID;
|
|
8
|
+
private readonly rowsByID;
|
|
9
|
+
private readonly indexesByField;
|
|
10
|
+
constructor(store: StoreHooks, name: string, schema: Schema);
|
|
11
|
+
insert(input: InsertInput<Schema>): TableRow<Schema>;
|
|
12
|
+
private insertRow;
|
|
13
|
+
addIndexToField<FieldName extends Extract<keyof Schema, string>>(field: FieldName, config: {
|
|
14
|
+
kind: "hashmap";
|
|
15
|
+
unique?: boolean;
|
|
16
|
+
}): void;
|
|
17
|
+
getByIndex<FieldName extends Extract<keyof Schema, string>>(field: FieldName, value: TableRow<Schema>[FieldName]): TableRow<Schema> | null;
|
|
18
|
+
get(id: number): TableRow<Schema> | null;
|
|
19
|
+
all(): readonly TableRow<Schema>[];
|
|
20
|
+
values(): IterableIterator<TableRow<Schema>>;
|
|
21
|
+
filter(predicate: (row: TableRow<Schema>) => boolean): TableRow<Schema>[];
|
|
22
|
+
count(): number;
|
|
23
|
+
getByID(id: number): TableRow<Schema> | null;
|
|
24
|
+
update(id: number, patch: UpdateInput<Schema>): TableRow<Schema> | undefined;
|
|
25
|
+
delete(id: number): boolean;
|
|
26
|
+
private deleteByID;
|
|
27
|
+
clear(): void;
|
|
28
|
+
serialize(): SerializedTable;
|
|
29
|
+
private createRow;
|
|
30
|
+
private createRowClass;
|
|
31
|
+
private setRowField;
|
|
32
|
+
private validateInput;
|
|
33
|
+
private toStoredFieldValue;
|
|
34
|
+
private indexRow;
|
|
35
|
+
private unindexRow;
|
|
36
|
+
private indexRowField;
|
|
37
|
+
private tryUpsertUniqueIndexRow;
|
|
38
|
+
private getIndexedRow;
|
|
39
|
+
private unindexRowField;
|
|
40
|
+
private encodeIndexValue;
|
|
41
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export type PrimitiveFieldValue = string | number | boolean | null | PrimitiveFieldValue[] | {
|
|
2
|
+
[key: string]: PrimitiveFieldValue;
|
|
3
|
+
};
|
|
4
|
+
declare const KEY_VALUE_TYPE: unique symbol;
|
|
5
|
+
export type KeyFieldDefinition<TValue extends PrimitiveFieldValue> = {
|
|
6
|
+
kind: "key";
|
|
7
|
+
[KEY_VALUE_TYPE]: TValue;
|
|
8
|
+
};
|
|
9
|
+
export type TableSchema = Record<string, KeyFieldDefinition<PrimitiveFieldValue>>;
|
|
10
|
+
type FieldValueForDefinition<Definition extends KeyFieldDefinition<PrimitiveFieldValue>> = Definition extends KeyFieldDefinition<infer TValue> ? NonNullable<TValue> : never;
|
|
11
|
+
export type InsertInput<Schema extends TableSchema> = {
|
|
12
|
+
-readonly [K in keyof Schema]: FieldValueForDefinition<Schema[K]>;
|
|
13
|
+
};
|
|
14
|
+
export type UpdateInput<Schema extends TableSchema> = Partial<InsertInput<Schema>>;
|
|
15
|
+
export type TableRow<Schema extends TableSchema> = {
|
|
16
|
+
-readonly [K in keyof Schema]: FieldValueForDefinition<Schema[K]>;
|
|
17
|
+
} & {
|
|
18
|
+
id: number;
|
|
19
|
+
delete(): boolean;
|
|
20
|
+
setAsync(patch: UpdateInput<Schema>): Promise<void>;
|
|
21
|
+
};
|
|
22
|
+
export type EnvelopeMeta = {
|
|
23
|
+
requestId: string;
|
|
24
|
+
sourceStoreId: string;
|
|
25
|
+
timestamp: number;
|
|
26
|
+
version?: number;
|
|
27
|
+
};
|
|
28
|
+
export type RowUpdateChangePayload = {
|
|
29
|
+
kind: "row:update";
|
|
30
|
+
tableName: string;
|
|
31
|
+
rowID: number;
|
|
32
|
+
field: string;
|
|
33
|
+
value: PrimitiveFieldValue;
|
|
34
|
+
};
|
|
35
|
+
export type RowInsertChangePayload = {
|
|
36
|
+
kind: "row:insert";
|
|
37
|
+
tableName: string;
|
|
38
|
+
rowID: number;
|
|
39
|
+
fields: Record<string, PrimitiveFieldValue>;
|
|
40
|
+
};
|
|
41
|
+
export type RowDeleteChangePayload = {
|
|
42
|
+
kind: "row:delete";
|
|
43
|
+
tableName: string;
|
|
44
|
+
rowID: number;
|
|
45
|
+
};
|
|
46
|
+
export type StoreChangePayload = RowInsertChangePayload | RowUpdateChangePayload | RowDeleteChangePayload;
|
|
47
|
+
export type StoreChange = StoreChangePayload & EnvelopeMeta;
|
|
48
|
+
export type BinaryStoreChange = Uint8Array;
|
|
49
|
+
export type StoreChangeRequestPayload = {
|
|
50
|
+
kind: "row:set-async";
|
|
51
|
+
tableName: string;
|
|
52
|
+
rowID: number;
|
|
53
|
+
patch: Record<string, PrimitiveFieldValue>;
|
|
54
|
+
};
|
|
55
|
+
export type StoreChangeRequest = StoreChangeRequestPayload & EnvelopeMeta;
|
|
56
|
+
export type BinaryStoreChangeRequest = Uint8Array;
|
|
57
|
+
export type SerializedPrimitiveField = {
|
|
58
|
+
kind: "key";
|
|
59
|
+
};
|
|
60
|
+
export type SerializedFieldSchema = SerializedPrimitiveField;
|
|
61
|
+
export type SerializedTableSchema = Record<string, SerializedFieldSchema>;
|
|
62
|
+
export type SerializedTableIndex = {
|
|
63
|
+
field: string;
|
|
64
|
+
kind: "hashmap";
|
|
65
|
+
unique?: boolean;
|
|
66
|
+
};
|
|
67
|
+
export type SerializedTable = {
|
|
68
|
+
name: string;
|
|
69
|
+
schema: SerializedTableSchema;
|
|
70
|
+
indexes?: SerializedTableIndex[];
|
|
71
|
+
rows: Array<Record<string, PrimitiveFieldValue> & {
|
|
72
|
+
id: number;
|
|
73
|
+
}>;
|
|
74
|
+
};
|
|
75
|
+
export type SerializedStore = {
|
|
76
|
+
tables: SerializedTable[];
|
|
77
|
+
};
|
|
78
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "any-store-js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"module": "./dist/lib.es.js",
|
|
10
|
+
"types": "./dist/src/lib.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/lib.es.js",
|
|
14
|
+
"types": "./dist/src/lib.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"dev": "vite",
|
|
19
|
+
"build": "npm run check && vite build",
|
|
20
|
+
"preview": "vite preview",
|
|
21
|
+
"check": "tsc --build",
|
|
22
|
+
"test": "vitest",
|
|
23
|
+
"bench": "vitest bench",
|
|
24
|
+
"test:browser": "vitest --config=vitest.browser.config.ts",
|
|
25
|
+
"test-ci": "vitest --run && vitest --config=vitest.browser.config.ts --run --browser.headless",
|
|
26
|
+
"deploy": "npm run build && npm publish --access public"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^25.0.3",
|
|
30
|
+
"@vitest/browser-playwright": "^4.0.18",
|
|
31
|
+
"tsx": "^4.21.0",
|
|
32
|
+
"typescript": "~5.9.3",
|
|
33
|
+
"vite": "npm:rolldown-vite@7.2.5",
|
|
34
|
+
"vite-plugin-dts": "^4.5.4",
|
|
35
|
+
"vitest": "^4.0.16"
|
|
36
|
+
},
|
|
37
|
+
"overrides": {
|
|
38
|
+
"vite": "npm:rolldown-vite@7.2.5"
|
|
39
|
+
}
|
|
40
|
+
}
|