@interocitor/core 0.0.0-beta.2
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/README.md +178 -0
- package/dist/adapters/cloudflare.d.ts +72 -0
- package/dist/adapters/cloudflare.d.ts.map +1 -0
- package/dist/adapters/cloudflare.js +227 -0
- package/dist/adapters/cloudflare.js.map +1 -0
- package/dist/adapters/google-drive.d.ts +64 -0
- package/dist/adapters/google-drive.d.ts.map +1 -0
- package/dist/adapters/google-drive.js +340 -0
- package/dist/adapters/google-drive.js.map +1 -0
- package/dist/adapters/memory.d.ts +45 -0
- package/dist/adapters/memory.d.ts.map +1 -0
- package/dist/adapters/memory.js +129 -0
- package/dist/adapters/memory.js.map +1 -0
- package/dist/adapters/webdav.d.ts +59 -0
- package/dist/adapters/webdav.d.ts.map +1 -0
- package/dist/adapters/webdav.js +247 -0
- package/dist/adapters/webdav.js.map +1 -0
- package/dist/core/codec.d.ts +20 -0
- package/dist/core/codec.d.ts.map +1 -0
- package/dist/core/codec.js +66 -0
- package/dist/core/codec.js.map +1 -0
- package/dist/core/compaction.d.ts +37 -0
- package/dist/core/compaction.d.ts.map +1 -0
- package/dist/core/compaction.js +134 -0
- package/dist/core/compaction.js.map +1 -0
- package/dist/core/crdt.d.ts +33 -0
- package/dist/core/crdt.d.ts.map +1 -0
- package/dist/core/crdt.js +188 -0
- package/dist/core/crdt.js.map +1 -0
- package/dist/core/flush.d.ts +9 -0
- package/dist/core/flush.d.ts.map +1 -0
- package/dist/core/flush.js +41 -0
- package/dist/core/flush.js.map +1 -0
- package/dist/core/hlc.d.ts +25 -0
- package/dist/core/hlc.d.ts.map +1 -0
- package/dist/core/hlc.js +76 -0
- package/dist/core/hlc.js.map +1 -0
- package/dist/core/internals.d.ts +25 -0
- package/dist/core/internals.d.ts.map +1 -0
- package/dist/core/internals.js +54 -0
- package/dist/core/internals.js.map +1 -0
- package/dist/core/manifest.d.ts +31 -0
- package/dist/core/manifest.d.ts.map +1 -0
- package/dist/core/manifest.js +111 -0
- package/dist/core/manifest.js.map +1 -0
- package/dist/core/pull.d.ts +26 -0
- package/dist/core/pull.d.ts.map +1 -0
- package/dist/core/pull.js +98 -0
- package/dist/core/pull.js.map +1 -0
- package/dist/core/row-id.d.ts +12 -0
- package/dist/core/row-id.d.ts.map +1 -0
- package/dist/core/row-id.js +12 -0
- package/dist/core/row-id.js.map +1 -0
- package/dist/core/schema-types.d.ts +13 -0
- package/dist/core/schema-types.d.ts.map +1 -0
- package/dist/core/schema-types.js +18 -0
- package/dist/core/schema-types.js.map +1 -0
- package/dist/core/schema-types.type-test.d.ts +2 -0
- package/dist/core/schema-types.type-test.d.ts.map +1 -0
- package/dist/core/schema-types.type-test.js +149 -0
- package/dist/core/schema-types.type-test.js.map +1 -0
- package/dist/core/sync-engine.d.ts +158 -0
- package/dist/core/sync-engine.d.ts.map +1 -0
- package/dist/core/sync-engine.js +714 -0
- package/dist/core/sync-engine.js.map +1 -0
- package/dist/core/table.d.ts +60 -0
- package/dist/core/table.d.ts.map +1 -0
- package/dist/core/table.js +106 -0
- package/dist/core/table.js.map +1 -0
- package/dist/core/types.d.ts +478 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +7 -0
- package/dist/core/types.js.map +1 -0
- package/dist/crypto/encryption.d.ts +57 -0
- package/dist/crypto/encryption.d.ts.map +1 -0
- package/dist/crypto/encryption.js +195 -0
- package/dist/crypto/encryption.js.map +1 -0
- package/dist/crypto/keys.d.ts +48 -0
- package/dist/crypto/keys.d.ts.map +1 -0
- package/dist/crypto/keys.js +55 -0
- package/dist/crypto/keys.js.map +1 -0
- package/dist/handshake/channel.d.ts +117 -0
- package/dist/handshake/channel.d.ts.map +1 -0
- package/dist/handshake/channel.js +246 -0
- package/dist/handshake/channel.js.map +1 -0
- package/dist/handshake/index.d.ts +213 -0
- package/dist/handshake/index.d.ts.map +1 -0
- package/dist/handshake/index.js +182 -0
- package/dist/handshake/index.js.map +1 -0
- package/dist/handshake/qr.d.ts +100 -0
- package/dist/handshake/qr.d.ts.map +1 -0
- package/dist/handshake/qr.js +103 -0
- package/dist/handshake/qr.js.map +1 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/storage/credential-store.d.ts +99 -0
- package/dist/storage/credential-store.d.ts.map +1 -0
- package/dist/storage/credential-store.js +309 -0
- package/dist/storage/credential-store.js.map +1 -0
- package/dist/storage/local-store.d.ts +56 -0
- package/dist/storage/local-store.d.ts.map +1 -0
- package/dist/storage/local-store.js +411 -0
- package/dist/storage/local-store.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/core/pull.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,GAAG,EACH,EAAE,EAEF,SAAS,EACT,wBAAwB,EACzB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAKtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,iBAAiB,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,GAAG,EAAE,GAAG,CAAC;IACT,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAC5C,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,MAAM,CAAC,EAAE,wBAAwB,CAAC;IAClC,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACjC,gBAAgB,EAAE,CAAC,GAAG,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC;IAChE,oBAAoB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C;AAiBD,0CAA0C;AAC1C,wBAAsB,IAAI,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAiFzD"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pull — download remote changes and merge into local state.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from SyncEngine. Not part of the public API.
|
|
5
|
+
*/
|
|
6
|
+
import { hlcParse, hlcReceive, hlcCompareStr, hlcSerialize } from "./hlc.js";
|
|
7
|
+
import { applyChangeEntry } from "./crdt.js";
|
|
8
|
+
import { paths, textDecoder, log } from "./internals.js";
|
|
9
|
+
import { decodeChangePayload } from "./codec.js";
|
|
10
|
+
import { readJsonIfExists } from "./manifest.js";
|
|
11
|
+
function emitAffectedRows(affected, knownTables, emit) {
|
|
12
|
+
for (const row of affected) {
|
|
13
|
+
knownTables.add(row._table);
|
|
14
|
+
if (row._deleted) {
|
|
15
|
+
emit({ type: 'delete', table: row._table, rowId: row._rowId });
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
emit({ type: 'change', table: row._table, rowId: row._rowId, row });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Returns the updated HLC after pull. */
|
|
23
|
+
export async function pull(ctx) {
|
|
24
|
+
const { adapter, local, remotePath, codecState, tables, knownTables, emit } = ctx;
|
|
25
|
+
let hlc = ctx.hlc;
|
|
26
|
+
log('debug', 'pull() — start');
|
|
27
|
+
emit({ type: 'sync:start' });
|
|
28
|
+
try {
|
|
29
|
+
await ctx.loadOrCreateManifest();
|
|
30
|
+
const p = paths(remotePath);
|
|
31
|
+
const cursorRaw = await local.getMeta('cursor');
|
|
32
|
+
const cursor = typeof cursorRaw === 'string' ? cursorRaw : '';
|
|
33
|
+
// Fast path: if global head hasn't advanced past cursor, skip listing.
|
|
34
|
+
const head = await readJsonIfExists(adapter, p.changesHead);
|
|
35
|
+
if (head?.latestHlc && cursor && hlcCompareStr(head.latestHlc, cursor) <= 0) {
|
|
36
|
+
log('debug', 'pull() — head unchanged, skipping');
|
|
37
|
+
emit({ type: 'sync:complete', entriesMerged: 0 });
|
|
38
|
+
return hlc;
|
|
39
|
+
}
|
|
40
|
+
// List the flat changes folder once.
|
|
41
|
+
let files;
|
|
42
|
+
try {
|
|
43
|
+
files = await adapter.listFiles(p.changesFolder);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
log('debug', 'pull() — changes folder not found, nothing to merge');
|
|
47
|
+
emit({ type: 'sync:complete', entriesMerged: 0 });
|
|
48
|
+
return hlc;
|
|
49
|
+
}
|
|
50
|
+
files.sort((a, b) => a.name.localeCompare(b.name));
|
|
51
|
+
let totalMerged = 0;
|
|
52
|
+
let latestMergedHlc = cursor;
|
|
53
|
+
for (const file of files) {
|
|
54
|
+
if (file.name === 'head.json')
|
|
55
|
+
continue;
|
|
56
|
+
try {
|
|
57
|
+
const chgIdx = file.name.lastIndexOf('-chg_');
|
|
58
|
+
if (chgIdx === -1)
|
|
59
|
+
continue;
|
|
60
|
+
const fileHlc = file.name.slice(0, chgIdx);
|
|
61
|
+
if (cursor && hlcCompareStr(fileHlc, cursor) <= 0)
|
|
62
|
+
continue;
|
|
63
|
+
const raw = textDecoder.decode(await adapter.readFile(file.path));
|
|
64
|
+
const entry = await decodeChangePayload(codecState, local, raw, file.path);
|
|
65
|
+
if (cursor && hlcCompareStr(entry.hlc, cursor) <= 0)
|
|
66
|
+
continue;
|
|
67
|
+
const remoteHlc = hlcParse(entry.hlc);
|
|
68
|
+
hlc = hlcReceive(hlc, remoteHlc);
|
|
69
|
+
await ctx.ensureRowsCached(entry.ops);
|
|
70
|
+
const affected = applyChangeEntry(tables, entry, codecState.manifest?.schema ?? 1, ctx.schema);
|
|
71
|
+
if (affected.length > 0) {
|
|
72
|
+
await local.putRows(affected);
|
|
73
|
+
totalMerged += affected.length;
|
|
74
|
+
emitAffectedRows(affected, knownTables, emit);
|
|
75
|
+
}
|
|
76
|
+
if (!latestMergedHlc || hlcCompareStr(entry.hlc, latestMergedHlc) > 0) {
|
|
77
|
+
latestMergedHlc = entry.hlc;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
throw await ctx.poisonRemote(err, file.path);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (latestMergedHlc && latestMergedHlc !== cursor) {
|
|
85
|
+
await local.setMeta('cursor', latestMergedHlc);
|
|
86
|
+
}
|
|
87
|
+
await local.setMeta('hlc', hlcSerialize(hlc));
|
|
88
|
+
log('debug', 'pull() — complete', { totalMerged });
|
|
89
|
+
emit({ type: 'sync:complete', entriesMerged: totalMerged });
|
|
90
|
+
return hlc;
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
log('error', 'pull() — failed', err);
|
|
94
|
+
emit({ type: 'sync:error', error: err });
|
|
95
|
+
throw err;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=pull.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/core/pull.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable client-side row ID generator.
|
|
3
|
+
*
|
|
4
|
+
* Use for synced rows. Do not use auto-increment IDs across devices.
|
|
5
|
+
* Default output uses `crypto.randomUUID()` when available.
|
|
6
|
+
*/
|
|
7
|
+
export interface CreateRowIdOptions {
|
|
8
|
+
/** Optional prefix like `task`, `meal`, `note`. */
|
|
9
|
+
prefix?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function createRowId(options?: CreateRowIdOptions): string;
|
|
12
|
+
//# sourceMappingURL=row-id.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"row-id.d.ts","sourceRoot":"","sources":["../../src/core/row-id.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAQD,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,MAAM,CAKpE"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
function randomHex(bytes) {
|
|
2
|
+
const buf = new Uint8Array(bytes);
|
|
3
|
+
crypto.getRandomValues(buf);
|
|
4
|
+
return Array.from(buf, b => b.toString(16).padStart(2, '0')).join('');
|
|
5
|
+
}
|
|
6
|
+
export function createRowId(options = {}) {
|
|
7
|
+
const base = typeof crypto.randomUUID === 'function'
|
|
8
|
+
? crypto.randomUUID()
|
|
9
|
+
: `${randomHex(8)}-${randomHex(4)}-${randomHex(4)}-${randomHex(4)}-${randomHex(12)}`;
|
|
10
|
+
return options.prefix ? `${options.prefix}_${base}` : base;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=row-id.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"row-id.js","sourceRoot":"","sources":["../../src/core/row-id.ts"],"names":[],"mappings":"AAWA,SAAS,SAAS,CAAC,KAAa;IAC9B,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;IAClC,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IAC5B,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,UAA8B,EAAE;IAC1D,MAAM,IAAI,GAAG,OAAO,MAAM,CAAC,UAAU,KAAK,UAAU;QAClD,CAAC,CAAC,MAAM,CAAC,UAAU,EAAE;QACrB,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC;IACvF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { IndexableSchemaField, SchemaField } from './types.ts';
|
|
2
|
+
export declare const types: {
|
|
3
|
+
string: IndexableSchemaField<string>;
|
|
4
|
+
number: IndexableSchemaField<number>;
|
|
5
|
+
boolean: IndexableSchemaField<boolean>;
|
|
6
|
+
date: IndexableSchemaField<Date>;
|
|
7
|
+
Date: IndexableSchemaField<Date>;
|
|
8
|
+
json: SchemaField<unknown>;
|
|
9
|
+
enum<const T extends string>(..._values: T[]): IndexableSchemaField<T>;
|
|
10
|
+
index<T>(field: IndexableSchemaField<T>): IndexableSchemaField<T>;
|
|
11
|
+
unique<T>(field: IndexableSchemaField<T>): IndexableSchemaField<T>;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=schema-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-types.d.ts","sourceRoot":"","sources":["../../src/core/schema-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEpE,eAAO,MAAM,KAAK;YACgB,oBAAoB,CAAC,MAAM,CAAC;YAC5B,oBAAoB,CAAC,MAAM,CAAC;aAC5B,oBAAoB,CAAC,OAAO,CAAC;UAC7B,oBAAoB,CAAC,IAAI,CAAC;UAC1B,oBAAoB,CAAC,IAAI,CAAC;UAC1B,WAAW,CAAC,OAAO,CAAC;eAEzC,CAAC,SAAS,MAAM,cAAc,CAAC,EAAE,GAAG,oBAAoB,CAAC,CAAC,CAAC;UAIhE,CAAC,SAAS,oBAAoB,CAAC,CAAC,CAAC,GAAG,oBAAoB,CAAC,CAAC,CAAC;WAI1D,CAAC,SAAS,oBAAoB,CAAC,CAAC,CAAC,GAAG,oBAAoB,CAAC,CAAC,CAAC;CAGnE,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const types = {
|
|
2
|
+
string: { kind: 'string' },
|
|
3
|
+
number: { kind: 'number' },
|
|
4
|
+
boolean: { kind: 'boolean' },
|
|
5
|
+
date: { kind: 'date' },
|
|
6
|
+
Date: { kind: 'date' },
|
|
7
|
+
json: { kind: 'json' },
|
|
8
|
+
enum(..._values) {
|
|
9
|
+
return { kind: 'enum' };
|
|
10
|
+
},
|
|
11
|
+
index(field) {
|
|
12
|
+
return { ...field, index: true };
|
|
13
|
+
},
|
|
14
|
+
unique(field) {
|
|
15
|
+
return { ...field, index: true, unique: true };
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=schema-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-types.js","sourceRoot":"","sources":["../../src/core/schema-types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,MAAM,EAAG,EAAE,IAAI,EAAE,QAAQ,EAAmC;IAC5D,MAAM,EAAG,EAAE,IAAI,EAAE,QAAQ,EAAmC;IAC5D,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAmC;IAC7D,IAAI,EAAK,EAAE,IAAI,EAAE,MAAM,EAAmC;IAC1D,IAAI,EAAK,EAAE,IAAI,EAAE,MAAM,EAAmC;IAC1D,IAAI,EAAK,EAAE,IAAI,EAAE,MAAM,EAA6B;IAEpD,IAAI,CAAyB,GAAG,OAAY;QAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,EAA6B,CAAC;IACrD,CAAC;IAED,KAAK,CAAI,KAA8B;QACrC,OAAO,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACnC,CAAC;IAED,MAAM,CAAI,KAA8B;QACtC,OAAO,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACjD,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-types.type-test.d.ts","sourceRoot":"","sources":["../../src/core/schema-types.type-test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { types } from "./schema-types.js";
|
|
2
|
+
// ─── Scalar types carry their generic ────────────────────────────────
|
|
3
|
+
const _s = types.string;
|
|
4
|
+
const _n = types.number;
|
|
5
|
+
const _b = types.boolean;
|
|
6
|
+
const _d = types.date;
|
|
7
|
+
const _D = types.Date;
|
|
8
|
+
const _j = types.json;
|
|
9
|
+
void _s;
|
|
10
|
+
void _n;
|
|
11
|
+
void _b;
|
|
12
|
+
void _d;
|
|
13
|
+
void _D;
|
|
14
|
+
void _j;
|
|
15
|
+
// ─── enum() infers literal union from const generic ─────────────────
|
|
16
|
+
const statusType = types.enum('open', 'done', 'archived');
|
|
17
|
+
void statusType;
|
|
18
|
+
const indexedStatus = types.index(types.enum('open', 'done', 'archived'));
|
|
19
|
+
const uniqueRole = types.unique(types.enum('admin', 'viewer'));
|
|
20
|
+
void indexedStatus;
|
|
21
|
+
void uniqueRole;
|
|
22
|
+
// @ts-expect-error — 'open'|'done'|'other' is wider than the target 'open'|'done'
|
|
23
|
+
const _wrongEnum = types.enum('open', 'done', 'other');
|
|
24
|
+
void _wrongEnum;
|
|
25
|
+
// @ts-expect-error — string is wider than 'open'|'done'
|
|
26
|
+
const _enumNotString = types.index(types.string);
|
|
27
|
+
void _enumNotString;
|
|
28
|
+
// ─── index() and unique() return the same flat shape with flags set ──
|
|
29
|
+
const indexedString = types.index(types.string);
|
|
30
|
+
const uniqueNumber = types.unique(types.number);
|
|
31
|
+
const indexedDate = types.index(types.Date);
|
|
32
|
+
void indexedString;
|
|
33
|
+
void uniqueNumber;
|
|
34
|
+
void indexedDate;
|
|
35
|
+
// @ts-expect-error — IndexableSchemaField<string> is not IndexableSchemaField<number>
|
|
36
|
+
const _wrongGeneric = types.index(types.string);
|
|
37
|
+
void _wrongGeneric;
|
|
38
|
+
// ─── json is not indexable ──────────────────────────────────────────
|
|
39
|
+
// @ts-expect-error — SchemaField<unknown> (json) is not IndexableSchemaField
|
|
40
|
+
types.index(types.json);
|
|
41
|
+
// @ts-expect-error — SchemaField<unknown> (json) is not IndexableSchemaField
|
|
42
|
+
types.unique(types.json);
|
|
43
|
+
// ─── Can't pass an already-indexed field back into index/unique ──────
|
|
44
|
+
// (IndexableSchemaField is still IndexableSchemaField — nesting compiles,
|
|
45
|
+
// but index/unique are idempotent by design; the flag just stays true)
|
|
46
|
+
// ─── Bare string literal is not a valid field descriptor ─────────────
|
|
47
|
+
// @ts-expect-error — 'string' is not IndexableSchemaField
|
|
48
|
+
types.index('string');
|
|
49
|
+
// ─── Full schema definition compiles ────────────────────────────────
|
|
50
|
+
const schema = {
|
|
51
|
+
version: 1,
|
|
52
|
+
tables: {
|
|
53
|
+
tasks: {
|
|
54
|
+
fields: {
|
|
55
|
+
status: types.index(types.enum('open', 'done', 'archived')),
|
|
56
|
+
assignee: types.unique(types.string),
|
|
57
|
+
priority: types.index(types.number),
|
|
58
|
+
dueDate: types.Date,
|
|
59
|
+
payload: types.json,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
void schema;
|
|
65
|
+
// ─── Generic DatabaseSchemaDefinition + InferSchemaType ─────────────
|
|
66
|
+
// Build a typed schema via `satisfies` — TS widens to the generic but keeps
|
|
67
|
+
// the phantom types intact for inference.
|
|
68
|
+
const typedSchema = {
|
|
69
|
+
version: 1,
|
|
70
|
+
tables: {
|
|
71
|
+
tasks: {
|
|
72
|
+
fields: {
|
|
73
|
+
title: types.string,
|
|
74
|
+
status: types.enum('open', 'done'),
|
|
75
|
+
priority: types.number,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
notes: {
|
|
79
|
+
fields: {
|
|
80
|
+
content: types.string,
|
|
81
|
+
pinned: types.boolean,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
// Field types are correct
|
|
87
|
+
const _taskTitle = 'hello';
|
|
88
|
+
const _taskStatus = 'open';
|
|
89
|
+
const _taskPrio = 42;
|
|
90
|
+
const _noteContent = 'text';
|
|
91
|
+
const _notePinned = true;
|
|
92
|
+
void _taskTitle;
|
|
93
|
+
void _taskStatus;
|
|
94
|
+
void _taskPrio;
|
|
95
|
+
void _noteContent;
|
|
96
|
+
void _notePinned;
|
|
97
|
+
// InferTableType matches direct extraction
|
|
98
|
+
const _same = {};
|
|
99
|
+
void _same;
|
|
100
|
+
// @ts-expect-error — 'other' is not in the 'open'|'done' union
|
|
101
|
+
const _badStatus = 'other';
|
|
102
|
+
void _badStatus;
|
|
103
|
+
// @ts-expect-error — number is not string
|
|
104
|
+
const _badTitle = 42;
|
|
105
|
+
void _badTitle;
|
|
106
|
+
// ─── TableSchemaDefinition<T> typed fields ───────────────────────────
|
|
107
|
+
// Valid typed table schema compiles
|
|
108
|
+
const _validTableSchema = {
|
|
109
|
+
fields: { title: types.string, priority: types.number },
|
|
110
|
+
};
|
|
111
|
+
void _validTableSchema;
|
|
112
|
+
// Field type mismatch — SchemaField<number> is not SchemaField<string>
|
|
113
|
+
const _mismatchedField = {
|
|
114
|
+
// @ts-expect-error — IndexableSchemaField<number> is not SchemaField<string>
|
|
115
|
+
fields: { title: types.number },
|
|
116
|
+
};
|
|
117
|
+
void _mismatchedField;
|
|
118
|
+
// ─── SyncConfig<S> carries schema type ──────────────────────────────
|
|
119
|
+
// Config typed explicitly — schema must match S
|
|
120
|
+
const _config = {
|
|
121
|
+
remotePath: '/App',
|
|
122
|
+
appName: 'App',
|
|
123
|
+
schema: {
|
|
124
|
+
version: 1,
|
|
125
|
+
tables: { tasks: { fields: { title: types.string } } },
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
void _config;
|
|
129
|
+
// Schema field type mismatch caught inline
|
|
130
|
+
const _badConfig = {
|
|
131
|
+
remotePath: '/App',
|
|
132
|
+
appName: 'App',
|
|
133
|
+
schema: {
|
|
134
|
+
version: 1,
|
|
135
|
+
tables: { tasks: { fields: {
|
|
136
|
+
// @ts-expect-error — IndexableSchemaField<number> is not SchemaField<string>
|
|
137
|
+
title: types.number,
|
|
138
|
+
} } },
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
void _badConfig;
|
|
142
|
+
// table() with known key → Table<{ title: string; status: 'open'|'done'; priority: number }>
|
|
143
|
+
const tasksTable = typedEngine.table('tasks');
|
|
144
|
+
// _TasksGet should be { title: string; ... } | undefined — not Record<string,unknown>
|
|
145
|
+
const _checkGet = { title: 'x', status: 'open', priority: 1 };
|
|
146
|
+
void _checkGet;
|
|
147
|
+
// table() with an unknown key falls back to Table<Record<string,unknown>> via the string overload —
|
|
148
|
+
// that is intentional (untyped fallback). The typed overload only fires for keyof S.
|
|
149
|
+
//# sourceMappingURL=schema-types.type-test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-types.type-test.js","sourceRoot":"","sources":["../../src/core/schema-types.type-test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync Engine
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates:
|
|
5
|
+
* - Local writes → outbox → flush to cloud (primary + replicas)
|
|
6
|
+
* - Cloud poll → download → decrypt → CRDT merge → local DB
|
|
7
|
+
* - Rehydration from manifest-authoritative snapshot
|
|
8
|
+
*
|
|
9
|
+
* Network is never required for reads or local writes.
|
|
10
|
+
* All data operations hit IndexedDB first; cloud sync is async.
|
|
11
|
+
*/
|
|
12
|
+
import type { StorageAdapter, SyncConfig, LocalStoreAdapter, Manifest, Row, SyncEventListener, WhereClause } from './types.ts';
|
|
13
|
+
import { Table } from './table.ts';
|
|
14
|
+
/**
|
|
15
|
+
* Type parameter S maps table names to their plain record types.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* interface AppSchema {
|
|
19
|
+
* tasks: { title: string; status: 'open' | 'done' };
|
|
20
|
+
* notes: { content: string };
|
|
21
|
+
* }
|
|
22
|
+
* const engine = new SyncEngine<AppSchema>(adapter, { remotePath: '/App' });
|
|
23
|
+
* const tasks = engine.table('tasks'); // Table<{ title: string; status: 'open' | 'done' }>
|
|
24
|
+
*
|
|
25
|
+
* Schema is optional — omit it for untyped usage.
|
|
26
|
+
*/
|
|
27
|
+
export declare class SyncEngine<S extends Record<string, Record<string, unknown>> = Record<string, Record<string, unknown>>> {
|
|
28
|
+
private adapter;
|
|
29
|
+
private config;
|
|
30
|
+
private serverId;
|
|
31
|
+
private local;
|
|
32
|
+
private deviceId;
|
|
33
|
+
private hlc;
|
|
34
|
+
private encryptionKey;
|
|
35
|
+
private encrypted;
|
|
36
|
+
private passphrase;
|
|
37
|
+
private tables;
|
|
38
|
+
private manifest;
|
|
39
|
+
private remotePoisonError;
|
|
40
|
+
private knownTables;
|
|
41
|
+
private flushTimer;
|
|
42
|
+
private pendingCount;
|
|
43
|
+
private pollTimer;
|
|
44
|
+
private initialized;
|
|
45
|
+
private connected;
|
|
46
|
+
private listeners;
|
|
47
|
+
private readonly schema?;
|
|
48
|
+
private readonly credentialStore;
|
|
49
|
+
/**
|
|
50
|
+
* Create a sync engine.
|
|
51
|
+
*
|
|
52
|
+
* Pass a remote adapter up front for immediate sync support, or pass only
|
|
53
|
+
* config to start fully local and attach a remote later with
|
|
54
|
+
* {@link setRemoteStorage}.
|
|
55
|
+
*
|
|
56
|
+
* The schema type `S` is inferred automatically from the `schema` field in
|
|
57
|
+
* config — no manual type parameter needed:
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* const engine = new SyncEngine(adapter, { schema, remotePath: '/App', appName: 'App' });
|
|
61
|
+
* const tasks = engine.table('tasks'); // Table<{ title: string; status: 'open' | 'done' }>
|
|
62
|
+
*/
|
|
63
|
+
constructor(config: SyncConfig<S>);
|
|
64
|
+
constructor(adapter: StorageAdapter | null, config: SyncConfig<S>);
|
|
65
|
+
private requireAdapter;
|
|
66
|
+
private get codecState();
|
|
67
|
+
private get manifestContext();
|
|
68
|
+
private clearScheduledFlush;
|
|
69
|
+
private stopPolling;
|
|
70
|
+
private startPolling;
|
|
71
|
+
private resetRemoteSyncState;
|
|
72
|
+
private getRowHlc;
|
|
73
|
+
private rowToSyncOp;
|
|
74
|
+
private buildChangeEntry;
|
|
75
|
+
private rebuildOutboxFromLocalState;
|
|
76
|
+
private loadLocalState;
|
|
77
|
+
private ensureRowsCached;
|
|
78
|
+
private poisonRemote;
|
|
79
|
+
on(listener: SyncEventListener): () => void;
|
|
80
|
+
private emit;
|
|
81
|
+
private persistCredentials;
|
|
82
|
+
private loadPersistedCredentials;
|
|
83
|
+
private clearPersistedCredentials;
|
|
84
|
+
private resolveEncryption;
|
|
85
|
+
/**
|
|
86
|
+
* Set the mesh encryption passphrase.
|
|
87
|
+
* Call before init() or between disconnect() and init().
|
|
88
|
+
*/
|
|
89
|
+
setPassphrase(passphrase: string): void;
|
|
90
|
+
/**
|
|
91
|
+
* Get the current mesh passphrase.
|
|
92
|
+
* Returns null if the mesh is unencrypted.
|
|
93
|
+
* Call after init() to ensure key derivation is complete.
|
|
94
|
+
*/
|
|
95
|
+
getPassphrase(): string | null;
|
|
96
|
+
/**
|
|
97
|
+
* Persist credentials to the OS keychain via biometrics.
|
|
98
|
+
* Call after pairing, or from a "Secure my keys" UI action.
|
|
99
|
+
* Returns true if saved, false if unavailable or user cancelled.
|
|
100
|
+
*/
|
|
101
|
+
secureWithBiometrics(): Promise<boolean>;
|
|
102
|
+
/**
|
|
103
|
+
* Explicit restore path for wiped / returning users.
|
|
104
|
+
* Call only from intentional app UI: "try restore purchases",
|
|
105
|
+
* "restore access", etc.
|
|
106
|
+
*
|
|
107
|
+
* On success:
|
|
108
|
+
* - restores passphrase + device ID from OS keychain
|
|
109
|
+
* - re-populates silent local storage
|
|
110
|
+
* - derives encryption key
|
|
111
|
+
*
|
|
112
|
+
* Returns true if restore succeeded.
|
|
113
|
+
*/
|
|
114
|
+
restoreWithBiometrics(): Promise<boolean>;
|
|
115
|
+
/**
|
|
116
|
+
* Clear persisted credentials for this mesh.
|
|
117
|
+
* Warning: lost key = lost data. No recovery.
|
|
118
|
+
*/
|
|
119
|
+
clearCredentials(): Promise<void>;
|
|
120
|
+
/**
|
|
121
|
+
* @deprecated Use setPassphrase() instead. Will be removed.
|
|
122
|
+
*/
|
|
123
|
+
setEncryptionKey(key: CryptoKey): void;
|
|
124
|
+
init(): Promise<void>;
|
|
125
|
+
/**
|
|
126
|
+
* Silent credential restore from the primary store only.
|
|
127
|
+
* Used during normal init(). No biometric prompt.
|
|
128
|
+
*/
|
|
129
|
+
private restoreCredentials;
|
|
130
|
+
connect(): Promise<void>;
|
|
131
|
+
disconnect(): Promise<void>;
|
|
132
|
+
setRemoteStorage(adapter: StorageAdapter | null): Promise<void>;
|
|
133
|
+
setLocalStorage(local: LocalStoreAdapter): Promise<void>;
|
|
134
|
+
private doLoadOrCreateManifest;
|
|
135
|
+
put(table: string, rowId: string, columns: Record<string, unknown>, userId?: string): Promise<Row>;
|
|
136
|
+
delete(table: string, rowId: string, userId?: string): Promise<void>;
|
|
137
|
+
get(table: string, rowId: string): Promise<Row | undefined>;
|
|
138
|
+
query(table: string): Promise<Row[]>;
|
|
139
|
+
queryWhere(table: string, clause: WhereClause): Promise<Row[]>;
|
|
140
|
+
tableNames(): Promise<string[]>;
|
|
141
|
+
table<K extends keyof S & string>(name: K): Table<S[K]>;
|
|
142
|
+
table<T extends Record<string, unknown>>(name: string): Table<T>;
|
|
143
|
+
private scheduleFlush;
|
|
144
|
+
flush(): Promise<void>;
|
|
145
|
+
pull(): Promise<void>;
|
|
146
|
+
rehydrate(): Promise<void>;
|
|
147
|
+
compact(): Promise<void>;
|
|
148
|
+
getManifest(): Manifest | null;
|
|
149
|
+
getDeviceId(): string;
|
|
150
|
+
getMeshId(): string | undefined;
|
|
151
|
+
isEncrypted(): boolean;
|
|
152
|
+
/**
|
|
153
|
+
* Enable encryption on an existing unencrypted mesh.
|
|
154
|
+
* @deprecated Use setPassphrase() or pass encrypted/passphrase in config.
|
|
155
|
+
*/
|
|
156
|
+
enableEncryption(key: CryptoKey): Promise<void>;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=sync-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-engine.d.ts","sourceRoot":"","sources":["../../src/core/sync-engine.ts"],"names":[],"mappings":"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"}
|