@nexus_js/sync 0.7.1 → 0.7.4
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/README.md +38 -1
- package/dist/byte-mirror-bridge.d.ts +31 -0
- package/dist/byte-mirror-bridge.d.ts.map +1 -0
- package/dist/byte-mirror-bridge.js +100 -0
- package/dist/byte-mirror-bridge.js.map +1 -0
- package/dist/byte-mirror-protocol.d.ts +81 -0
- package/dist/byte-mirror-protocol.d.ts.map +1 -0
- package/dist/byte-mirror-protocol.js +6 -0
- package/dist/byte-mirror-protocol.js.map +1 -0
- package/dist/byte-mirror-protocol.test.d.ts +2 -0
- package/dist/byte-mirror-protocol.test.d.ts.map +1 -0
- package/dist/byte-mirror-protocol.test.js +49 -0
- package/dist/byte-mirror-protocol.test.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/sync-index.test.d.ts +2 -0
- package/dist/sync-index.test.d.ts.map +1 -0
- package/dist/sync-index.test.js +8 -0
- package/dist/sync-index.test.js.map +1 -0
- package/dist/workers/sqlite-sync.worker.d.ts +7 -0
- package/dist/workers/sqlite-sync.worker.d.ts.map +1 -0
- package/dist/workers/sqlite-sync.worker.js +210 -0
- package/dist/workers/sqlite-sync.worker.js.map +1 -0
- package/package.json +10 -4
package/README.md
CHANGED
|
@@ -1,6 +1,43 @@
|
|
|
1
1
|
# @nexus_js/sync
|
|
2
2
|
|
|
3
|
-
Nexus Local-First Sync
|
|
3
|
+
Nexus Local-First Sync — two tracks:
|
|
4
|
+
|
|
5
|
+
1. **`$localSync` / `syncEngine`** — IndexedDB + JSON ops queue + `fetch` flush (production-ready baseline).
|
|
6
|
+
2. **Byte-Mirror (prototype)** — SQLite WASM inside a **dedicated Web Worker**, with **OPFS** persistence when the host sends COOP/COEP headers (otherwise `:memory:` fallback).
|
|
7
|
+
|
|
8
|
+
## Byte-Mirror (SQLite worker)
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import {
|
|
12
|
+
ByteMirrorBridge,
|
|
13
|
+
resolveSqliteSyncWorkerUrl,
|
|
14
|
+
} from '@nexus_js/sync';
|
|
15
|
+
|
|
16
|
+
const bridge = new ByteMirrorBridge(resolveSqliteSyncWorkerUrl());
|
|
17
|
+
await bridge.init();
|
|
18
|
+
await bridge.upsertNode({
|
|
19
|
+
id: 'n1',
|
|
20
|
+
flowId: 'f1',
|
|
21
|
+
x: 120,
|
|
22
|
+
y: 40,
|
|
23
|
+
data: { label: 'Start' },
|
|
24
|
+
});
|
|
25
|
+
const rows = await bridge.listNodes('f1');
|
|
26
|
+
const outbox = await bridge.drainOutbox(20);
|
|
27
|
+
// POST `outbox[].frame_json` to your Server Action, then:
|
|
28
|
+
await bridge.markOutboxSynced(outbox.map((r) => r.id));
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Security:** the worker never executes arbitrary SQL from the page — only whitelisted ops (`UPSERT_NODE`, `DELETE_NODE`, …).
|
|
32
|
+
|
|
33
|
+
**OPFS:** for durable local SQLite, serve your app with:
|
|
34
|
+
|
|
35
|
+
- `Cross-Origin-Opener-Policy: same-origin`
|
|
36
|
+
- `Cross-Origin-Embedder-Policy: require-corp` (or `credentialless` if compatible with your assets)
|
|
37
|
+
|
|
38
|
+
**Bundlers:** prefer `new Worker(new URL('@nexus_js/sync/workers/sqlite-sync.worker.js', import.meta.url), { type: 'module' })` or Vite’s `?worker` so `@sqlite.org/sqlite-wasm` and `.wasm` resolve correctly.
|
|
39
|
+
|
|
40
|
+
Next steps (not in this package yet): binary ChangeSet protocol, server-side merge / LWW, AES-GCM at rest, and a compiler-backed `$mirror` rune.
|
|
4
41
|
|
|
5
42
|
## Documentation
|
|
6
43
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main-thread bridge to the SQLite WASM sync worker (`workers/sqlite-sync.worker.ts`).
|
|
3
|
+
*/
|
|
4
|
+
import type { ByteMirrorStorageMode, FlowNodePayload, FlowNodeRow, OutboxRow } from './byte-mirror-protocol.js';
|
|
5
|
+
/** Resolve the bundled worker script URL (works from `dist/index.js` in the published package). */
|
|
6
|
+
export declare function resolveSqliteSyncWorkerUrl(): URL;
|
|
7
|
+
/**
|
|
8
|
+
* Typed façade over the SQLite WASM worker. Instantiate with
|
|
9
|
+
* `new ByteMirrorBridge(resolveSqliteSyncWorkerUrl())` or a Vite `?worker` URL.
|
|
10
|
+
*/
|
|
11
|
+
export declare class ByteMirrorBridge {
|
|
12
|
+
#private;
|
|
13
|
+
private readonly worker;
|
|
14
|
+
private readonly pending;
|
|
15
|
+
constructor(workerUrl: URL | string);
|
|
16
|
+
/** Boot SQLite + schema. Call once before other methods. */
|
|
17
|
+
init(opts?: {
|
|
18
|
+
dbFilename?: string;
|
|
19
|
+
}): Promise<{
|
|
20
|
+
storage: ByteMirrorStorageMode;
|
|
21
|
+
}>;
|
|
22
|
+
upsertNode(payload: FlowNodePayload): Promise<void>;
|
|
23
|
+
deleteNode(id: string): Promise<void>;
|
|
24
|
+
listNodes(flowId: string): Promise<FlowNodeRow[]>;
|
|
25
|
+
/** Pull pending sync frames (JSON) to POST to your Server Action. */
|
|
26
|
+
drainOutbox(limit?: number): Promise<OutboxRow[]>;
|
|
27
|
+
/** After the server ACKs frames, remove them from the local outbox. */
|
|
28
|
+
markOutboxSynced(ids: number[]): Promise<void>;
|
|
29
|
+
terminate(): void;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=byte-mirror-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byte-mirror-bridge.d.ts","sourceRoot":"","sources":["../src/byte-mirror-bridge.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,eAAe,EACf,WAAW,EACX,SAAS,EAGV,MAAM,2BAA2B,CAAC;AAEnC,mGAAmG;AACnG,wBAAgB,0BAA0B,IAAI,GAAG,CAEhD;AAID;;;GAGG;AACH,qBAAa,gBAAgB;;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;gBAE1C,SAAS,EAAE,GAAG,GAAG,MAAM;IAqCnC,4DAA4D;IACtD,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,qBAAqB,CAAA;KAAE,CAAC;IAWjF,UAAU,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAMnD,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMrC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAOvD,qEAAqE;IAC/D,WAAW,CAAC,KAAK,SAAK,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAOnD,uEAAuE;IACjE,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpD,SAAS,IAAI,IAAI;CAIlB"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main-thread bridge to the SQLite WASM sync worker (`workers/sqlite-sync.worker.ts`).
|
|
3
|
+
*/
|
|
4
|
+
/** Resolve the bundled worker script URL (works from `dist/index.js` in the published package). */
|
|
5
|
+
export function resolveSqliteSyncWorkerUrl() {
|
|
6
|
+
return new URL('./workers/sqlite-sync.worker.js', import.meta.url);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Typed façade over the SQLite WASM worker. Instantiate with
|
|
10
|
+
* `new ByteMirrorBridge(resolveSqliteSyncWorkerUrl())` or a Vite `?worker` URL.
|
|
11
|
+
*/
|
|
12
|
+
export class ByteMirrorBridge {
|
|
13
|
+
worker;
|
|
14
|
+
pending = new Map();
|
|
15
|
+
constructor(workerUrl) {
|
|
16
|
+
const url = typeof workerUrl === 'string' ? workerUrl : workerUrl.href;
|
|
17
|
+
this.worker = new Worker(url, { type: 'module' });
|
|
18
|
+
this.worker.onmessage = (ev) => {
|
|
19
|
+
const data = ev.data;
|
|
20
|
+
const p = this.pending.get(data.requestId);
|
|
21
|
+
if (!p)
|
|
22
|
+
return;
|
|
23
|
+
this.pending.delete(data.requestId);
|
|
24
|
+
if (data.type === 'ERROR') {
|
|
25
|
+
p.reject(new Error(data.message));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
p.resolve(data);
|
|
29
|
+
};
|
|
30
|
+
this.worker.onmessageerror = () => {
|
|
31
|
+
this.#rejectAll(new Error('Worker message deserialization error'));
|
|
32
|
+
};
|
|
33
|
+
this.worker.addEventListener('error', (e) => {
|
|
34
|
+
const err = e.error instanceof Error ? e.error : new Error('Worker crashed');
|
|
35
|
+
this.#rejectAll(err);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
#rejectAll(err) {
|
|
39
|
+
for (const [, p] of this.pending) {
|
|
40
|
+
p.reject(err);
|
|
41
|
+
}
|
|
42
|
+
this.pending.clear();
|
|
43
|
+
}
|
|
44
|
+
#post(msg) {
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
this.pending.set(msg.requestId, { resolve, reject });
|
|
47
|
+
this.worker.postMessage(msg);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/** Boot SQLite + schema. Call once before other methods. */
|
|
51
|
+
async init(opts) {
|
|
52
|
+
const requestId = crypto.randomUUID();
|
|
53
|
+
const initMsg = opts?.dbFilename !== undefined
|
|
54
|
+
? { type: 'INIT', requestId, dbFilename: opts.dbFilename }
|
|
55
|
+
: { type: 'INIT', requestId };
|
|
56
|
+
const res = await this.#post(initMsg);
|
|
57
|
+
if (res.type !== 'READY')
|
|
58
|
+
throw new Error(`[ByteMirror] expected READY, got ${res.type}`);
|
|
59
|
+
return { storage: res.storage };
|
|
60
|
+
}
|
|
61
|
+
async upsertNode(payload) {
|
|
62
|
+
const requestId = crypto.randomUUID();
|
|
63
|
+
const res = await this.#post({ type: 'UPSERT_NODE', requestId, payload });
|
|
64
|
+
if (res.type !== 'ACK')
|
|
65
|
+
throw new Error(`[ByteMirror] expected ACK, got ${res.type}`);
|
|
66
|
+
}
|
|
67
|
+
async deleteNode(id) {
|
|
68
|
+
const requestId = crypto.randomUUID();
|
|
69
|
+
const res = await this.#post({ type: 'DELETE_NODE', requestId, payload: { id } });
|
|
70
|
+
if (res.type !== 'ACK')
|
|
71
|
+
throw new Error(`[ByteMirror] expected ACK, got ${res.type}`);
|
|
72
|
+
}
|
|
73
|
+
async listNodes(flowId) {
|
|
74
|
+
const requestId = crypto.randomUUID();
|
|
75
|
+
const res = await this.#post({ type: 'LIST_NODES', requestId, payload: { flowId } });
|
|
76
|
+
if (res.type !== 'NODES')
|
|
77
|
+
throw new Error(`[ByteMirror] expected NODES, got ${res.type}`);
|
|
78
|
+
return res.rows;
|
|
79
|
+
}
|
|
80
|
+
/** Pull pending sync frames (JSON) to POST to your Server Action. */
|
|
81
|
+
async drainOutbox(limit = 50) {
|
|
82
|
+
const requestId = crypto.randomUUID();
|
|
83
|
+
const res = await this.#post({ type: 'DRAIN_OUTBOX', requestId, payload: { limit } });
|
|
84
|
+
if (res.type !== 'OUTBOX')
|
|
85
|
+
throw new Error(`[ByteMirror] expected OUTBOX, got ${res.type}`);
|
|
86
|
+
return res.rows;
|
|
87
|
+
}
|
|
88
|
+
/** After the server ACKs frames, remove them from the local outbox. */
|
|
89
|
+
async markOutboxSynced(ids) {
|
|
90
|
+
const requestId = crypto.randomUUID();
|
|
91
|
+
const res = await this.#post({ type: 'MARK_OUTBOX_SYNCED', requestId, payload: { ids } });
|
|
92
|
+
if (res.type !== 'ACK')
|
|
93
|
+
throw new Error(`[ByteMirror] expected ACK, got ${res.type}`);
|
|
94
|
+
}
|
|
95
|
+
terminate() {
|
|
96
|
+
this.worker.terminate();
|
|
97
|
+
this.pending.clear();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=byte-mirror-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byte-mirror-bridge.js","sourceRoot":"","sources":["../src/byte-mirror-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte-Mirror — typed messages between the main thread and the SQLite sync worker.
|
|
3
|
+
* No arbitrary SQL crosses this boundary: only whitelisted mutation kinds (see worker).
|
|
4
|
+
*/
|
|
5
|
+
export type ByteMirrorStorageMode = 'opfs' | 'memory';
|
|
6
|
+
/** Payload for flow-editor style nodes (NexusFlow-oriented). */
|
|
7
|
+
export interface FlowNodePayload {
|
|
8
|
+
id: string;
|
|
9
|
+
flowId: string;
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
/** Extra JSON-serializable fields (ports, label, etc.) */
|
|
13
|
+
data?: Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
export type SqliteSyncWorkerInboundMessage = {
|
|
16
|
+
type: 'INIT';
|
|
17
|
+
requestId: string;
|
|
18
|
+
dbFilename?: string;
|
|
19
|
+
} | {
|
|
20
|
+
type: 'UPSERT_NODE';
|
|
21
|
+
requestId: string;
|
|
22
|
+
payload: FlowNodePayload;
|
|
23
|
+
} | {
|
|
24
|
+
type: 'DELETE_NODE';
|
|
25
|
+
requestId: string;
|
|
26
|
+
payload: {
|
|
27
|
+
id: string;
|
|
28
|
+
};
|
|
29
|
+
} | {
|
|
30
|
+
type: 'LIST_NODES';
|
|
31
|
+
requestId: string;
|
|
32
|
+
payload: {
|
|
33
|
+
flowId: string;
|
|
34
|
+
};
|
|
35
|
+
} | {
|
|
36
|
+
type: 'DRAIN_OUTBOX';
|
|
37
|
+
requestId: string;
|
|
38
|
+
payload: {
|
|
39
|
+
limit: number;
|
|
40
|
+
};
|
|
41
|
+
} | {
|
|
42
|
+
type: 'MARK_OUTBOX_SYNCED';
|
|
43
|
+
requestId: string;
|
|
44
|
+
payload: {
|
|
45
|
+
ids: number[];
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
export type FlowNodeRow = {
|
|
49
|
+
id: string;
|
|
50
|
+
flow_id: string;
|
|
51
|
+
x: number;
|
|
52
|
+
y: number;
|
|
53
|
+
data_json: string;
|
|
54
|
+
updated_at: number;
|
|
55
|
+
};
|
|
56
|
+
export type OutboxRow = {
|
|
57
|
+
id: number;
|
|
58
|
+
frame_json: string;
|
|
59
|
+
created_at: number;
|
|
60
|
+
};
|
|
61
|
+
export type SqliteSyncWorkerOutboundMessage = {
|
|
62
|
+
type: 'READY';
|
|
63
|
+
requestId: string;
|
|
64
|
+
storage: ByteMirrorStorageMode;
|
|
65
|
+
} | {
|
|
66
|
+
type: 'ACK';
|
|
67
|
+
requestId: string;
|
|
68
|
+
} | {
|
|
69
|
+
type: 'NODES';
|
|
70
|
+
requestId: string;
|
|
71
|
+
rows: FlowNodeRow[];
|
|
72
|
+
} | {
|
|
73
|
+
type: 'OUTBOX';
|
|
74
|
+
requestId: string;
|
|
75
|
+
rows: OutboxRow[];
|
|
76
|
+
} | {
|
|
77
|
+
type: 'ERROR';
|
|
78
|
+
requestId: string;
|
|
79
|
+
message: string;
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=byte-mirror-protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byte-mirror-protocol.d.ts","sourceRoot":"","sources":["../src/byte-mirror-protocol.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEtD,gEAAgE;AAChE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,MAAM,8BAA8B,GACtC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,eAAe,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACvE;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;CAAE,CAAC;AAElF,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/E,MAAM,MAAM,+BAA+B,GACvC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,qBAAqB,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,EAAE,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,EAAE,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byte-mirror-protocol.js","sourceRoot":"","sources":["../src/byte-mirror-protocol.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byte-mirror-protocol.test.d.ts","sourceRoot":"","sources":["../src/byte-mirror-protocol.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
describe('byte-mirror-protocol', () => {
|
|
3
|
+
it('round-trips representative inbound messages as JSON', () => {
|
|
4
|
+
const messages = [
|
|
5
|
+
{ type: 'INIT', requestId: 'r1' },
|
|
6
|
+
{ type: 'INIT', requestId: 'r2', dbFilename: '/custom.sqlite' },
|
|
7
|
+
{
|
|
8
|
+
type: 'UPSERT_NODE',
|
|
9
|
+
requestId: 'r3',
|
|
10
|
+
payload: { id: 'n1', flowId: 'f1', x: 1, y: 2, data: { label: 'a' } },
|
|
11
|
+
},
|
|
12
|
+
{ type: 'DELETE_NODE', requestId: 'r4', payload: { id: 'n1' } },
|
|
13
|
+
{ type: 'LIST_NODES', requestId: 'r5', payload: { flowId: 'f1' } },
|
|
14
|
+
{ type: 'DRAIN_OUTBOX', requestId: 'r6', payload: { limit: 10 } },
|
|
15
|
+
{ type: 'MARK_OUTBOX_SYNCED', requestId: 'r7', payload: { ids: [1, 2] } },
|
|
16
|
+
];
|
|
17
|
+
for (const m of messages) {
|
|
18
|
+
const copy = JSON.parse(JSON.stringify(m));
|
|
19
|
+
expect(copy).toEqual(m);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
it('round-trips representative outbound messages', () => {
|
|
23
|
+
const out = [
|
|
24
|
+
{ type: 'READY', requestId: 'a', storage: 'memory' },
|
|
25
|
+
{ type: 'READY', requestId: 'b', storage: 'opfs' },
|
|
26
|
+
{ type: 'ACK', requestId: 'c' },
|
|
27
|
+
{
|
|
28
|
+
type: 'NODES',
|
|
29
|
+
requestId: 'd',
|
|
30
|
+
rows: [
|
|
31
|
+
{
|
|
32
|
+
id: '1',
|
|
33
|
+
flow_id: 'f',
|
|
34
|
+
x: 0,
|
|
35
|
+
y: 0,
|
|
36
|
+
data_json: '{}',
|
|
37
|
+
updated_at: 1,
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
{ type: 'OUTBOX', requestId: 'e', rows: [{ id: 1, frame_json: '{}', created_at: 2 }] },
|
|
42
|
+
{ type: 'ERROR', requestId: 'f', message: 'x' },
|
|
43
|
+
];
|
|
44
|
+
for (const m of out) {
|
|
45
|
+
expect(JSON.parse(JSON.stringify(m))).toEqual(m);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
//# sourceMappingURL=byte-mirror-protocol.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byte-mirror-protocol.test.js","sourceRoot":"","sources":["../src/byte-mirror-protocol.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAM9C,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,QAAQ,GAAqC;YACjD,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE;YACjC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,gBAAgB,EAAE;YAC/D;gBACE,IAAI,EAAU,aAAa;gBAC3B,SAAS,EAAK,IAAI;gBAClB,OAAO,EAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;aAC3E;YACD,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE;YAC/D,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;YAClE,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YACjE,EAAE,IAAI,EAAE,oBAAoB,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE;SAC1E,CAAC;QACF,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAmC,CAAC;YAC7E,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,GAAG,GAAsC;YAC7C,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE;YACpD,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE;YAClD,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE;YAC/B;gBACE,IAAI,EAAO,OAAO;gBAClB,SAAS,EAAE,GAAG;gBACd,IAAI,EAAO;oBACT;wBACE,EAAE,EAAU,GAAG;wBACf,OAAO,EAAK,GAAG;wBACf,CAAC,EAAW,CAAC;wBACb,CAAC,EAAW,CAAC;wBACb,SAAS,EAAG,IAAI;wBAChB,UAAU,EAAE,CAAC;qBACd;iBACF;aACF;YACD,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,EAAE;YACtF,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE;SAChD,CAAC;QACF,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;YACpB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACnD,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,9 @@ export { syncEngine, NexusSyncEngine } from './engine.js';
|
|
|
8
8
|
export type { SyncOp, SyncStatus, SyncCollectionOpts, ConflictInfo } from './engine.js';
|
|
9
9
|
export { $localSync } from './rune.js';
|
|
10
10
|
export type { LocalSyncState, LocalSyncOpts } from './rune.js';
|
|
11
|
+
/** Byte-Mirror — SQLite WASM in a worker (OPFS / memory fallback). */
|
|
12
|
+
export { ByteMirrorBridge, resolveSqliteSyncWorkerUrl, } from './byte-mirror-bridge.js';
|
|
13
|
+
export type { ByteMirrorStorageMode, FlowNodePayload, FlowNodeRow, OutboxRow, SqliteSyncWorkerInboundMessage, SqliteSyncWorkerOutboundMessage, } from './byte-mirror-protocol.js';
|
|
11
14
|
/** Convenience: check if the browser is currently online. */
|
|
12
15
|
export declare const isOnline: () => boolean;
|
|
13
16
|
/** Returns a promise that resolves when the browser comes back online. */
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC1D,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExF,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/D,6DAA6D;AAC7D,eAAO,MAAM,QAAQ,QAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC1D,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExF,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/D,sEAAsE;AACtE,OAAO,EACL,gBAAgB,EAChB,0BAA0B,GAC3B,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,qBAAqB,EACrB,eAAe,EACf,WAAW,EACX,SAAS,EACT,8BAA8B,EAC9B,+BAA+B,GAChC,MAAM,2BAA2B,CAAC;AAEnC,6DAA6D;AAC7D,eAAO,MAAM,QAAQ,QAAO,OAG3B,CAAC;AAEF,0EAA0E;AAC1E,wBAAgB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAM7C"}
|
package/dist/index.js
CHANGED
|
@@ -6,8 +6,14 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export { syncEngine, NexusSyncEngine } from './engine.js';
|
|
8
8
|
export { $localSync } from './rune.js';
|
|
9
|
+
/** Byte-Mirror — SQLite WASM in a worker (OPFS / memory fallback). */
|
|
10
|
+
export { ByteMirrorBridge, resolveSqliteSyncWorkerUrl, } from './byte-mirror-bridge.js';
|
|
9
11
|
/** Convenience: check if the browser is currently online. */
|
|
10
|
-
export const isOnline = () =>
|
|
12
|
+
export const isOnline = () => {
|
|
13
|
+
if (typeof navigator === 'undefined')
|
|
14
|
+
return true;
|
|
15
|
+
return navigator.onLine !== false;
|
|
16
|
+
};
|
|
11
17
|
/** Returns a promise that resolves when the browser comes back online. */
|
|
12
18
|
export function waitForOnline() {
|
|
13
19
|
if (isOnline())
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG1D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC,6DAA6D;AAC7D,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG1D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC,sEAAsE;AACtE,OAAO,EACL,gBAAgB,EAChB,0BAA0B,GAC3B,MAAM,yBAAyB,CAAC;AAUjC,6DAA6D;AAC7D,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAY,EAAE;IACpC,IAAI,OAAO,SAAS,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IAClD,OAAO,SAAS,CAAC,MAAM,KAAK,KAAK,CAAC;AACpC,CAAC,CAAC;AAEF,0EAA0E;AAC1E,MAAM,UAAU,aAAa;IAC3B,IAAI,QAAQ,EAAE;QAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IACzC,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QACnC,MAAM,OAAO,GAAG,GAAG,EAAE,GAAG,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QACpF,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-index.test.d.ts","sourceRoot":"","sources":["../src/sync-index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { isOnline } from './index.js';
|
|
3
|
+
describe('@nexus_js/sync entry', () => {
|
|
4
|
+
it('isOnline is true when navigator is undefined (Node)', () => {
|
|
5
|
+
expect(isOnline()).toBe(true);
|
|
6
|
+
});
|
|
7
|
+
});
|
|
8
|
+
//# sourceMappingURL=sync-index.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-index.test.js","sourceRoot":"","sources":["../src/sync-index.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-sync.worker.d.ts","sourceRoot":"","sources":["../../src/workers/sqlite-sync.worker.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nexus Byte-Mirror — SQLite WASM worker (OPFS when COOP/COEP allow it, else :memory:).
|
|
3
|
+
*
|
|
4
|
+
* Security: accepts only structured mutation messages — never raw SQL strings from the UI.
|
|
5
|
+
*/
|
|
6
|
+
/// <reference lib="webworker" />
|
|
7
|
+
import sqlite3InitModule from '@sqlite.org/sqlite-wasm';
|
|
8
|
+
let db = null;
|
|
9
|
+
function reply(msg) {
|
|
10
|
+
self.postMessage(msg);
|
|
11
|
+
}
|
|
12
|
+
function ensureDb() {
|
|
13
|
+
if (!db)
|
|
14
|
+
throw new Error('[Nexus Byte-Mirror] Worker not initialized (send INIT first)');
|
|
15
|
+
return db;
|
|
16
|
+
}
|
|
17
|
+
function runSchema(d) {
|
|
18
|
+
d.exec(`
|
|
19
|
+
CREATE TABLE IF NOT EXISTS nexus_flow_nodes (
|
|
20
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
21
|
+
flow_id TEXT NOT NULL,
|
|
22
|
+
x REAL NOT NULL,
|
|
23
|
+
y REAL NOT NULL,
|
|
24
|
+
data_json TEXT NOT NULL DEFAULT '{}',
|
|
25
|
+
updated_at INTEGER NOT NULL
|
|
26
|
+
);
|
|
27
|
+
CREATE INDEX IF NOT EXISTS idx_nexus_flow_nodes_flow ON nexus_flow_nodes(flow_id);
|
|
28
|
+
`);
|
|
29
|
+
d.exec(`
|
|
30
|
+
CREATE TABLE IF NOT EXISTS nexus_sync_outbox (
|
|
31
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
32
|
+
frame_json TEXT NOT NULL,
|
|
33
|
+
created_at INTEGER NOT NULL
|
|
34
|
+
);
|
|
35
|
+
`);
|
|
36
|
+
}
|
|
37
|
+
function enqueueOutbox(frame) {
|
|
38
|
+
const d = ensureDb();
|
|
39
|
+
const stmt = d.prepare(`INSERT INTO nexus_sync_outbox (frame_json, created_at) VALUES (?1, ?2)`);
|
|
40
|
+
try {
|
|
41
|
+
stmt.bind(1, JSON.stringify(frame));
|
|
42
|
+
stmt.bind(2, Date.now());
|
|
43
|
+
while (stmt.step()) {
|
|
44
|
+
/* drain */
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
stmt.finalize();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function upsertNode(payload) {
|
|
52
|
+
const d = ensureDb();
|
|
53
|
+
const dataJson = JSON.stringify(payload.data ?? {});
|
|
54
|
+
const stmt = d.prepare(`
|
|
55
|
+
INSERT INTO nexus_flow_nodes (id, flow_id, x, y, data_json, updated_at)
|
|
56
|
+
VALUES (?1, ?2, ?3, ?4, ?5, ?6)
|
|
57
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
58
|
+
flow_id = excluded.flow_id,
|
|
59
|
+
x = excluded.x,
|
|
60
|
+
y = excluded.y,
|
|
61
|
+
data_json = excluded.data_json,
|
|
62
|
+
updated_at = excluded.updated_at
|
|
63
|
+
`);
|
|
64
|
+
try {
|
|
65
|
+
stmt.bind(1, payload.id);
|
|
66
|
+
stmt.bind(2, payload.flowId);
|
|
67
|
+
stmt.bind(3, payload.x);
|
|
68
|
+
stmt.bind(4, payload.y);
|
|
69
|
+
stmt.bind(5, dataJson);
|
|
70
|
+
stmt.bind(6, Date.now());
|
|
71
|
+
while (stmt.step()) {
|
|
72
|
+
/* drain */
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
stmt.finalize();
|
|
77
|
+
}
|
|
78
|
+
enqueueOutbox({ kind: 'upsert_node', ...payload, data: payload.data ?? {} });
|
|
79
|
+
}
|
|
80
|
+
function deleteNode(id) {
|
|
81
|
+
const d = ensureDb();
|
|
82
|
+
const stmt = d.prepare(`DELETE FROM nexus_flow_nodes WHERE id = ?1`);
|
|
83
|
+
try {
|
|
84
|
+
stmt.bind(1, id);
|
|
85
|
+
while (stmt.step()) {
|
|
86
|
+
/* drain */
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
stmt.finalize();
|
|
91
|
+
}
|
|
92
|
+
enqueueOutbox({ kind: 'delete_node', id });
|
|
93
|
+
}
|
|
94
|
+
function listNodes(flowId) {
|
|
95
|
+
const d = ensureDb();
|
|
96
|
+
const rows = d.exec({
|
|
97
|
+
sql: `SELECT id, flow_id, x, y, data_json, updated_at FROM nexus_flow_nodes WHERE flow_id = ?1 ORDER BY id`,
|
|
98
|
+
bind: [flowId],
|
|
99
|
+
returnValue: 'resultRows',
|
|
100
|
+
rowMode: 'object',
|
|
101
|
+
});
|
|
102
|
+
return rows ?? [];
|
|
103
|
+
}
|
|
104
|
+
function drainOutbox(limit) {
|
|
105
|
+
const d = ensureDb();
|
|
106
|
+
const rows = d.exec({
|
|
107
|
+
sql: `SELECT id, frame_json, created_at FROM nexus_sync_outbox ORDER BY id ASC LIMIT ?1`,
|
|
108
|
+
bind: [limit],
|
|
109
|
+
returnValue: 'resultRows',
|
|
110
|
+
rowMode: 'object',
|
|
111
|
+
});
|
|
112
|
+
return rows ?? [];
|
|
113
|
+
}
|
|
114
|
+
function markOutboxSynced(ids) {
|
|
115
|
+
if (ids.length === 0)
|
|
116
|
+
return;
|
|
117
|
+
const d = ensureDb();
|
|
118
|
+
const placeholders = ids.map((_, i) => `?${i + 1}`).join(',');
|
|
119
|
+
const stmt = d.prepare(`DELETE FROM nexus_sync_outbox WHERE id IN (${placeholders})`);
|
|
120
|
+
try {
|
|
121
|
+
for (let i = 0; i < ids.length; i++) {
|
|
122
|
+
stmt.bind(i + 1, ids[i]);
|
|
123
|
+
}
|
|
124
|
+
while (stmt.step()) {
|
|
125
|
+
/* drain */
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
stmt.finalize();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function handleInit(requestId, dbFilename) {
|
|
133
|
+
const sqlite3 = await sqlite3InitModule({
|
|
134
|
+
print: () => undefined,
|
|
135
|
+
printErr: (m) => console.error('[sqlite-wasm]', m),
|
|
136
|
+
});
|
|
137
|
+
const oo1 = sqlite3.oo1;
|
|
138
|
+
const file = dbFilename ?? '/nexus_byte_mirror.sqlite';
|
|
139
|
+
let storage = 'memory';
|
|
140
|
+
try {
|
|
141
|
+
const OpfsDb = oo1.OpfsDb;
|
|
142
|
+
if (OpfsDb) {
|
|
143
|
+
db = new OpfsDb(file, 'c');
|
|
144
|
+
storage = 'opfs';
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
db = new oo1.DB(':memory:');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
db = new oo1.DB(':memory:');
|
|
152
|
+
storage = 'memory';
|
|
153
|
+
}
|
|
154
|
+
runSchema(db);
|
|
155
|
+
reply({ type: 'READY', requestId, storage });
|
|
156
|
+
}
|
|
157
|
+
self.onmessage = async (ev) => {
|
|
158
|
+
const msg = ev.data;
|
|
159
|
+
const requestId = msg.requestId;
|
|
160
|
+
try {
|
|
161
|
+
switch (msg.type) {
|
|
162
|
+
case 'INIT':
|
|
163
|
+
await handleInit(requestId, msg.dbFilename);
|
|
164
|
+
break;
|
|
165
|
+
case 'UPSERT_NODE':
|
|
166
|
+
ensureDb();
|
|
167
|
+
upsertNode(msg.payload);
|
|
168
|
+
reply({ type: 'ACK', requestId });
|
|
169
|
+
break;
|
|
170
|
+
case 'DELETE_NODE':
|
|
171
|
+
ensureDb();
|
|
172
|
+
deleteNode(msg.payload.id);
|
|
173
|
+
reply({ type: 'ACK', requestId });
|
|
174
|
+
break;
|
|
175
|
+
case 'LIST_NODES': {
|
|
176
|
+
ensureDb();
|
|
177
|
+
const raw = listNodes(msg.payload.flowId);
|
|
178
|
+
const rows = raw.map((r) => ({
|
|
179
|
+
id: String(r.id),
|
|
180
|
+
flow_id: String(r.flow_id),
|
|
181
|
+
x: Number(r.x),
|
|
182
|
+
y: Number(r.y),
|
|
183
|
+
data_json: String(r.data_json ?? '{}'),
|
|
184
|
+
updated_at: Number(r.updated_at),
|
|
185
|
+
}));
|
|
186
|
+
reply({ type: 'NODES', requestId, rows });
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
case 'DRAIN_OUTBOX': {
|
|
190
|
+
ensureDb();
|
|
191
|
+
const rows = drainOutbox(Math.max(1, Math.min(500, msg.payload.limit)));
|
|
192
|
+
reply({ type: 'OUTBOX', requestId, rows });
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
case 'MARK_OUTBOX_SYNCED': {
|
|
196
|
+
ensureDb();
|
|
197
|
+
markOutboxSynced(msg.payload.ids);
|
|
198
|
+
reply({ type: 'ACK', requestId });
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
default:
|
|
202
|
+
reply({ type: 'ERROR', requestId, message: 'Unknown worker message type' });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
catch (e) {
|
|
206
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
207
|
+
reply({ type: 'ERROR', requestId, message });
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
//# sourceMappingURL=sqlite-sync.worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-sync.worker.js","sourceRoot":"","sources":["../../src/workers/sqlite-sync.worker.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexus_js/sync",
|
|
3
|
-
"version": "0.7.
|
|
4
|
-
"description": "Nexus Local-First Sync
|
|
3
|
+
"version": "0.7.4",
|
|
4
|
+
"description": "Nexus Local-First Sync — IndexedDB engine ($localSync) + Byte-Mirror prototype (SQLite WASM worker / OPFS)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
".": {
|
|
10
10
|
"import": "./dist/index.js",
|
|
11
11
|
"types": "./dist/index.d.ts"
|
|
12
|
-
}
|
|
12
|
+
},
|
|
13
|
+
"./workers/sqlite-sync.worker.js": "./dist/workers/sqlite-sync.worker.js"
|
|
13
14
|
},
|
|
14
15
|
"keywords": [
|
|
15
16
|
"nexus",
|
|
@@ -37,7 +38,8 @@
|
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
39
40
|
"@types/node": "^22.0.0",
|
|
40
|
-
"typescript": "^5.5.0"
|
|
41
|
+
"typescript": "^5.5.0",
|
|
42
|
+
"vitest": "^2.0.0"
|
|
41
43
|
},
|
|
42
44
|
"files": [
|
|
43
45
|
"dist",
|
|
@@ -47,9 +49,13 @@
|
|
|
47
49
|
"access": "public",
|
|
48
50
|
"registry": "https://registry.npmjs.org/"
|
|
49
51
|
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@sqlite.org/sqlite-wasm": "3.48.0-build1"
|
|
54
|
+
},
|
|
50
55
|
"scripts": {
|
|
51
56
|
"build": "tsc -p tsconfig.json",
|
|
52
57
|
"dev": "tsc -p tsconfig.json --watch",
|
|
58
|
+
"test": "vitest run",
|
|
53
59
|
"clean": "rm -rf dist"
|
|
54
60
|
}
|
|
55
61
|
}
|