@doync/client 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/LICENSE +21 -0
- package/README.md +233 -0
- package/dist/adapter.cjs +1 -0
- package/dist/adapter.d.cts +86 -0
- package/dist/adapter.d.cts.map +1 -0
- package/dist/adapter.d.ts +86 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +2 -0
- package/dist/adapter.js.map +1 -0
- package/dist/client-C6jAdhbe.cjs +15 -0
- package/dist/client-CNyLMCw0.d.ts +812 -0
- package/dist/client-CNyLMCw0.d.ts.map +1 -0
- package/dist/client-ClV8ce6X.js +16 -0
- package/dist/client-ClV8ce6X.js.map +1 -0
- package/dist/client-DHXO0dbf.d.cts +812 -0
- package/dist/client-DHXO0dbf.d.cts.map +1 -0
- package/dist/index.cjs +0 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +0 -0
- package/dist/internal.cjs +1 -0
- package/dist/internal.d.cts +69 -0
- package/dist/internal.d.cts.map +1 -0
- package/dist/internal.d.ts +69 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +2 -0
- package/dist/internal.js.map +1 -0
- package/package.json +79 -0
- package/src/adapter.ts +25 -0
- package/src/client-mutation-registry.ts +31 -0
- package/src/client.ts +100 -0
- package/src/engine.ts +3322 -0
- package/src/identity.ts +41 -0
- package/src/index.ts +36 -0
- package/src/internal.ts +37 -0
- package/src/migrate.ts +156 -0
- package/src/mutations.ts +96 -0
- package/src/port.ts +74 -0
- package/src/raw-read.ts +135 -0
- package/src/replica/db/0000_replica_engine_v0.sql +20 -0
- package/src/replica/db/0001_release_stamps.sql +6 -0
- package/src/replica/db/meta/0000_snapshot.json +129 -0
- package/src/replica/db/meta/0001_snapshot.json +167 -0
- package/src/replica/db/meta/_journal.json +20 -0
- package/src/replica/db/schema.ts +67 -0
- package/src/replica/index.ts +185 -0
- package/src/replica/meta.ts +26 -0
- package/src/replica/stamps.ts +102 -0
- package/src/replica/track.ts +190 -0
- package/src/socket-reconnect.ts +242 -0
- package/src/socket.ts +44 -0
- package/src/sql-raw.d.ts +4 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-DHXO0dbf.d.cts","names":["Input","Output","StandardTypedV1","Props","version","vendor","types","Types","input","output","InferInput","Schema","NonNullable","InferOutput","StandardSchemaV1","validate","value","Options","options","Result","Promise","SuccessResult","FailureResult","issues","libraryOptions","Record","ReadonlyArray","Issue","message","path","PropertyKey","PathSegment","key","StandardJSONSchemaV1","jsonSchema","Converter","Target","target"],"sources":["../../../node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.d.ts","../src/port.ts","../src/mutations.ts","../src/socket.ts","../src/replica/meta.ts","../src/replica/stamps.ts","../src/replica/index.ts","../src/engine.ts","../src/client.ts"],"x_google_ignoreList":[0],"mappings":"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"}
|
package/dist/index.cjs
ADDED
|
File without changes
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { F as ClientMutation, I as ClientMutationHandler, L as ClientMutationRegistry, R as ClientMutationTx, _ as SchemaEventKind, b as ViewStatus, c as FalsyQuery, d as MutationResult, f as OnceView, g as SchemaEvent, h as QueryStatus, l as LogoutBehavior, m as PreloadOptions, o as ConnectionStatus, p as PreloadHandle, s as DoyncClient, u as MutationOptions, v as SubscribeOptions, y as View } from "./client-DHXO0dbf.cjs";
|
|
2
|
+
export type { ClientMutation, ClientMutationHandler, ClientMutationRegistry, ClientMutationTx, ConnectionStatus, DoyncClient, FalsyQuery, LogoutBehavior, MutationOptions, MutationResult, OnceView, PreloadHandle, PreloadOptions, QueryStatus, SchemaEvent, SchemaEventKind, SubscribeOptions, View, ViewStatus };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { F as ClientMutation, I as ClientMutationHandler, L as ClientMutationRegistry, R as ClientMutationTx, _ as SchemaEventKind, b as ViewStatus, c as FalsyQuery, d as MutationResult, f as OnceView, g as SchemaEvent, h as QueryStatus, l as LogoutBehavior, m as PreloadOptions, o as ConnectionStatus, p as PreloadHandle, s as DoyncClient, u as MutationOptions, v as SubscribeOptions, y as View } from "./client-CNyLMCw0.js";
|
|
2
|
+
export type { ClientMutation, ClientMutationHandler, ClientMutationRegistry, ClientMutationTx, ConnectionStatus, DoyncClient, FalsyQuery, LogoutBehavior, MutationOptions, MutationResult, OnceView, PreloadHandle, PreloadOptions, QueryStatus, SchemaEvent, SchemaEventKind, SubscribeOptions, View, ViewStatus };
|
package/dist/index.js
ADDED
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./client-C6jAdhbe.cjs");let t=require("@doync/sqlite-parser");function n(e){return encodeURIComponent(e).replaceAll(`_`,`%5F`)}function r(e,t){let r=n(e);return t===null?`doync__${r}__anon.db`:`doync__${r}__${n(t)}.db`}function i(e){let n;try{n=(0,t.parse)(e)}catch(t){return console.warn(`extractWriteTable: failed to parse SQL statement`,{sql:e,err:t}),null}switch(n.kind){case`STMT_INSERT`:case`STMT_UPDATE`:case`STMT_DELETE`:return n.table??null;default:return null}}exports.ClientEngine=e.r,exports.__CONNECTED_CLOCK_META_KEY=e.i,exports.__LOGOUT_BEHAVIOR_META_KEY=e.a,exports.applyBundledMigrations=e.l,exports.asClientMutation=e.v,exports.bundledSchemaDdl=e.h,exports.classifyClientStatement=e.g,exports.createClientEngine=e.n,exports.createEngineTables=e.u,exports.dbFileForUserId=r,exports.dropConsumerTables=e.d,exports.extractWriteTable=i,exports.isFalsyQuery=e.o,exports.normalizeQuerySurface=e.s,exports.readMeta=e.p,exports.replayMigrations=e.f,exports.settledRejection=e.c,exports.splitClientStatements=e._,exports.toClientMutationRegistry=e.b,exports.validateMutationArgs=e.y,exports.writeMeta=e.m;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { A as readMeta, B as validateMutationArgs, C as isFalsyQuery, D as createEngineTables, E as applyBundledMigrations, L as ClientMutationRegistry, O as dropConsumerTables, S as __LOGOUT_BEHAVIOR_META_KEY, T as settledRejection, U as extractWriteTable, a as ClientEngineConfig, i as ClientEngine, j as writeMeta, k as replayMigrations, r as createClientEngine, w as normalizeQuerySurface, x as __CONNECTED_CLOCK_META_KEY, z as asClientMutation } from "./client-DHXO0dbf.cjs";
|
|
2
|
+
import { DoyncSchema, MutationTree } from "@doync/core";
|
|
3
|
+
|
|
4
|
+
//#region src/client-mutation-registry.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Flat `dottedName → {args, handler}` registry the client engine resolves
|
|
7
|
+
* optimistic bodies against (ADR-0019). Feed the SHARED tree so no `.server.ts`
|
|
8
|
+
* override enters the client bundle. Handler may return a promise (exclusive
|
|
9
|
+
* chain awaits); engine validates args at `mutate()` via carried schema.
|
|
10
|
+
*/
|
|
11
|
+
declare function toClientMutationRegistry(tree: MutationTree): ClientMutationRegistry;
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/identity.d.ts
|
|
14
|
+
/**
|
|
15
|
+
* Durable replica file for one `(Database name, asserted userId)` pair:
|
|
16
|
+
* `doync__<name>__anon.db` when `userId` is `null`, else
|
|
17
|
+
* `doync__<name>__<userId>.db`. Separators are `__` so hyphens (common in UUIDs
|
|
18
|
+
* and ids) stay unescaped and filenames stay short enough for OPFS. Each half
|
|
19
|
+
* is percent-encoded; `_` is additionally escaped so halves cannot forge a
|
|
20
|
+
* separator.
|
|
21
|
+
*/
|
|
22
|
+
declare function dbFileForUserId(name: string, userId: string | null): string;
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/migrate.d.ts
|
|
25
|
+
/**
|
|
26
|
+
* Parser-backed SQL classification for client DDL-only bundled-track replay
|
|
27
|
+
* (ADR-0020 / ADR-0006). Same AST as the server conversation, narrower API: 1.
|
|
28
|
+
* split migrations keeping trigger BEGIN…END whole; 2. ddl vs trigger (skip —
|
|
29
|
+
* apply state, never enforce; ADR-0009/0020) vs backfill DML (skip — data via
|
|
30
|
+
* feed; ADR-0006). Fails closed on unparseable input.
|
|
31
|
+
*/
|
|
32
|
+
/** How the client treats one already-split migration statement. */
|
|
33
|
+
type ClientStatementKind = "ddl" | "trigger" | "dml" | "pragma" | "other";
|
|
34
|
+
/**
|
|
35
|
+
* Split a migration's SQL into its top-level statements. The parser understands
|
|
36
|
+
* statement structure, so a `CREATE TRIGGER … BEGIN … END` body's internal
|
|
37
|
+
* semicolons stay inside one statement — a migration may mix a trigger with
|
|
38
|
+
* surrounding DDL without mis-splitting. Each statement is returned as its
|
|
39
|
+
* canonical unparse (semantically identical to the source); statements that are
|
|
40
|
+
* empty (whitespace/comments only) yield nothing.
|
|
41
|
+
*
|
|
42
|
+
* Fails closed: an unparseable script throws a clear error rather than applying
|
|
43
|
+
* a partial or mis-read migration. Trusted input only in the sense that the
|
|
44
|
+
* consumer authored the migrations — the parse itself validates their syntax.
|
|
45
|
+
*/
|
|
46
|
+
declare function splitClientStatements(sql: string): string[];
|
|
47
|
+
/**
|
|
48
|
+
* Classify ONE already-split statement by its parsed kind. `CREATE TRIGGER` and
|
|
49
|
+
* `DROP TRIGGER` are `'trigger'` (the client neither creates nor drops triggers
|
|
50
|
+
* — it runs none, ADR-0009); every other shape-changing DDL is `'ddl'`
|
|
51
|
+
* (replayed); the row read/write verbs are `'dml'` (backfill, never replayed on
|
|
52
|
+
* the client); `PRAGMA` and anything unrecognized/unparseable land in their own
|
|
53
|
+
* buckets.
|
|
54
|
+
*/
|
|
55
|
+
declare function classifyClientStatement(statement: string): ClientStatementKind;
|
|
56
|
+
/**
|
|
57
|
+
* The non-trigger DDL statements of the bundled migrations in the half-open
|
|
58
|
+
* range `(fromVersion, toVersion]` (0-based migration indices `fromVersion …
|
|
59
|
+
* toVersion − 1`), in order — the replayable shape for the client's DDL-only
|
|
60
|
+
* bundled-track replay (ADR-0020). Trigger DDL is skipped (ADR-0009) and
|
|
61
|
+
* backfill DML never runs on the client (ADR-0006). Passing `fromVersion = 0`
|
|
62
|
+
* yields the full track up to `toVersion` (a fresh replica); a higher
|
|
63
|
+
* `fromVersion` yields just the newly-appended migrations (a mid-session
|
|
64
|
+
* catch-up).
|
|
65
|
+
*/
|
|
66
|
+
declare function bundledSchemaDdl(schema: DoyncSchema, fromVersion: number, toVersion: number): string[];
|
|
67
|
+
//#endregion
|
|
68
|
+
export { ClientEngine, type ClientEngineConfig, type ClientStatementKind, __CONNECTED_CLOCK_META_KEY, __LOGOUT_BEHAVIOR_META_KEY, applyBundledMigrations, asClientMutation, bundledSchemaDdl, classifyClientStatement, createClientEngine, createEngineTables, dbFileForUserId, dropConsumerTables, extractWriteTable, isFalsyQuery, normalizeQuerySurface, readMeta, replayMigrations, settledRejection, splitClientStatements, toClientMutationRegistry, validateMutationArgs, writeMeta };
|
|
69
|
+
//# sourceMappingURL=internal.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.d.cts","names":[],"sources":["../src/client-mutation-registry.ts","../src/identity.ts","../src/migrate.ts"],"mappings":";;;;;;;;AAqBG;;iBAFa,wBAAA,CACd,IAAA,EAAM,YAAA,GACL,sBAAA;;;;;;;AAFH;;;;iBCgBgB,eAAA,CAAgB,IAAA,UAAc,MAAA;;;;;;ADhB9C;;;;;KEAY,mBAAA;;;AFET;;;;ACcH;;;;AAA8C;;iBCgE9B,qBAAA,CAAsB,GAAA;;AAhFtC;;;;AAAY;AAgFZ;;iBAkBgB,uBAAA,CACd,SAAA,WACC,mBAAA;;AApBmC;AAkBtC;;;;AAEG;AAeH;;;iBAAgB,gBAAA,CACd,MAAA,EAAQ,WAAA,EACR,WAAA,UACA,SAAA"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { A as readMeta, B as validateMutationArgs, C as isFalsyQuery, D as createEngineTables, E as applyBundledMigrations, L as ClientMutationRegistry, O as dropConsumerTables, S as __LOGOUT_BEHAVIOR_META_KEY, T as settledRejection, U as extractWriteTable, a as ClientEngineConfig, i as ClientEngine, j as writeMeta, k as replayMigrations, r as createClientEngine, w as normalizeQuerySurface, x as __CONNECTED_CLOCK_META_KEY, z as asClientMutation } from "./client-CNyLMCw0.js";
|
|
2
|
+
import { DoyncSchema, MutationTree } from "@doync/core";
|
|
3
|
+
|
|
4
|
+
//#region src/client-mutation-registry.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Flat `dottedName → {args, handler}` registry the client engine resolves
|
|
7
|
+
* optimistic bodies against (ADR-0019). Feed the SHARED tree so no `.server.ts`
|
|
8
|
+
* override enters the client bundle. Handler may return a promise (exclusive
|
|
9
|
+
* chain awaits); engine validates args at `mutate()` via carried schema.
|
|
10
|
+
*/
|
|
11
|
+
declare function toClientMutationRegistry(tree: MutationTree): ClientMutationRegistry;
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/identity.d.ts
|
|
14
|
+
/**
|
|
15
|
+
* Durable replica file for one `(Database name, asserted userId)` pair:
|
|
16
|
+
* `doync__<name>__anon.db` when `userId` is `null`, else
|
|
17
|
+
* `doync__<name>__<userId>.db`. Separators are `__` so hyphens (common in UUIDs
|
|
18
|
+
* and ids) stay unescaped and filenames stay short enough for OPFS. Each half
|
|
19
|
+
* is percent-encoded; `_` is additionally escaped so halves cannot forge a
|
|
20
|
+
* separator.
|
|
21
|
+
*/
|
|
22
|
+
declare function dbFileForUserId(name: string, userId: string | null): string;
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/migrate.d.ts
|
|
25
|
+
/**
|
|
26
|
+
* Parser-backed SQL classification for client DDL-only bundled-track replay
|
|
27
|
+
* (ADR-0020 / ADR-0006). Same AST as the server conversation, narrower API: 1.
|
|
28
|
+
* split migrations keeping trigger BEGIN…END whole; 2. ddl vs trigger (skip —
|
|
29
|
+
* apply state, never enforce; ADR-0009/0020) vs backfill DML (skip — data via
|
|
30
|
+
* feed; ADR-0006). Fails closed on unparseable input.
|
|
31
|
+
*/
|
|
32
|
+
/** How the client treats one already-split migration statement. */
|
|
33
|
+
type ClientStatementKind = "ddl" | "trigger" | "dml" | "pragma" | "other";
|
|
34
|
+
/**
|
|
35
|
+
* Split a migration's SQL into its top-level statements. The parser understands
|
|
36
|
+
* statement structure, so a `CREATE TRIGGER … BEGIN … END` body's internal
|
|
37
|
+
* semicolons stay inside one statement — a migration may mix a trigger with
|
|
38
|
+
* surrounding DDL without mis-splitting. Each statement is returned as its
|
|
39
|
+
* canonical unparse (semantically identical to the source); statements that are
|
|
40
|
+
* empty (whitespace/comments only) yield nothing.
|
|
41
|
+
*
|
|
42
|
+
* Fails closed: an unparseable script throws a clear error rather than applying
|
|
43
|
+
* a partial or mis-read migration. Trusted input only in the sense that the
|
|
44
|
+
* consumer authored the migrations — the parse itself validates their syntax.
|
|
45
|
+
*/
|
|
46
|
+
declare function splitClientStatements(sql: string): string[];
|
|
47
|
+
/**
|
|
48
|
+
* Classify ONE already-split statement by its parsed kind. `CREATE TRIGGER` and
|
|
49
|
+
* `DROP TRIGGER` are `'trigger'` (the client neither creates nor drops triggers
|
|
50
|
+
* — it runs none, ADR-0009); every other shape-changing DDL is `'ddl'`
|
|
51
|
+
* (replayed); the row read/write verbs are `'dml'` (backfill, never replayed on
|
|
52
|
+
* the client); `PRAGMA` and anything unrecognized/unparseable land in their own
|
|
53
|
+
* buckets.
|
|
54
|
+
*/
|
|
55
|
+
declare function classifyClientStatement(statement: string): ClientStatementKind;
|
|
56
|
+
/**
|
|
57
|
+
* The non-trigger DDL statements of the bundled migrations in the half-open
|
|
58
|
+
* range `(fromVersion, toVersion]` (0-based migration indices `fromVersion …
|
|
59
|
+
* toVersion − 1`), in order — the replayable shape for the client's DDL-only
|
|
60
|
+
* bundled-track replay (ADR-0020). Trigger DDL is skipped (ADR-0009) and
|
|
61
|
+
* backfill DML never runs on the client (ADR-0006). Passing `fromVersion = 0`
|
|
62
|
+
* yields the full track up to `toVersion` (a fresh replica); a higher
|
|
63
|
+
* `fromVersion` yields just the newly-appended migrations (a mid-session
|
|
64
|
+
* catch-up).
|
|
65
|
+
*/
|
|
66
|
+
declare function bundledSchemaDdl(schema: DoyncSchema, fromVersion: number, toVersion: number): string[];
|
|
67
|
+
//#endregion
|
|
68
|
+
export { ClientEngine, type ClientEngineConfig, type ClientStatementKind, __CONNECTED_CLOCK_META_KEY, __LOGOUT_BEHAVIOR_META_KEY, applyBundledMigrations, asClientMutation, bundledSchemaDdl, classifyClientStatement, createClientEngine, createEngineTables, dbFileForUserId, dropConsumerTables, extractWriteTable, isFalsyQuery, normalizeQuerySurface, readMeta, replayMigrations, settledRejection, splitClientStatements, toClientMutationRegistry, validateMutationArgs, writeMeta };
|
|
69
|
+
//# sourceMappingURL=internal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.d.ts","names":[],"sources":["../src/client-mutation-registry.ts","../src/identity.ts","../src/migrate.ts"],"mappings":";;;;;;;;AAqBG;;iBAFa,wBAAA,CACd,IAAA,EAAM,YAAA,GACL,sBAAA;;;;;;;AAFH;;;;iBCgBgB,eAAA,CAAgB,IAAA,UAAc,MAAA;;;;;;ADhB9C;;;;;KEAY,mBAAA;;;AFET;;;;ACcH;;;;AAA8C;;iBCgE9B,qBAAA,CAAsB,GAAA;;AAhFtC;;;;AAAY;AAgFZ;;iBAkBgB,uBAAA,CACd,SAAA,WACC,mBAAA;;AApBmC;AAkBtC;;;;AAEG;AAeH;;;iBAAgB,gBAAA,CACd,MAAA,EAAQ,WAAA,EACR,WAAA,UACA,SAAA"}
|
package/dist/internal.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{_ as e,a as t,b as n,c as r,d as i,f as a,g as o,h as s,i as c,l,m as u,n as d,o as f,p,r as m,s as h,u as g,v as _,y as v}from"./client-ClV8ce6X.js";import{parse as y}from"@doync/sqlite-parser";function b(e){return encodeURIComponent(e).replaceAll(`_`,`%5F`)}function x(e,t){let n=b(e);return t===null?`doync__${n}__anon.db`:`doync__${n}__${b(t)}.db`}function S(e){let t;try{t=y(e)}catch(t){return console.warn(`extractWriteTable: failed to parse SQL statement`,{sql:e,err:t}),null}switch(t.kind){case`STMT_INSERT`:case`STMT_UPDATE`:case`STMT_DELETE`:return t.table??null;default:return null}}export{m as ClientEngine,c as __CONNECTED_CLOCK_META_KEY,t as __LOGOUT_BEHAVIOR_META_KEY,l as applyBundledMigrations,_ as asClientMutation,s as bundledSchemaDdl,o as classifyClientStatement,d as createClientEngine,g as createEngineTables,x as dbFileForUserId,i as dropConsumerTables,S as extractWriteTable,f as isFalsyQuery,h as normalizeQuerySurface,p as readMeta,a as replayMigrations,r as settledRejection,e as splitClientStatements,n as toClientMutationRegistry,v as validateMutationArgs,u as writeMeta};
|
|
2
|
+
//# sourceMappingURL=internal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.js","names":[],"sources":["../src/identity.ts","../src/port.ts"],"sourcesContent":["/**\n * Per-(Database name, identity) replica filename (CONTEXT.md Database name;\n * ADR-0019 addendum / closeio/doync#187 / #321) — a PURE helper shared by every\n * platform that owns a durable replica file (web OPFS, mobile op-sqlite, …).\n *\n * The file key is `(name, userId)`: two Database names in one app never collide\n * on the same store, and each identity (`doync__<name>__<userId|anon>.db`) owns\n * its own replica, clientId, cookie, and pending queue so a shared device never\n * leaks one user's rows into another's session. The id is percent-encoded so an\n * exotic identity can never escape the filename (a `/` would otherwise mean a\n * subpath); a numeric/alphanumeric id (the common case, e.g. a GitHub id)\n * encodes to itself, keeping the file readable. Pre-release: no migration of\n * pre-#187 / pre-#321 filenames — wipe/redeploy owns the cutover.\n */\n\n/**\n * Encode one half of the replica filename so it cannot contain the format's\n * `__` separator and cannot form a path segment (`/`, etc.).\n *\n * `encodeURIComponent` leaves `_` intact; escaping `_` → `%5F` keeps `(name:\n * 'a__b', user: 'c')` from colliding with `(name: 'a', user: 'b__c')`.\n * UUID-shaped names (hyphens only) encode to themselves.\n */\nfunction encodeHalf(value: string): string {\n return encodeURIComponent(value).replaceAll('_', '%5F')\n}\n\n/**\n * Durable replica file for one `(Database name, asserted userId)` pair:\n * `doync__<name>__anon.db` when `userId` is `null`, else\n * `doync__<name>__<userId>.db`. Separators are `__` so hyphens (common in UUIDs\n * and ids) stay unescaped and filenames stay short enough for OPFS. Each half\n * is percent-encoded; `_` is additionally escaped so halves cannot forge a\n * separator.\n */\nexport function dbFileForUserId(name: string, userId: string | null): string {\n const encodedName = encodeHalf(name)\n return userId === null\n ? `doync__${encodedName}__anon.db`\n : `doync__${encodedName}__${encodeHalf(userId)}.db`\n}\n","import type { SqlValue } from '@doync/core'\nimport type { Statement } from '@doync/sqlite-parser'\n\nimport { parse } from '@doync/sqlite-parser'\n\n/** One local-replica row: column name → {@link SqlValue}. */\nexport interface LocalRow {\n [column: string]: SqlValue\n}\n\n// ADR-0019 (synchronous local-DB port; platform adapters supply the impl).\n/**\n * Synchronous local SQLite port the client engine drives. Platform adapters\n * (wa-sqlite, node:sqlite, op-sqlite) implement this; app code does not.\n * Transactions and savepoints are ordinary SQL via {@link LocalDb.exec}.\n */\nexport interface LocalDb {\n /**\n * Run one parameterized statement; return its rows (empty for writes/DDL/\n * transaction control).\n */\n exec<T extends LocalRow = LocalRow>(sql: string, ...params: SqlValue[]): T[]\n\n /**\n * Run a multi-statement DDL script (no parameters). Used to replay bundled\n * migrations when creating a fresh replica. Trusted input only.\n */\n execBatch(script: string): void\n\n /**\n * Consumer tables written since the last call, then clear the set. Used so\n * only affected subscriptions re-project after a mutation or rebase.\n */\n drainWrittenTables(): Set<string>\n}\n\n/**\n * Extract the target table of one WRITE statement from its SQL text — the\n * adapter-side stand-in where no synchronous native change feed exists\n * (ADR-0019): node:sqlite has no update hook, and op-sqlite's hook delivers\n * callbacks via `invokeAsync` — a later event-loop turn, unusable for the\n * engine's drain-after-apply contract (closeio/doync#202 device pass).\n *\n * A real parse over `@doync/sqlite-parser`, not a keyword recognizer: the AST\n * attaches a `WITH …` CTE prefix to the DML node itself, so CTE-topped writes\n * (`WITH src AS (…) INSERT INTO t …`) extract their target with no string\n * games. Returns the unquoted table name for INSERT / REPLACE / UPDATE /\n * DELETE, or `null` for a non-write (SELECT, SAVEPOINT, PRAGMA, DDL) or\n * unparseable input.\n *\n * TRIGGER cascades remain invisible to statement text — and stay out of scope\n * by design: client replicas carry no triggers (the bundled-track replay strips\n * CREATE TRIGGER; ADR-0009 — clients apply state, never enforce).\n */\nexport function extractWriteTable(sql: string): string | null {\n let statement: Statement\n try {\n statement = parse(sql)\n } catch (err) {\n console.warn('extractWriteTable: failed to parse SQL statement', {\n sql,\n err,\n })\n return null\n }\n switch (statement.kind) {\n case 'STMT_INSERT':\n case 'STMT_UPDATE':\n case 'STMT_DELETE':\n return statement.table ?? null\n default:\n return null\n }\n}\n"],"mappings":"0MAuBA,SAAS,EAAW,EAAuB,CACzC,OAAO,mBAAmB,CAAK,CAAC,CAAC,WAAW,IAAK,KAAK,CACxD,CAUA,SAAgB,EAAgB,EAAc,EAA+B,CAC3E,IAAM,EAAc,EAAW,CAAI,EACnC,OAAO,IAAW,KACd,UAAU,EAAY,WACtB,UAAU,EAAY,IAAI,EAAW,CAAM,EAAE,IACnD,CCcA,SAAgB,EAAkB,EAA4B,CAC5D,IAAI,EACJ,GAAI,CACF,EAAY,EAAM,CAAG,CACvB,OAAS,EAAK,CAKZ,OAJA,QAAQ,KAAK,mDAAoD,CAC/D,MACA,KACF,CAAC,EACM,IACT,CACA,OAAQ,EAAU,KAAlB,CACE,IAAK,cACL,IAAK,cACL,IAAK,cACH,OAAO,EAAU,OAAS,KAC5B,QACE,OAAO,IACX,CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@doync/client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "doync client engine: optimistic Layer-1 savepoint/rebase over a synchronous local-DB port",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"client",
|
|
7
|
+
"doync",
|
|
8
|
+
"local-first",
|
|
9
|
+
"sqlite",
|
|
10
|
+
"sync-engine"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"author": "Vitor Buzinaro",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/closeio/doync.git",
|
|
17
|
+
"directory": "packages/client"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"src"
|
|
22
|
+
],
|
|
23
|
+
"type": "module",
|
|
24
|
+
"main": "./dist/index.cjs",
|
|
25
|
+
"module": "./dist/index.js",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"import": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"default": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"require": {
|
|
34
|
+
"types": "./dist/index.d.cts",
|
|
35
|
+
"default": "./dist/index.cjs"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"./adapter": {
|
|
39
|
+
"import": {
|
|
40
|
+
"types": "./dist/adapter.d.ts",
|
|
41
|
+
"default": "./dist/adapter.js"
|
|
42
|
+
},
|
|
43
|
+
"require": {
|
|
44
|
+
"types": "./dist/adapter.d.cts",
|
|
45
|
+
"default": "./dist/adapter.cjs"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"./internal": {
|
|
49
|
+
"import": {
|
|
50
|
+
"types": "./dist/internal.d.ts",
|
|
51
|
+
"default": "./dist/internal.js"
|
|
52
|
+
},
|
|
53
|
+
"require": {
|
|
54
|
+
"types": "./dist/internal.d.cts",
|
|
55
|
+
"default": "./dist/internal.cjs"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@doync/core": "0.1.0",
|
|
61
|
+
"@doync/sqlite-parser": "0.3053001.0"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@standard-schema/spec": "^1.1.0",
|
|
65
|
+
"@types/node": "^24.13.2",
|
|
66
|
+
"drizzle-kit": "^0.31.10",
|
|
67
|
+
"drizzle-orm": "^0.45.2",
|
|
68
|
+
"tsdown": "^0.22.3",
|
|
69
|
+
"typescript": "^7.0.2",
|
|
70
|
+
"unplugin-raw": "^0.7.0",
|
|
71
|
+
"vitest": "4.1.9",
|
|
72
|
+
"@doync/drizzle": "0.1.0"
|
|
73
|
+
},
|
|
74
|
+
"scripts": {
|
|
75
|
+
"build": "rm -rf dist && tsdown",
|
|
76
|
+
"test": "vitest run",
|
|
77
|
+
"typecheck": "tsc --noEmit"
|
|
78
|
+
}
|
|
79
|
+
}
|
package/src/adapter.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@doync/client/adapter` (ADR-0033): the adapter-author surface — host-seam
|
|
3
|
+
* ports (`LocalDb`, `SyncSocket`), the reconnect coordinator, and
|
|
4
|
+
* `createClient` / `CreateClientOptions`. Same lockstep semver as the main
|
|
5
|
+
* entry; the distinction is audience (third-party adapter authors), not
|
|
6
|
+
* stability. App-facing call-surface types (`DoyncClient`, views, mutation
|
|
7
|
+
* types, `LogoutBehavior`) live on `@doync/client`. Engine construction
|
|
8
|
+
* plumbing (`createClientEngine`, replica DDL, mutation dispatch helpers) lives
|
|
9
|
+
* under `/internal`.
|
|
10
|
+
*
|
|
11
|
+
* Our own platform packages (`@doync/web`, `@doync/mobile`) use
|
|
12
|
+
* `createClientEngine` from `/internal` rather than `createClient` — the latter
|
|
13
|
+
* is the only real call site audience for a third-party adapter.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export { createClient, type CreateClientOptions } from './client'
|
|
17
|
+
export type { LocalDb, LocalRow } from './port'
|
|
18
|
+
export type { SeamStatus, SyncSocket, SyncSocketHandlers } from './socket'
|
|
19
|
+
export {
|
|
20
|
+
createReconnectingSocket,
|
|
21
|
+
type ReconnectSocket,
|
|
22
|
+
type ReconnectingSocket,
|
|
23
|
+
type ReconnectingSocketConfig,
|
|
24
|
+
type SocketCloseInfo,
|
|
25
|
+
} from './socket-reconnect'
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flatten a shared MutationTree to the engine's name-keyed client mutation
|
|
3
|
+
* registry (ADR-0019/0021, #167). Internal helper for {@link createClient} and
|
|
4
|
+
* `@doync/web` `createWorker` — consumers pass a MutationTree; the lib
|
|
5
|
+
* flattens.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { MutationTree } from '@doync/core'
|
|
9
|
+
|
|
10
|
+
import { flattenMutations } from '@doync/core/internal'
|
|
11
|
+
|
|
12
|
+
import type { ClientMutation, ClientMutationRegistry } from './mutations'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Flat `dottedName → {args, handler}` registry the client engine resolves
|
|
16
|
+
* optimistic bodies against (ADR-0019). Feed the SHARED tree so no `.server.ts`
|
|
17
|
+
* override enters the client bundle. Handler may return a promise (exclusive
|
|
18
|
+
* chain awaits); engine validates args at `mutate()` via carried schema.
|
|
19
|
+
*/
|
|
20
|
+
export function toClientMutationRegistry(
|
|
21
|
+
tree: MutationTree,
|
|
22
|
+
): ClientMutationRegistry {
|
|
23
|
+
const out: Record<string, ClientMutation> = {}
|
|
24
|
+
for (const [name, def] of Object.entries(flattenMutations(tree))) {
|
|
25
|
+
out[name] = {
|
|
26
|
+
args: def.args,
|
|
27
|
+
handler: (args, ctx, sql) => def.body(args, ctx, sql),
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return out
|
|
31
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { DoyncSchema, MutationTree } from '@doync/core'
|
|
2
|
+
|
|
3
|
+
import type { DoyncClient, LogoutBehavior, SchemaEvent } from './engine'
|
|
4
|
+
import type { LocalDb } from './port'
|
|
5
|
+
import type { SyncSocket } from './socket'
|
|
6
|
+
|
|
7
|
+
import { toClientMutationRegistry } from './client-mutation-registry'
|
|
8
|
+
import { ClientEngine, __LOGOUT_BEHAVIOR_META_KEY } from './engine'
|
|
9
|
+
import { createEngineTables, writeMeta } from './replica'
|
|
10
|
+
|
|
11
|
+
// The durable logout-policy seam (ADR-0022) is owned by the engine (the layer
|
|
12
|
+
// that owns `__doync_meta` and the runtime {@link ClientEngine.setLogoutBehavior}).
|
|
13
|
+
// Only LogoutBehavior is public; the meta key stays on `./internal`.
|
|
14
|
+
export type { LogoutBehavior } from './engine'
|
|
15
|
+
|
|
16
|
+
// Identity is the asserted triple `{ token, ctx, userId }` — never derived
|
|
17
|
+
// from a bearer token (ADR-0018 asserted-identity).
|
|
18
|
+
/**
|
|
19
|
+
* Options for {@link createClient}. Platform adapters (`@doync/web`,
|
|
20
|
+
* `@doync/mobile`) fill these; app code rarely calls `createClient` directly.
|
|
21
|
+
*/
|
|
22
|
+
export interface CreateClientOptions<TAuthData = unknown> {
|
|
23
|
+
/** Synchronous local SQLite port (wa-sqlite / node:sqlite / op-sqlite). */
|
|
24
|
+
readonly db: LocalDb
|
|
25
|
+
/** Synced schema shared with Origin and Mirror. */
|
|
26
|
+
readonly schema: DoyncSchema
|
|
27
|
+
/**
|
|
28
|
+
* Shared mutation tree from `defineMutations(shared)` — no server overrides
|
|
29
|
+
* in the client bundle.
|
|
30
|
+
*/
|
|
31
|
+
readonly mutations: MutationTree
|
|
32
|
+
/** Transport to the Mirror. */
|
|
33
|
+
readonly socket: SyncSocket
|
|
34
|
+
/**
|
|
35
|
+
* Bearer credential for the handshake. Does not drive `userId` or `ctx`. Omit
|
|
36
|
+
* for cookie-session auth.
|
|
37
|
+
*/
|
|
38
|
+
readonly token?: string
|
|
39
|
+
/**
|
|
40
|
+
* Projected auth context for optimistic query/mutation resolution (mirror
|
|
41
|
+
* your server `toContext`). Defaults to `{}`.
|
|
42
|
+
*/
|
|
43
|
+
readonly ctx?: TAuthData
|
|
44
|
+
/**
|
|
45
|
+
* Authenticated identity, or `null`/omit for anonymous. Never derived from
|
|
46
|
+
* `token`.
|
|
47
|
+
*/
|
|
48
|
+
readonly userId?: string | null
|
|
49
|
+
/** Pin a durable client id across restarts. */
|
|
50
|
+
readonly clientId?: string
|
|
51
|
+
/** Observe schema/recovery transitions. */
|
|
52
|
+
readonly onSchemaEvent?: (event: SchemaEvent) => void
|
|
53
|
+
/**
|
|
54
|
+
* Initial {@link LogoutBehavior}, written durably when provided. Omit to keep
|
|
55
|
+
* a previously stored choice (a restart will not revert `forget` to `keep`).
|
|
56
|
+
* Change later via {@link DoyncClient.setLogoutBehavior}.
|
|
57
|
+
*/
|
|
58
|
+
readonly logoutBehavior?: LogoutBehavior
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Construct a {@link DoyncClient} from local DB, schema, shared mutations, and a
|
|
63
|
+
* Mirror socket. App code normally goes through `@doync/web` / `@doync/mobile`
|
|
64
|
+
* instead.
|
|
65
|
+
*/
|
|
66
|
+
export function createClient<TAuthData = unknown>(
|
|
67
|
+
options: CreateClientOptions<TAuthData>,
|
|
68
|
+
): DoyncClient {
|
|
69
|
+
return createClientEngine(options)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Concrete-engine factory (ADR-0033 / closeio/doync#241). Same construction as
|
|
74
|
+
* {@link createClient}, but typed as {@link ClientEngine} so platform adapters
|
|
75
|
+
* (web DB-worker, mobile wrapper) can reach engine-only fields like `clientId`
|
|
76
|
+
* without an unchecked downcast. Exported on `@doync/client/internal` only.
|
|
77
|
+
*/
|
|
78
|
+
export function createClientEngine<TAuthData = unknown>(
|
|
79
|
+
options: CreateClientOptions<TAuthData>,
|
|
80
|
+
): ClientEngine {
|
|
81
|
+
// Logout policy must land before boot (ADR-0022 / #135): construction opens
|
|
82
|
+
// the optimistic overlay (ADR-0019), so a later write on this connection would
|
|
83
|
+
// join the savepoint and roll back. Pre-boot is autocommit.
|
|
84
|
+
if (options.logoutBehavior !== undefined) {
|
|
85
|
+
createEngineTables(options.db)
|
|
86
|
+
writeMeta(options.db, __LOGOUT_BEHAVIOR_META_KEY, options.logoutBehavior)
|
|
87
|
+
}
|
|
88
|
+
return new ClientEngine({
|
|
89
|
+
db: options.db,
|
|
90
|
+
schema: options.schema,
|
|
91
|
+
mutations: toClientMutationRegistry(options.mutations),
|
|
92
|
+
socket: options.socket,
|
|
93
|
+
// Asserted identity (ADR-0018 / #167): never derived.
|
|
94
|
+
ctx: (options.ctx as Record<string, unknown> | undefined) ?? {},
|
|
95
|
+
token: options.token,
|
|
96
|
+
userId: options.userId ?? null,
|
|
97
|
+
clientId: options.clientId,
|
|
98
|
+
onSchemaEvent: options.onSchemaEvent,
|
|
99
|
+
})
|
|
100
|
+
}
|