@doync/client 0.3.3 → 0.4.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/README.md +3 -2
- package/dist/adapter.cjs +1 -1
- package/dist/adapter.d.cts +1 -1
- package/dist/adapter.d.ts +1 -1
- package/dist/adapter.js +1 -1
- package/dist/{client-CR5SoP5D.cjs → client-AGRXHAJy.cjs} +6 -6
- package/dist/{client-OAVaC3pt.d.ts → client-BZWglwNl.d.cts} +42 -7
- package/dist/{client-OPt8Axyp.d.cts.map → client-BZWglwNl.d.cts.map} +1 -1
- package/dist/client-Dphx71Qk.js +16 -0
- package/dist/client-Dphx71Qk.js.map +1 -0
- package/dist/{client-OPt8Axyp.d.cts → client-tAY8RnNM.d.ts} +42 -7
- package/dist/{client-OAVaC3pt.d.ts.map → client-tAY8RnNM.d.ts.map} +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/internal.cjs +1 -1
- package/dist/internal.d.cts +2 -2
- package/dist/internal.d.ts +2 -2
- package/dist/internal.js +1 -1
- package/dist/internal.js.map +1 -1
- package/package.json +3 -3
- package/src/engine.ts +91 -6
- package/src/index.ts +2 -0
- package/src/internal.ts +4 -0
- package/dist/client-C97IzM56.js +0 -16
- package/dist/client-C97IzM56.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AuthContext, AuthData, BoundQuery, DoyncSchema, MutationDefinition, MutationTree, SqlValue } from "@doync/core";
|
|
2
1
|
import { ClientMessage, ServerMessage } from "@doync/core/internal";
|
|
2
|
+
import { AuthContext, AuthData, BoundQuery, DoyncSchema, MutationDefinition, MutationTree, SqlValue } from "@doync/core";
|
|
3
3
|
|
|
4
4
|
//#region ../../node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.d.ts
|
|
5
5
|
/** The Standard Typed interface. This is a base type extended by other specs. */
|
|
@@ -419,6 +419,13 @@ interface DoyncClient {
|
|
|
419
419
|
*/
|
|
420
420
|
local<Row extends Record<string, unknown> = Record<string, SqlValue>>(sql: string, ...params: SqlValue[]): View<Row>;
|
|
421
421
|
/**
|
|
422
|
+
* Start a subscription and hold its view before a component needs it. The
|
|
423
|
+
* hold is released automatically after a short grace window, when its signal
|
|
424
|
+
* aborts, or when the returned handle is released. An already-aborted signal
|
|
425
|
+
* returns an inert handle without starting the query.
|
|
426
|
+
*/
|
|
427
|
+
warmup<Row extends Record<string, unknown> = Record<string, SqlValue>>(query: BoundQuery<Row, boolean> | FalsyQuery, options?: WarmupOptions): WarmupHandle;
|
|
428
|
+
/**
|
|
422
429
|
* Apply a registered mutation optimistically and push it to the Origin. Pass
|
|
423
430
|
* the {@link MutationDefinition} from your mutations tree; args are
|
|
424
431
|
* type-checked from the definition. Returns {@link MutationResult}.
|
|
@@ -459,15 +466,16 @@ interface DoyncClient {
|
|
|
459
466
|
* for other queries that read the same tables. Falsy yields a no-op handle.
|
|
460
467
|
* Call `cleanup()` to release (often never, for a session-long preload).
|
|
461
468
|
*/
|
|
462
|
-
preload(query: BoundQuery | FalsyQuery, options?: PreloadOptions): PreloadHandle;
|
|
469
|
+
preload<Row extends Record<string, unknown> = Record<string, SqlValue>>(query: BoundQuery<Row, boolean> | FalsyQuery, options?: PreloadOptions): PreloadHandle;
|
|
463
470
|
/** Current {@link ConnectionStatus} to the Mirror. */
|
|
464
471
|
readonly connectionStatus: ConnectionStatus;
|
|
465
472
|
/** Subscribe to connection-status transitions. Returns the unsubscribe. */
|
|
466
473
|
onConnectionChange(listener: () => void): () => void;
|
|
467
474
|
}
|
|
468
475
|
/**
|
|
469
|
-
* Falsy "no query" on subscribe / once / preload: `false | null |
|
|
470
|
-
* Lets `cond && query(args)` and optional-prop patterns
|
|
476
|
+
* Falsy "no query" on subscribe / once / preload / warmup: `false | null |
|
|
477
|
+
* undefined`. Lets `cond && query(args)` and optional-prop patterns
|
|
478
|
+
* type-check.
|
|
471
479
|
*/
|
|
472
480
|
type FalsyQuery = false | null | undefined;
|
|
473
481
|
/** Per-subscribe options. */
|
|
@@ -491,6 +499,18 @@ interface PreloadOptions {
|
|
|
491
499
|
*/
|
|
492
500
|
readonly ttl?: number;
|
|
493
501
|
}
|
|
502
|
+
/** Options accepted by `warmup()`. */
|
|
503
|
+
interface WarmupOptions {
|
|
504
|
+
/** Connected-time grace after the query is released. */
|
|
505
|
+
readonly ttl?: number;
|
|
506
|
+
/** Release the warmup hold when the signal aborts. */
|
|
507
|
+
readonly signal?: AbortSignal;
|
|
508
|
+
}
|
|
509
|
+
/** Handle returned by `warmup()`. */
|
|
510
|
+
interface WarmupHandle {
|
|
511
|
+
/** Release the warmup hold. Idempotent. */
|
|
512
|
+
release(): void;
|
|
513
|
+
}
|
|
494
514
|
/** Handle returned by {@link DoyncClient.preload}. */
|
|
495
515
|
interface PreloadHandle {
|
|
496
516
|
/**
|
|
@@ -633,13 +653,20 @@ declare class ClientEngine implements DoyncClient {
|
|
|
633
653
|
*/
|
|
634
654
|
subscribe<Row extends Record<string, unknown> = Record<string, SqlValue>>(query: BoundQuery<Row, boolean> | FalsyQuery, options?: SubscribeOptions): View<Row>;
|
|
635
655
|
/**
|
|
656
|
+
* Start a subscription and hold its view before a component needs it. The
|
|
657
|
+
* hold is released automatically after a short grace window, when its signal
|
|
658
|
+
* aborts, or when the returned handle is released. An already-aborted signal
|
|
659
|
+
* returns an inert handle without starting the query.
|
|
660
|
+
*/
|
|
661
|
+
warmup<Row extends Record<string, unknown> = Record<string, SqlValue>>(query: BoundQuery<Row, boolean> | FalsyQuery, options?: WarmupOptions): WarmupHandle;
|
|
662
|
+
/**
|
|
636
663
|
* Warm the replica without materializing a View (#104, ADR-0019/0021):
|
|
637
664
|
* register upstream so pokes hydrate rows other queries read, at zero local
|
|
638
665
|
* recompute of the preload statement. Refcounts the same desired instance as
|
|
639
666
|
* a live subscribe (byte-identical statement). `{cleanup}` releases into TTL
|
|
640
667
|
* grace (ADR-0014). Bound form only (ADR-0027 / #200); falsy → no-op handle.
|
|
641
668
|
*/
|
|
642
|
-
preload(query: BoundQuery | FalsyQuery, options?: PreloadOptions): PreloadHandle;
|
|
669
|
+
preload<Row extends Record<string, unknown> = Record<string, SqlValue>>(query: BoundQuery<Row, boolean> | FalsyQuery, options?: PreloadOptions): PreloadHandle;
|
|
643
670
|
/**
|
|
644
671
|
* Once (ADR-0012 / ADR-0021): cache-and-network. Local replica first (real
|
|
645
672
|
* SQL `[]` when empty); Mirror executes once under its ctx. Local
|
|
@@ -718,6 +745,14 @@ declare function normalizeQuerySurface<Options = never>(surface: "subscribe" | "
|
|
|
718
745
|
args: unknown;
|
|
719
746
|
options: Options | undefined;
|
|
720
747
|
};
|
|
748
|
+
/** No-op {@link WarmupHandle} for warmup(falsy) (ADR-0027). */
|
|
749
|
+
declare const NOOP_WARMUP: WarmupHandle;
|
|
750
|
+
/**
|
|
751
|
+
* Retain `view` as a warmup hold: released by the grace lapse, `signal` abort,
|
|
752
|
+
* or the handle — idempotent, first wins. Shared by every client's `warmup` so
|
|
753
|
+
* the three release paths cannot drift per platform.
|
|
754
|
+
*/
|
|
755
|
+
declare function warmupHold(view: View<Record<string, unknown>>, signal?: AbortSignal): WarmupHandle;
|
|
721
756
|
/**
|
|
722
757
|
* A `mutate()` whose failure is known synchronously (unknown name, bad args).
|
|
723
758
|
* Exported for the web topology's tab-side `mutate`, which shares the
|
|
@@ -796,5 +831,5 @@ declare function resolveClientAuthData<TAuthContext extends AuthContext>(authDat
|
|
|
796
831
|
ctx: AuthContext;
|
|
797
832
|
};
|
|
798
833
|
//#endregion
|
|
799
|
-
export {
|
|
800
|
-
//# sourceMappingURL=client-
|
|
834
|
+
export { warmupHold as A, SyncSocket as B, WarmupHandle as C, isFalsyQuery as D, __LOGOUT_BEHAVIOR_PREF_KEY as E, readMeta as F, LocalDb as H, readPref as I, writeMeta as L, createEngineTables as M, dropConsumerTables as N, normalizeQuerySurface as O, replayMigrations as P, writePref as R, ViewStatus as S, __CONNECTED_CLOCK_META_KEY as T, LocalRow as U, SyncSocketHandlers as V, extractWriteTable as W, QueryStatus as _, ClientEngine as a, SubscribeOptions as b, DoyncClient as c, MutationOptions as d, MutationResult as f, PreloadOptions as g, PreloadHandle as h, resolveClientAuthData as i, applyBundledMigrations as j, settledRejection as k, FalsyQuery as l, OnceView as m, createClient as n, ClientEngineConfig as o, NOOP_WARMUP as p, createClientEngine as r, ConnectionStatus as s, CreateClientOptions as t, LogoutBehavior as u, SchemaEvent as v, WarmupOptions as w, View as x, SchemaEventKind as y, SeamStatus as z };
|
|
835
|
+
//# sourceMappingURL=client-tAY8RnNM.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-
|
|
1
|
+
{"version":3,"file":"client-tAY8RnNM.d.ts","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/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.d.cts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { _ as
|
|
1
|
+
import { C as WarmupHandle, S as ViewStatus, _ as QueryStatus, b as SubscribeOptions, c as DoyncClient, d as MutationOptions, f as MutationResult, g as PreloadOptions, h as PreloadHandle, l as FalsyQuery, m as OnceView, s as ConnectionStatus, u as LogoutBehavior, v as SchemaEvent, w as WarmupOptions, x as View, y as SchemaEventKind } from "./client-BZWglwNl.cjs";
|
|
2
2
|
import { AuthData } from "@doync/core";
|
|
3
|
-
export type { AuthData, ConnectionStatus, DoyncClient, FalsyQuery, LogoutBehavior, MutationOptions, MutationResult, OnceView, PreloadHandle, PreloadOptions, QueryStatus, SchemaEvent, SchemaEventKind, SubscribeOptions, View, ViewStatus };
|
|
3
|
+
export type { AuthData, ConnectionStatus, DoyncClient, FalsyQuery, LogoutBehavior, MutationOptions, MutationResult, OnceView, PreloadHandle, PreloadOptions, QueryStatus, SchemaEvent, SchemaEventKind, SubscribeOptions, View, ViewStatus, WarmupHandle, WarmupOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { _ as
|
|
1
|
+
import { C as WarmupHandle, S as ViewStatus, _ as QueryStatus, b as SubscribeOptions, c as DoyncClient, d as MutationOptions, f as MutationResult, g as PreloadOptions, h as PreloadHandle, l as FalsyQuery, m as OnceView, s as ConnectionStatus, u as LogoutBehavior, v as SchemaEvent, w as WarmupOptions, x as View, y as SchemaEventKind } from "./client-tAY8RnNM.js";
|
|
2
2
|
import { AuthData } from "@doync/core";
|
|
3
|
-
export type { AuthData, ConnectionStatus, DoyncClient, FalsyQuery, LogoutBehavior, MutationOptions, MutationResult, OnceView, PreloadHandle, PreloadOptions, QueryStatus, SchemaEvent, SchemaEventKind, SubscribeOptions, View, ViewStatus };
|
|
3
|
+
export type { AuthData, ConnectionStatus, DoyncClient, FalsyQuery, LogoutBehavior, MutationOptions, MutationResult, OnceView, PreloadHandle, PreloadOptions, QueryStatus, SchemaEvent, SchemaEventKind, SubscribeOptions, View, ViewStatus, WarmupHandle, WarmupOptions };
|
package/dist/internal.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./client-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./client-AGRXHAJy.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.i,exports.NOOP_WARMUP=e.a,exports.__CONNECTED_CLOCK_META_KEY=e.o,exports.__LOGOUT_BEHAVIOR_PREF_KEY=e.s,exports.applyBundledMigrations=e.f,exports.bundledSchemaDdl=e.b,exports.classifyClientStatement=e.x,exports.createClientEngine=e.n,exports.createEngineTables=e.p,exports.dbFileForUserId=r,exports.dropConsumerTables=e.m,exports.extractWriteTable=i,exports.isFalsyQuery=e.c,exports.normalizeQuerySurface=e.l,exports.readMeta=e.g,exports.readPref=e._,exports.replayMigrations=e.h,exports.resolveClientAuthData=e.r,exports.settledRejection=e.u,exports.splitClientStatements=e.S,exports.warmupHold=e.d,exports.writeMeta=e.v,exports.writePref=e.y;
|
package/dist/internal.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as warmupHold, C as WarmupHandle, D as isFalsyQuery, E as __LOGOUT_BEHAVIOR_PREF_KEY, F as readMeta, I as readPref, L as writeMeta, M as createEngineTables, N as dropConsumerTables, O as normalizeQuerySurface, P as replayMigrations, R as writePref, T as __CONNECTED_CLOCK_META_KEY, W as extractWriteTable, a as ClientEngine, i as resolveClientAuthData, j as applyBundledMigrations, k as settledRejection, o as ClientEngineConfig, p as NOOP_WARMUP, r as createClientEngine, w as WarmupOptions } from "./client-BZWglwNl.cjs";
|
|
2
2
|
import { DoyncSchema } from "@doync/core";
|
|
3
3
|
|
|
4
4
|
//#region src/identity.d.ts
|
|
@@ -56,5 +56,5 @@ declare function classifyClientStatement(statement: string): ClientStatementKind
|
|
|
56
56
|
*/
|
|
57
57
|
declare function bundledSchemaDdl(schema: DoyncSchema, fromVersion: number, toVersion: number): string[];
|
|
58
58
|
//#endregion
|
|
59
|
-
export { ClientEngine, type ClientEngineConfig, type ClientStatementKind, __CONNECTED_CLOCK_META_KEY, __LOGOUT_BEHAVIOR_PREF_KEY, applyBundledMigrations, bundledSchemaDdl, classifyClientStatement, createClientEngine, createEngineTables, dbFileForUserId, dropConsumerTables, extractWriteTable, isFalsyQuery, normalizeQuerySurface, readMeta, readPref, replayMigrations, resolveClientAuthData, settledRejection, splitClientStatements, writeMeta, writePref };
|
|
59
|
+
export { ClientEngine, type ClientEngineConfig, type ClientStatementKind, NOOP_WARMUP, type WarmupHandle, type WarmupOptions, __CONNECTED_CLOCK_META_KEY, __LOGOUT_BEHAVIOR_PREF_KEY, applyBundledMigrations, bundledSchemaDdl, classifyClientStatement, createClientEngine, createEngineTables, dbFileForUserId, dropConsumerTables, extractWriteTable, isFalsyQuery, normalizeQuerySurface, readMeta, readPref, replayMigrations, resolveClientAuthData, settledRejection, splitClientStatements, warmupHold, writeMeta, writePref };
|
|
60
60
|
//# sourceMappingURL=internal.d.cts.map
|
package/dist/internal.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as warmupHold, C as WarmupHandle, D as isFalsyQuery, E as __LOGOUT_BEHAVIOR_PREF_KEY, F as readMeta, I as readPref, L as writeMeta, M as createEngineTables, N as dropConsumerTables, O as normalizeQuerySurface, P as replayMigrations, R as writePref, T as __CONNECTED_CLOCK_META_KEY, W as extractWriteTable, a as ClientEngine, i as resolveClientAuthData, j as applyBundledMigrations, k as settledRejection, o as ClientEngineConfig, p as NOOP_WARMUP, r as createClientEngine, w as WarmupOptions } from "./client-tAY8RnNM.js";
|
|
2
2
|
import { DoyncSchema } from "@doync/core";
|
|
3
3
|
|
|
4
4
|
//#region src/identity.d.ts
|
|
@@ -56,5 +56,5 @@ declare function classifyClientStatement(statement: string): ClientStatementKind
|
|
|
56
56
|
*/
|
|
57
57
|
declare function bundledSchemaDdl(schema: DoyncSchema, fromVersion: number, toVersion: number): string[];
|
|
58
58
|
//#endregion
|
|
59
|
-
export { ClientEngine, type ClientEngineConfig, type ClientStatementKind, __CONNECTED_CLOCK_META_KEY, __LOGOUT_BEHAVIOR_PREF_KEY, applyBundledMigrations, bundledSchemaDdl, classifyClientStatement, createClientEngine, createEngineTables, dbFileForUserId, dropConsumerTables, extractWriteTable, isFalsyQuery, normalizeQuerySurface, readMeta, readPref, replayMigrations, resolveClientAuthData, settledRejection, splitClientStatements, writeMeta, writePref };
|
|
59
|
+
export { ClientEngine, type ClientEngineConfig, type ClientStatementKind, NOOP_WARMUP, type WarmupHandle, type WarmupOptions, __CONNECTED_CLOCK_META_KEY, __LOGOUT_BEHAVIOR_PREF_KEY, applyBundledMigrations, bundledSchemaDdl, classifyClientStatement, createClientEngine, createEngineTables, dbFileForUserId, dropConsumerTables, extractWriteTable, isFalsyQuery, normalizeQuerySurface, readMeta, readPref, replayMigrations, resolveClientAuthData, settledRejection, splitClientStatements, warmupHold, writeMeta, writePref };
|
|
60
60
|
//# sourceMappingURL=internal.d.ts.map
|
package/dist/internal.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{S as e,_ as t,a as n,b as r,c as i,d as a,f as o,g as s,h as c,i as l,l as u,m as d,n as f,o as p,p as m,r as h,s as g,u as _,v,x as y,y as b}from"./client-Dphx71Qk.js";import{parse as x}from"@doync/sqlite-parser";function S(e){return encodeURIComponent(e).replaceAll(`_`,`%5F`)}function C(e,t){let n=S(e);return t===null?`doync__${n}__anon.db`:`doync__${n}__${S(t)}.db`}function w(e){let t;try{t=x(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{l as ClientEngine,n as NOOP_WARMUP,p as __CONNECTED_CLOCK_META_KEY,g as __LOGOUT_BEHAVIOR_PREF_KEY,o as applyBundledMigrations,r as bundledSchemaDdl,y as classifyClientStatement,f as createClientEngine,m as createEngineTables,C as dbFileForUserId,d as dropConsumerTables,w as extractWriteTable,i as isFalsyQuery,u as normalizeQuerySurface,s as readMeta,t as readPref,c as replayMigrations,h as resolveClientAuthData,_ as settledRejection,e as splitClientStatements,a as warmupHold,v as writeMeta,b as writePref};
|
|
2
2
|
//# sourceMappingURL=internal.js.map
|
package/dist/internal.js.map
CHANGED
|
@@ -1 +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":"
|
|
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":"6NAuBA,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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@doync/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "doync client engine: optimistic Layer-1 savepoint/rebase over a synchronous local-DB port",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"client",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
}
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@doync/core": "0.
|
|
60
|
+
"@doync/core": "0.4.0",
|
|
61
61
|
"@doync/sqlite-parser": "0.3053003.0"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"typescript": "^7.0.2",
|
|
70
70
|
"unplugin-raw": "^0.7.0",
|
|
71
71
|
"vitest": "4.1.9",
|
|
72
|
-
"@doync/drizzle": "0.
|
|
72
|
+
"@doync/drizzle": "0.4.0"
|
|
73
73
|
},
|
|
74
74
|
"scripts": {
|
|
75
75
|
"build": "rm -rf dist && tsdown",
|
package/src/engine.ts
CHANGED
|
@@ -266,6 +266,16 @@ export interface DoyncClient {
|
|
|
266
266
|
sql: string,
|
|
267
267
|
...params: SqlValue[]
|
|
268
268
|
): View<Row>
|
|
269
|
+
/**
|
|
270
|
+
* Start a subscription and hold its view before a component needs it. The
|
|
271
|
+
* hold is released automatically after a short grace window, when its signal
|
|
272
|
+
* aborts, or when the returned handle is released. An already-aborted signal
|
|
273
|
+
* returns an inert handle without starting the query.
|
|
274
|
+
*/
|
|
275
|
+
warmup<Row extends Record<string, unknown> = Record<string, SqlValue>>(
|
|
276
|
+
query: BoundQuery<Row, boolean> | FalsyQuery,
|
|
277
|
+
options?: WarmupOptions,
|
|
278
|
+
): WarmupHandle
|
|
269
279
|
/**
|
|
270
280
|
* Apply a registered mutation optimistically and push it to the Origin. Pass
|
|
271
281
|
* the {@link MutationDefinition} from your mutations tree; args are
|
|
@@ -311,8 +321,8 @@ export interface DoyncClient {
|
|
|
311
321
|
* for other queries that read the same tables. Falsy yields a no-op handle.
|
|
312
322
|
* Call `cleanup()` to release (often never, for a session-long preload).
|
|
313
323
|
*/
|
|
314
|
-
preload(
|
|
315
|
-
query: BoundQuery | FalsyQuery,
|
|
324
|
+
preload<Row extends Record<string, unknown> = Record<string, SqlValue>>(
|
|
325
|
+
query: BoundQuery<Row, boolean> | FalsyQuery,
|
|
316
326
|
options?: PreloadOptions,
|
|
317
327
|
): PreloadHandle
|
|
318
328
|
/** Current {@link ConnectionStatus} to the Mirror. */
|
|
@@ -322,8 +332,9 @@ export interface DoyncClient {
|
|
|
322
332
|
}
|
|
323
333
|
|
|
324
334
|
/**
|
|
325
|
-
* Falsy "no query" on subscribe / once / preload: `false | null |
|
|
326
|
-
* Lets `cond && query(args)` and optional-prop patterns
|
|
335
|
+
* Falsy "no query" on subscribe / once / preload / warmup: `false | null |
|
|
336
|
+
* undefined`. Lets `cond && query(args)` and optional-prop patterns
|
|
337
|
+
* type-check.
|
|
327
338
|
*/
|
|
328
339
|
export type FalsyQuery = false | null | undefined
|
|
329
340
|
|
|
@@ -350,6 +361,20 @@ export interface PreloadOptions {
|
|
|
350
361
|
readonly ttl?: number
|
|
351
362
|
}
|
|
352
363
|
|
|
364
|
+
/** Options accepted by `warmup()`. */
|
|
365
|
+
export interface WarmupOptions {
|
|
366
|
+
/** Connected-time grace after the query is released. */
|
|
367
|
+
readonly ttl?: number
|
|
368
|
+
/** Release the warmup hold when the signal aborts. */
|
|
369
|
+
readonly signal?: AbortSignal
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** Handle returned by `warmup()`. */
|
|
373
|
+
export interface WarmupHandle {
|
|
374
|
+
/** Release the warmup hold. Idempotent. */
|
|
375
|
+
release(): void
|
|
376
|
+
}
|
|
377
|
+
|
|
353
378
|
/** Handle returned by {@link DoyncClient.preload}. */
|
|
354
379
|
export interface PreloadHandle {
|
|
355
380
|
/**
|
|
@@ -1559,6 +1584,26 @@ export class ClientEngine implements DoyncClient {
|
|
|
1559
1584
|
) as unknown as View<Row>
|
|
1560
1585
|
}
|
|
1561
1586
|
|
|
1587
|
+
/**
|
|
1588
|
+
* Start a subscription and hold its view before a component needs it. The
|
|
1589
|
+
* hold is released automatically after a short grace window, when its signal
|
|
1590
|
+
* aborts, or when the returned handle is released. An already-aborted signal
|
|
1591
|
+
* returns an inert handle without starting the query.
|
|
1592
|
+
*/
|
|
1593
|
+
warmup<Row extends Record<string, unknown> = Record<string, SqlValue>>(
|
|
1594
|
+
query: BoundQuery<Row, boolean> | FalsyQuery,
|
|
1595
|
+
options?: WarmupOptions,
|
|
1596
|
+
): WarmupHandle {
|
|
1597
|
+
if (isFalsyQuery(query) || options?.signal?.aborted) return NOOP_WARMUP
|
|
1598
|
+
return warmupHold(
|
|
1599
|
+
this.subscribe(
|
|
1600
|
+
query,
|
|
1601
|
+
options === undefined ? undefined : { ttl: options.ttl },
|
|
1602
|
+
),
|
|
1603
|
+
options?.signal,
|
|
1604
|
+
)
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1562
1607
|
/**
|
|
1563
1608
|
* Warm the replica without materializing a View (#104, ADR-0019/0021):
|
|
1564
1609
|
* register upstream so pokes hydrate rows other queries read, at zero local
|
|
@@ -1566,8 +1611,8 @@ export class ClientEngine implements DoyncClient {
|
|
|
1566
1611
|
* a live subscribe (byte-identical statement). `{cleanup}` releases into TTL
|
|
1567
1612
|
* grace (ADR-0014). Bound form only (ADR-0027 / #200); falsy → no-op handle.
|
|
1568
1613
|
*/
|
|
1569
|
-
preload(
|
|
1570
|
-
query: BoundQuery | FalsyQuery,
|
|
1614
|
+
preload<Row extends Record<string, unknown> = Record<string, SqlValue>>(
|
|
1615
|
+
query: BoundQuery<Row, boolean> | FalsyQuery,
|
|
1571
1616
|
options?: PreloadOptions,
|
|
1572
1617
|
): PreloadHandle {
|
|
1573
1618
|
if (isFalsyQuery(query)) {
|
|
@@ -3285,6 +3330,36 @@ class SkippedOnceView implements OnceView<Record<string, unknown>> {
|
|
|
3285
3330
|
dispose(): void {}
|
|
3286
3331
|
}
|
|
3287
3332
|
|
|
3333
|
+
/** No-op {@link WarmupHandle} for warmup(falsy) (ADR-0027). */
|
|
3334
|
+
export const NOOP_WARMUP: WarmupHandle = {
|
|
3335
|
+
release(): void {},
|
|
3336
|
+
}
|
|
3337
|
+
|
|
3338
|
+
/**
|
|
3339
|
+
* Retain `view` as a warmup hold: released by the grace lapse, `signal` abort,
|
|
3340
|
+
* or the handle — idempotent, first wins. Shared by every client's `warmup` so
|
|
3341
|
+
* the three release paths cannot drift per platform.
|
|
3342
|
+
*/
|
|
3343
|
+
export function warmupHold(
|
|
3344
|
+
view: View<Record<string, unknown>>,
|
|
3345
|
+
signal?: AbortSignal,
|
|
3346
|
+
): WarmupHandle {
|
|
3347
|
+
view.retain()
|
|
3348
|
+
let timer: ReturnType<typeof setTimeout>
|
|
3349
|
+
let released = false
|
|
3350
|
+
const release = (): void => {
|
|
3351
|
+
if (released) return
|
|
3352
|
+
released = true
|
|
3353
|
+
clearTimeout(timer)
|
|
3354
|
+
signal?.removeEventListener('abort', release)
|
|
3355
|
+
view.release()
|
|
3356
|
+
}
|
|
3357
|
+
timer = setTimeout(release, WARMUP_GRACE_MS)
|
|
3358
|
+
unrefTimer(timer)
|
|
3359
|
+
signal?.addEventListener('abort', release, { once: true })
|
|
3360
|
+
return { release }
|
|
3361
|
+
}
|
|
3362
|
+
|
|
3288
3363
|
/** No-op {@link PreloadHandle} for preload(falsy) (ADR-0027). */
|
|
3289
3364
|
const NOOP_PRELOAD: PreloadHandle = {
|
|
3290
3365
|
cleanup(): void {},
|
|
@@ -3329,6 +3404,16 @@ function errorMessage(error: unknown): string {
|
|
|
3329
3404
|
* soft-nav). Future count/time bounds change only this value's shape.
|
|
3330
3405
|
*/
|
|
3331
3406
|
const WARM_POOL_TICK_MS = 0
|
|
3407
|
+
/** Warmup ownership grace; callers can release sooner via signal or handle. */
|
|
3408
|
+
const WARMUP_GRACE_MS = 15_000
|
|
3409
|
+
|
|
3410
|
+
/** Release an event-loop reference when the runtime exposes `unref()`. */
|
|
3411
|
+
function unrefTimer(timer: ReturnType<typeof setTimeout>): void {
|
|
3412
|
+
if (typeof timer === 'object' && timer !== null && 'unref' in timer) {
|
|
3413
|
+
const unref = (timer as { unref?: () => void }).unref
|
|
3414
|
+
unref?.call(timer)
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3332
3417
|
|
|
3333
3418
|
/** Shared empty-rows snapshot for skipped/unseeded Views (stable). */
|
|
3334
3419
|
const EMPTY_ROWS: readonly Record<string, unknown>[] = Object.freeze([])
|
package/src/index.ts
CHANGED
package/src/internal.ts
CHANGED
|
@@ -15,7 +15,11 @@ export {
|
|
|
15
15
|
settledRejection,
|
|
16
16
|
isFalsyQuery,
|
|
17
17
|
normalizeQuerySurface,
|
|
18
|
+
NOOP_WARMUP,
|
|
19
|
+
warmupHold,
|
|
18
20
|
type ClientEngineConfig,
|
|
21
|
+
type WarmupHandle,
|
|
22
|
+
type WarmupOptions,
|
|
19
23
|
} from './engine'
|
|
20
24
|
export { dbFileForUserId } from './identity'
|
|
21
25
|
export {
|
package/dist/client-C97IzM56.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import{declaredSchemaVersion as e,decodeArgs as t,decodeImageValue as n,decodePkValue as r,encodeArgs as i,flattenMutations as a,isBoundQuery as o,isInternalTable as s,isSqlIdentifier as c,prepareArgs as l,tablePrimaryKey as u,validateStandardSchema as ee}from"@doync/core/internal";import{SQLiteParserError as d,parse as te,parseAll as ne,unparse as re}from"@doync/sqlite-parser";var f=class{host;statement;identity;#e=[];#t=0;#n=new Set;#r;constructor(e,t,n,r){this.host=e,this.statement=t,this.identity=n,this.#r=r}get readSet(){return this.identity===void 0?void 0:this.host.readSet()}status(){return this.#r}updateStatus(e){return this.#r.status===e.status&&this.#r.error===e.error?!1:(this.#r=e,!0)}recompute(){let e=this.host.run(this.statement);return ie(e,this.#e)?!1:(this.#e=e,this.#t+=1,!0)}rawRows(){return this.#e}get generation(){return this.#t}onChange(e){return this.#n.add(e),()=>this.#n.delete(e)}notify(){for(let e of this.#n)e()}};function ie(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++){let r=e[n],i=t[n],a=Object.keys(r);if(a.length!==Object.keys(i).length)return!1;for(let e of a)if(!ae(r[e]??null,i[e]??null))return!1}return!0}function ae(e,t){if(e===t)return!0;if(e instanceof ArrayBuffer&&t instanceof ArrayBuffer){if(e.byteLength!==t.byteLength)return!1;let n=new Uint8Array(e),r=new Uint8Array(t);for(let e=0;e<n.length;e++)if(n[e]!==r[e])return!1;return!0}return!1}const oe=new Set([`STMT_CREATE_TABLE`,`STMT_CREATE_INDEX`,`STMT_CREATE_VIEW`,`STMT_CREATE_VTABLE`,`STMT_DROP`,`STMT_ALTER`]),se=new Set([`STMT_INSERT`,`STMT_UPDATE`,`STMT_DELETE`,`STMT_SELECT`,`COMPOUND_SELECT`]);function ce(e){try{return te(e)}catch(e){if(e instanceof d)return null;throw e}}function le(e){try{return ne(e)}catch(e){if(e instanceof d)return null;throw e}}function ue(e){return e.kind===`STMT_CREATE_TRIGGER`||e.kind===`STMT_DROP`&&e.target===`TRIGGER`?`trigger`:e.kind===`STMT_PRAGMA`?`pragma`:oe.has(e.kind)?`ddl`:se.has(e.kind)?`dml`:`other`}function p(e){let t=le(e);if(t===null)throw Error(`could not parse the SQL — a statement has a syntax error; fix it and retry`);return t.map(e=>re(e))}function m(e){let t=ce(e);return t===null?`other`:ue(t)}function de(e,t,n){let r=[];for(let i=t;i<n;i+=1){let a=e.migrations[i];if(a===void 0)throw Error(`doync: bundled migration track has a hole at version ${i} (requested range ${t}..${n}, but the track holds ${e.migrations.length}) — the schema is corrupt or truncated`);for(let e of p(a.sql))m(e)===`ddl`&&r.push(e)}return r}function h(e,t){let n=e.exec(`SELECT v FROM __doync_meta WHERE k = ?`,t)[0];return n===void 0||n.v===null?null:String(n.v)}function g(e,t,n){e.exec(`INSERT INTO __doync_meta (k, v) VALUES (?, ?)
|
|
2
|
-
ON CONFLICT (k) DO UPDATE SET v = excluded.v`,t,n)}function _(e,t){let n=e.exec(`SELECT v FROM __doync_prefs WHERE k = ?`,t)[0];return n===void 0||n.v===null?null:String(n.v)}function v(e,t,n){e.exec(`INSERT INTO __doync_prefs (k, v) VALUES (?, ?)
|
|
3
|
-
ON CONFLICT (k) DO UPDATE SET v = excluded.v`,t,n)}var fe="CREATE TABLE `__doync_membership` (\n `instance` text NOT NULL,\n `level` integer NOT NULL,\n `tbl` text NOT NULL,\n `pk` text NOT NULL,\n PRIMARY KEY(`instance`, `level`, `pk`)\n) WITHOUT ROWID;\n--> statement-breakpoint\nCREATE INDEX `__doync_membership_by_row` ON `__doync_membership` (`tbl`,`pk`);--> statement-breakpoint\nCREATE TABLE `__doync_meta` (\n `k` text PRIMARY KEY NOT NULL,\n `v` blob\n) WITHOUT ROWID;\n--> statement-breakpoint\nCREATE TABLE `__doync_pending` (\n `mutation_id` integer PRIMARY KEY NOT NULL,\n `name` text NOT NULL,\n `args` text NOT NULL,\n `idem_key` text\n);\n",pe="CREATE TABLE `__doync_release_stamp` (\n `instance` text PRIMARY KEY NOT NULL,\n `cookie` integer NOT NULL,\n `released_at` integer NOT NULL,\n `ttl_ms` integer NOT NULL\n) WITHOUT ROWID;\n",me="CREATE TABLE `__doync_prefs` (\n `k` text PRIMARY KEY NOT NULL,\n `v` blob\n) WITHOUT ROWID;\n--> statement-breakpoint\nINSERT INTO `__doync_prefs` (`k`, `v`)\n SELECT `k`, `v` FROM `__doync_meta` WHERE `k` = 'logout_behavior';\n--> statement-breakpoint\nDELETE FROM `__doync_meta` WHERE `k` = 'logout_behavior';\n",he=[{idx:0,version:`6`,when:1784031358638,tag:`0000_replica_engine_v0`,breakpoints:!0},{idx:1,version:`6`,when:1784450022155,tag:`0001_release_stamps`,breakpoints:!0},{idx:2,version:`6`,when:1785060176159,tag:`0002_prefs_table`,breakpoints:!0}];const ge={"0000_replica_engine_v0":fe,"0001_release_stamps":pe,"0002_prefs_table":me},y=he.slice().sort((e,t)=>e.idx-t.idx).map(e=>{let t=ge[e.tag];if(t===void 0)throw Error(`doync: replica engine track missing sql for journal tag ${JSON.stringify(e.tag)}`);return t.split(/-->\s*statement-breakpoint/).map(e=>e.trim()).filter(e=>e.length>0)});function b(e){e.exec(`CREATE TABLE IF NOT EXISTS __doync_engine (
|
|
4
|
-
k TEXT PRIMARY KEY,
|
|
5
|
-
v
|
|
6
|
-
) WITHOUT ROWID`)}function x(e,t){let n=t;for(;n<y.length;){let t=y[n];if(t===void 0)break;let r=n+1;for(let n of t)e.exec(n);e.exec(`INSERT INTO __doync_engine (k, v) VALUES ('track_version', ?)
|
|
7
|
-
ON CONFLICT (k) DO UPDATE SET v = excluded.v`,r),n=r}}function _e(e){b(e);let t=e.exec(`SELECT v FROM __doync_engine WHERE k = 'track_version'`),n=t.length===0?0:Number(t[0]?.v);if((!Number.isFinite(n)||n<0)&&(n=0),n>y.length)return console.warn(`doync: replica engine track_version ${n} is above bundled track length ${y.length} — wiping engine tables and rebuilding (code rollback against a newer database). Consumer state will resync through wipe-and-resync.`),S(e),{rolledBack:!0};try{x(e,n)}catch(t){return console.warn(`doync: replica engine track failed at version ${n} — wiping engine tables and rebuilding (code rollback against a newer database). Consumer state will resync through wipe-and-resync.`,t),S(e),{rolledBack:!0}}return{rolledBack:!1}}function S(e){let t=null;try{t=_(e,`logout_behavior`)}catch{}e.exec(`DROP TABLE IF EXISTS __doync_release_stamp`),e.exec(`DROP TABLE IF EXISTS __doync_membership`),e.exec(`DROP TABLE IF EXISTS __doync_prefs`),e.exec(`DROP TABLE IF EXISTS __doync_meta`),e.exec(`DROP TABLE IF EXISTS __doync_pending`),e.exec(`DROP TABLE IF EXISTS __doync_engine`),b(e),x(e,0),t!==null&&v(e,`logout_behavior`,t)}function ve(e){return e===void 0?18e5:e}function ye(e,t){e.exec(`INSERT INTO __doync_release_stamp (instance, cookie, released_at, ttl_ms)
|
|
8
|
-
VALUES (?, ?, ?, ?)
|
|
9
|
-
ON CONFLICT (instance) DO UPDATE SET
|
|
10
|
-
cookie = excluded.cookie,
|
|
11
|
-
released_at = excluded.released_at,
|
|
12
|
-
ttl_ms = excluded.ttl_ms`,t.instance,t.cookie,t.releasedAt,t.ttlMs)}function C(e,t){e.exec(`DELETE FROM __doync_release_stamp WHERE instance = ?`,t)}function be(e){e.exec(`DELETE FROM __doync_release_stamp`)}function w(e){return{instance:String(e.instance),cookie:Number(e.cookie),releasedAt:Number(e.released_at),ttlMs:Number(e.ttl_ms)}}function T(e,t){let n=e.exec(`SELECT instance, cookie, released_at, ttl_ms
|
|
13
|
-
FROM __doync_release_stamp WHERE instance = ?`,t)[0];return n===void 0?null:w(n)}function E(e){return e.exec(`SELECT instance, cookie, released_at, ttl_ms FROM __doync_release_stamp`).map(w)}function D(e){if(!c(e))throw Error(`doync: refusing to quote non-identifier ${JSON.stringify(e)}`);return`"${e}"`}function O(e,t){let n=JSON.parse(e),i=u(t);if(!Array.isArray(n)||n.length!==i.length)throw Error(`doync: malformed pk ${e} for table ${t.name} (expected ${i.length} key part(s))`);return n.map(e=>r(e))}function k(e){return u(e).map(e=>`${D(e)} = ?`).join(` AND `)}function xe(e,t){let r=Object.keys(t);for(let t of r)if(!c(t))throw Error(`doync: patch image for table ${e.name} has an invalid column name ${JSON.stringify(t)}`);return{columns:r,values:r.map(e=>n(t[e]))}}function Se(e,t){let n=e.tables.find(e=>e.name===t);if(n===void 0)throw Error(`doync: no synced table named ${JSON.stringify(t)} in the client schema`);return n}function A(e){return _e(e)}function j(t,n){h(t,`schema_version`)===null&&M(t,n,0,e(n))}function M(e,t,n,r){for(let i of de(t,n,r))e.execBatch(i);g(e,`schema_version`,String(r))}function N(e,t){for(let n of t.tables)e.exec(`DROP TABLE IF EXISTS ${D(n.name)}`)}function Ce(e){for(let t of e.tables)if(s(t.name))throw Error(`doync: synced table ${t.name} uses the reserved __doync_ prefix`)}const P=`logout_behavior`,F=`connected_clock`,I=`doync_optimistic`,L=`doync_body`;var R=class{lifecycle;decode;one;#e=!1;#t=null;#n=new Set;#r=Y;#i=X;#a=!1;#o=null;constructor(e,t,n){this.lifecycle=e,this.decode=t,this.one=n}#s(e){if(this.#o?.read!==e||this.#o.generation!==e.generation){let t=e.rawRows();this.#r=this.decode?this.decode(t):t,this.#o={read:e,generation:e.generation}}return this.#r}#c(){if(this.#a)return;this.#a=!0;let e=this.lifecycle.peek();if(e!==null)this.#s(e),this.#i=e.status();else{let e=this.lifecycle.compute();this.#r=e.rows,this.#i=e.status}}current(){let e=this.lifecycle.peek();return e!==null&&e.generation>0?(this.#a=!0,this.#s(e)):(this.#c(),this.#r)}status(){let e=this.lifecycle.peek();return e===null?(this.#c(),this.#i):(this.#a=!0,this.#i=e.status(),this.#i)}onChange(e){return this.#n.add(e),()=>this.#n.delete(e)}retain(){if(this.#e)return;this.#e=!0,this.#a=!0;let e=this.lifecycle.retain();if(this.#t=e.onChange(()=>{this.#s(e),this.#i=e.status();for(let e of this.#n)e()}),e.generation>0&&(this.#o?.read!==e||this.#o.generation!==e.generation)||e.status()!==this.#i){e.generation>0&&this.#s(e),this.#i=e.status();for(let e of this.#n)e()}}release(){this.#e&&(this.#e=!1,this.#t?.(),this.#t=null,this.lifecycle.release())}},z=class{#e;#t;#n;#r;#i;#a;#o=null;#s;#c;#l=1;#u=null;#d=!1;#f=0;#p=null;#m;#h=!1;#g=null;#_=!1;#v=new Set;#y=0;#b=0;#x=null;#S;#C=new Set;#w=!1;#T=[];#E=new Map;#D=new Map;#O=new Set;#k=new Set;#A=new Map;#j=new Map;#M=new Map;#N=new Map;#P=new Map;#F=1;#I=new Map;#L=new Map;#R=new Set;#z=null;#B=[];#V=!1;#H=[];#U=new Set;constructor(e){this.#e=e.db,this.#t=e.schema,this.#n=e.mutations,this.#r=e.socket,this.#i=e.ctx??null,this.#a=e.token,this.#o=e.userId??null,this.#S=e.onSchemaEvent,this.#c=e.generateId??je,this.#m=e.now??Date.now,this.#W(e),this.#r.setHandlers({message:e=>this.#Ee(e),open:()=>this.#xe(),close:()=>{this.#p=null,this.#rt(!1)},status:e=>this.#it(e)})}get connectedClock(){return this.#f}releaseStamp(e){return T(this.#e,e)}releaseStamps(){return E(this.#e)}get clientId(){return this.#s}get userId(){return this.#o}get cookie(){return this.#u}get errors(){return this.#B}get recoveredKeys(){return this.#O}get schemaVersion(){return this.#y}get schemaStatus(){return this.#x}#W(n){let r=this.#e;r.exec(`PRAGMA foreign_keys = OFF`),Ce(this.#t);let{rolledBack:i}=A(r);i?(this.#Ge(r,e(this.#t)),this.#u=null):j(r,this.#t),this.#y=e(this.#t);let a=Ne(r);a!==null&&(console.error(`doync: durable meta "${a}" is corrupt — healing by FORGETTING the local store (fresh identity, full re-hydration). A corrupt mutation counter makes the pending queue untrustworthy, so unsynced writes are discarded rather than risk double-apply.`),this.#Ke(r)),this.#b=this.#G(r,`schema_version`)??0;let o=h(r,`client_id`);this.#s=o??n.clientId??this.#c(),o===null&&g(r,`client_id`,this.#s),this.#l=this.#G(r,`next_mutation_id`)??1,this.#u=this.#G(r,`cookie`);let s=Number(h(r,F));Number.isInteger(s)&&s>=0?this.#f=s:(h(r,`connected_clock`)!==null&&console.warn(`doync: durable connected-clock reading is corrupt — resetting to 0 (clock runs slow; GC defers, server full-hydrates)`),this.#f=0),this.#p=null,a!==null&&this.#$e(`forget`,`corrupt durable meta "${a}" — forgot the local store and reset to a fresh identity`),this.#T=r.exec(`SELECT mutation_id, name, args, idem_key FROM __doync_pending ORDER BY mutation_id ASC`).map(e=>{let n=JSON.parse(String(e.args));return{mutationId:Number(e.mutation_id),name:String(e.name),wireArgs:n,args:t(n,`mutation args`),key:e.idem_key===null?void 0:String(e.idem_key)}});for(let e of this.#T){let t=this.#ut(e.mutationId,!0);e.key!==void 0&&(this.#D.set(e.key,t.pair),this.#O.add(e.key))}this.#ge({includeStampless:!1}),r.drainWrittenTables();let c=this.#Q();B(c)&&(this.#V=!0,c.then(()=>this.#J(),()=>this.#J()))}#G(e,t){let n=h(e,t);if(n===null)return null;let r=Number(n);if(!Number.isInteger(r))throw Error(`doync: durable meta "${t}" is corrupt (${JSON.stringify(n)} → ${r}) — a non-integer must never ride the wire (ADR-0019 next-id trap); the boot-time corrupt-meta heal should have caught this`);return r}#K(e){if(this.#V){this.#H.push(e);return}this.#V=!0,this.#q(e)}#q(e){let t;try{t=e()}catch(e){throw this.#V=!1,this.#Y(),e}B(t)?t.then(()=>this.#J(),e=>{this.#B.push(`doync: exclusive-chain step rejected — ${q(e)}`),this.#J()}):this.#J()}#J(){this.#V=!1,this.#Y()}#Y(){let e=this.#H.shift();if(e!==void 0){this.#V=!0,this.#q(e);return}this.#X()}#X(){if(this.#U.size===0)return;let e=[...this.#U];this.#U.clear();for(let t of e)t.recompute()&&t.notify()}#Z(e){this.#V?this.#U.add(e):e.recompute()}#Q(){return this.#e.drainWrittenTables(),this.#e.exec(`SAVEPOINT ${I}`),this.#_=!0,this.#A.clear(),V(this.#$(0),()=>{this.#R=G(this.#e.drainWrittenTables())})}#$(e){for(let t=e;t<this.#T.length;t++){let e=this.#ne(this.#T[t]);if(B(e))return e.then(()=>this.#$(t+1))}}#ee(){this.#_&&=(this.#e.exec(`ROLLBACK TO ${I}`),this.#e.exec(`RELEASE ${I}`),!1)}#te(e){let t=this.#R;this.#ee(),this.#e.drainWrittenTables(),this.#e.exec(`BEGIN`);try{e(),this.#e.exec(`COMMIT`)}catch(e){return this.#e.exec(`ROLLBACK`),V(this.#Q(),()=>{throw e})}let n=G(this.#e.drainWrittenTables());return V(this.#Q(),()=>new Set([...t,...n,...this.#R]))}#ne(e){this.#e.exec(`SAVEPOINT ${L}`);let t;try{let n=this.#n[e.name];if(n===void 0)throw Error(`unknown mutation "${e.name}"`);t=n.body({args:e.args,ctx:this.#i,sql:this.#ae()})}catch(t){this.#ie(e.mutationId,t);return}if(B(t))return t.then(()=>this.#re(e.mutationId),t=>this.#ie(e.mutationId,t));this.#re(e.mutationId)}#re(e){this.#e.exec(`RELEASE ${L}`),this.#A.delete(e)}#ie(e,t){this.#e.exec(`ROLLBACK TO ${L}`),this.#e.exec(`RELEASE ${L}`),this.#A.set(e,t)}#ae(){return{exec:(e,...t)=>this.#e.exec(e,...t.map(e=>typeof e==`boolean`?+!!e:e))}}#oe(e){this.#r.send({type:`push`,clientId:this.#s,mutationId:e.mutationId,name:e.name,args:e.wireArgs})}mutate(e,t,n){let r=n?.key;if(r!==void 0){let e=this.#D.get(r);if(e!==void 0)return e}let a=e.name;if(a===void 0||a===``)return K(Error(`doync: mutate requires a registered mutation — wrap it in defineMutations(...) so it carries a dotted name`));let o=this.#n[a];if(o===void 0)return K(Error(`doync: unknown mutation "${a}"`));let s,c;try{s=l(o.args,t,`mutation args`),c=i(s,`mutation args`)}catch(e){return K(e)}let u=this.#dt(!1);return r!==void 0&&this.#D.set(r,u.pair),this.#K(()=>this.#se({name:a,args:s,wireArgs:c,key:r,promise:u})),u.pair}#se(e){let t=this.#e,n=this.#l;this.#E.set(n,e.promise);let r={mutationId:n,name:e.name,args:e.args,wireArgs:e.wireArgs,key:e.key};return V(this.#te(()=>{t.exec(`INSERT INTO __doync_pending (mutation_id, name, args, idem_key) VALUES (?, ?, ?, ?)`,n,r.name,JSON.stringify(r.wireArgs??null),r.key??null),this.#l=n+1,g(t,`next_mutation_id`,String(this.#l)),this.#T.push(r)}),e=>this.#ce(r,e))}#ce(e,t){let n=e.mutationId;if(!this.#A.has(n)){this.#ft(n,null),this.#st(t),this.#d&&this.#oe(e);return}let r=this.#A.get(n),i=this.#E.get(n)?.pair;return e.key!==void 0&&this.#D.delete(e.key),V(this.#le(n,!0),e=>{this.#ft(n,r),this.#pt(n,r),i?.client.catch(()=>{}),i?.server.catch(()=>{}),this.#st(new Set([...t,...e]))})}#le(e,t=!1){let n=this.#e;return this.#te(()=>{n.exec(`DELETE FROM __doync_pending WHERE mutation_id = ?`,e),this.#T=this.#T.filter(t=>t.mutationId!==e),t&&(this.#l=e,g(n,`next_mutation_id`,String(e)))})}updateAuth(e,t,n){this.#a=e??void 0,n!==void 0&&(this.#o=n),t!==void 0&&(this.#i=t),this.#d&&!this.#w&&typeof e==`string`&&e!==``&&this.#r.send({type:`updateAuth`,jwt:e})}subscribe(e,t){if(U(e))return new H;let{query:n,args:r,options:i}=W(`subscribe`,e,t);if(i?.skip)return new H;let a=n.name,o=n.resolve({args:r,ctx:this.#i}),s={sql:o.sql,params:o.params},c=o.identity,l={name:a,args:r,ttl:i?.ttl,statement:s},u=o.decode;return new R({peek:()=>this.#M.get(c)?.read??null,retain:()=>this.#de(c,l),release:()=>this.#pe(c),compute:()=>{if(this.#V)return{rows:Y,status:X};let e=this.#e.exec(s.sql,...s.params),t=this.#M.get(c);return{rows:u?u(e):e,status:Q(t?.phase??`pending`,t?.error)}}},u,o.one??!1)}preload(e,t){if(U(e))return ke;let{query:n,args:r,options:i}=W(`preload`,e,t),a=n.name,o=n.resolve({args:r,ctx:this.#i}),s=o.identity;this.#fe(s,{name:a,args:r,ttl:i?.ttl,statement:{sql:o.sql,params:o.params}});let c=!1;return{cleanup:()=>{c||(c=!0,this.#pe(s))}}}#ue(e,t){let n=this.#M.get(e);if(n===void 0){let r=this.#Te(e);n={name:t.name,args:t.args,ttl:t.ttl,count:0,read:null,phase:`pending`,error:void 0},this.#M.set(e,n),this.#We(()=>C(this.#e,e)),this.#d&&this.#r.send({type:`subscribe`,queries:[this.#we(e,{heldAt:r})]})}else n.phase===`error`&&this.#d?(this.#lt(e,`pending`),this.#r.send({type:`subscribe`,queries:[this.#we(e)]})):t.ttl!==void 0&&(n.ttl===void 0||t.ttl>n.ttl)&&(n.ttl=t.ttl,this.#d&&this.#r.send({type:`subscribe`,queries:[this.#we(e)]}));return n.count+=1,n}#de(e,t){let n=this.#ue(e,t);if(n.read===null){let r=this.#L.get(e);if(r!==void 0)clearTimeout(r.timer),this.#L.delete(e),n.read=r.read,this.#Z(r.read);else{let r=new f({run:e=>this.#e.exec(e.sql,...e.params),readSet:()=>{let t=this.#j.get(e);return t===void 0?void 0:new Set(t.readSet)}},t.statement,e,Q(n.phase,n.error));n.read=r,this.#Z(r)}}return n.read}#fe(e,t){this.#ue(e,t)}#pe(e){let t=this.#M.get(e);t===void 0||--t.count>0||(this.#M.delete(e),this.#d&&this.#r.send({type:`unsubscribe`,queries:[{name:t.name,args:t.args===void 0?void 0:i(t.args,`query args`)}]}),this.#me(e,t.ttl),t.read!==null&&this.#ve(e,t.read))}#me(e,t){let n=this.#u;if(n===null)return;let r={instance:e,cookie:n,releasedAt:this.#f,ttlMs:ve(t)};this.#K(()=>V(this.#te(()=>{ye(this.#e,r),this.#ge({includeStampless:!0}),this.#he()}),e=>this.#st(e)))}#he(){g(this.#e,F,String(this.#f))}#ge(e){let t=this.#_e(e.includeStampless);if(t.length!==0){for(let e of t)this.#Le(e);this.#he()}}#_e(e){let t=this.#M,n=E(this.#e),r=new Set(n.map(e=>e.instance)),i=[];if(e){let e=this.#e.exec(`SELECT DISTINCT instance FROM __doync_membership`);for(let n of e){let e=String(n.instance);t.has(e)||r.has(e)||i.push(e)}}let a=this.#f;for(let e of n)t.has(e.instance)||(e.ttlMs<=0||a-e.releasedAt>e.ttlMs)&&i.push(e.instance);return i}#ve(e,t){let n=this.#L.get(e);n!==void 0&&clearTimeout(n.timer),this.#L.set(e,{read:t,timer:setTimeout(()=>{let n=this.#L.get(e);n===void 0||n.read!==t||(this.#L.delete(e),this.#U.delete(t))},J)})}once(e){if(U(e))return new Oe;let{query:t,args:n}=W(`once`,e),r=t.name,a=t.resolve({args:n,ctx:this.#i}),o;if(this.#V)o=[];else{let e=this.#e.exec(a.sql,...a.params);o=a.decode?a.decode(e):e}let s=`once-${this.#F++}`,c=n===void 0?void 0:i(n,`query args`),l=new Te(o,a.decode,{start:()=>{this.#N.set(s,{view:l,name:r,args:c}),this.#d&&this.#r.send({type:`once`,id:s,name:r,args:c})},drop:()=>{this.#N.delete(s),this.#P.delete(s)}});return l}local(e,...t){let n=`local:${e}\u0000${JSON.stringify(t)}`,r={sql:e,params:t};return new R({peek:()=>this.#I.get(n)?.read??null,retain:()=>this.#ye(n,r),release:()=>this.#be(n),compute:()=>this.#V?{rows:Y,status:X}:{rows:this.#e.exec(r.sql,...r.params),status:Z}},void 0,void 0)}#ye(e,t){let n=this.#I.get(e);if(n===void 0&&(n={count:0,read:null},this.#I.set(e,n)),n.count+=1,n.read===null){let r=this.#L.get(e);if(r!==void 0)clearTimeout(r.timer),this.#L.delete(e),n.read=r.read,this.#Z(r.read);else{let e=new f({run:e=>this.#e.exec(e.sql,...e.params),readSet:()=>void 0},t,void 0,Z);n.read=e,this.#Z(e)}}return n.read}#be(e){let t=this.#I.get(e);t===void 0||--t.count>0||(this.#I.delete(e),t.read!==null&&this.#ve(e,t.read))}#xe(){this.#w||(this.#p=null,this.#rt(!0),this.#Ce())}#Se(){let e=this.#m();if(this.#p!==null){let t=e-this.#p;t>0&&(this.#f+=t)}this.#p=e}#Ce(){for(let e of this.#M.keys())this.#lt(e,`pending`);this.#r.send({type:`connect`,clientId:this.#s,...this.#a===void 0?{}:{jwt:this.#a},cookie:this.#u,desiredQueries:[...this.#M.keys()].map(e=>this.#we(e)),schemaVersion:this.#y});for(let e of this.#T)this.#oe(e);for(let[e,t]of this.#N)this.#r.send({type:`once`,id:e,name:t.name,args:t.args})}#we(e,t){let n=this.#M.get(e),r=t===void 0?this.#Te(e):t.heldAt;return{name:n?.name??e,args:n?.args===void 0?void 0:i(n.args,`query args`),...n?.ttl===void 0?{}:{ttl:n.ttl},...r===void 0?{}:{heldAt:r}}}#Te(e){if(!(this.#e.exec(`SELECT 1 FROM __doync_membership WHERE instance = ? LIMIT 1`,e).length>0))return;if(this.#M.has(e))return this.#u??void 0;let t=T(this.#e,e);if(t!==null)return t.cookie}#Ee(e){if(this.#w){e.type===`error`&&this.#B.push(e.message);return}if(e.type===`pong`){this.#Se();return}if(e.type===`unauthorized`){this.#B.push(e.message),this.#at(!0);return}if(e.type===`pokeStart`&&e.clientId!==this.#s){this.#B.push(`doync: pokeStart addressed to client ${e.clientId}, this engine is ${this.#s}`);return}switch(this.#h&&e.type!==`error`&&this.#at(!1),e.type){case`schemaSkew`:this.#Be(e);break;case`schema`:this.#Ve(e);break;case`subscribeAck`:this.#et();for(let t of e.instances){this.#j.set(t.instance,t);let e=this.#M.get(t.instance);e!==void 0&&e.phase!==`complete`&&this.#lt(t.instance,`acked`)}break;case`pokeStart`:this.#et(),this.#z=[];break;case`pokePart`:if(this.#z===null)this.#B.push(`doync: pokePart arrived with no open poke`);else for(let t of e.patches)this.#z.push(t);break;case`pokeEnd`:this.#z===null?this.#B.push(`doync: pokeEnd arrived with no open poke`):this.#Ae(e.cookie,e.lastMutationId,e.confirms);break;case`pokeReject`:this.#ze(e.mutationId,e.error,e.reason);break;case`onceStart`:this.#P.set(e.id,[]);break;case`oncePart`:{let t=this.#P.get(e.id);if(t===void 0)this.#B.push(`doync: oncePart arrived with no open once`);else for(let n of e.rows)t.push(n);break}case`onceEnd`:this.#ke(e);break;case`resyncRequired`:this.#B.push(e.message),this.#K(()=>this.#Ze(`heldAt ahead of vouched baseline (instance ${e.instance}: heldAt=${e.heldAt} baseline=${e.baseline}) — ${e.message}`));break;case`error`:if(this.#B.push(e.message),Pe(e.message)){this.#K(()=>this.#Ze(`cookie above the Origin head (server reset) — ${e.message}`));break}e.instances===void 0?this.#Oe(e.message):this.#De(e.instances,e.message);break;default:this.#B.push(`doync: unknown ServerMessage type ${String(e.type)}`)}}#De(e,t){let n=Error(t);for(let t of e){let e=this.#M.get(t);e!==void 0&&(e.phase===`pending`||e.phase===`acked`)&&this.#lt(t,`error`,n)}}#Oe(e){let t=Error(e);for(let[e,n]of this.#M)(n.phase===`pending`||n.phase===`acked`)&&this.#lt(e,`error`,t)}#ke(e){let t=this.#P.get(e.id)??[];this.#P.delete(e.id);let n=this.#N.get(e.id);if(n!==void 0){if(this.#N.delete(e.id),e.error!==void 0){n.view.settleError(Error(e.error));return}n.view.deliver(t.map(Ae))}}#Ae(e,t,n){let r=this.#z??[];this.#z=null,this.#K(()=>this.#je(r,e,t,n))}#je(e,t,n,r){let i=this.#e,a=[];return V(this.#te(()=>{for(let t of e)t.op===`put`&&this.#Ne(t);for(let t of e)t.op===`del`&&this.#Pe(t);for(let t of e)t.op===`pks`&&this.#Fe(t);if(n!==null){for(let e of this.#T)e.mutationId<=n&&!this.#k.has(e.mutationId)&&a.push(e.mutationId);for(let e of a)i.exec(`DELETE FROM __doync_pending WHERE mutation_id = ?`,e)}this.#u=t,g(i,`cookie`,String(t)),this.#he(),this.#T=this.#T.filter(e=>!a.includes(e.mutationId))}),e=>{for(let e of a)this.#pt(e,null);for(let e of a)this.#k.delete(e);this.#st(e),this.#Me(r)})}#Me(e){if(e!==void 0)for(let t of e){let e=this.#M.get(t);e!==void 0&&e.phase===`acked`&&this.#lt(t,`complete`)}}#Ne(e){let t=this.#e,n=this.#Re(e.instance,e.level);t.exec(`INSERT INTO __doync_membership (instance, level, tbl, pk) VALUES (?, ?, ?, ?)
|
|
14
|
-
ON CONFLICT (instance, level, pk) DO UPDATE SET tbl = excluded.tbl`,e.instance,e.level,n.name,e.pk);let r=O(e.pk,n);t.exec(`DELETE FROM ${D(n.name)} WHERE ${k(n)}`,...r);let{columns:i,values:a}=xe(n,e.image);t.exec(`INSERT INTO ${D(n.name)} (${i.map(D).join(`, `)})
|
|
15
|
-
VALUES (${i.map(()=>`?`).join(`, `)})`,...a)}#Pe(e){this.#Ie(e.instance,e.level,e.pk)}#Fe(e){let t=new Set(e.pks),n=this.#e.exec(`SELECT pk FROM __doync_membership WHERE instance = ? AND level = ?`,e.instance,e.level);for(let r of n){let n=String(r.pk);t.has(n)||this.#Ie(e.instance,e.level,n)}}#Ie(e,t,n){let r=this.#e,i=this.#Re(e,t);r.exec(`DELETE FROM __doync_membership WHERE instance = ? AND level = ? AND pk = ?`,e,t,n);let a=r.exec(`SELECT DISTINCT instance FROM __doync_membership WHERE tbl = ? AND pk = ?`,i.name,n);if(!a.some(e=>this.#M.has(String(e.instance)))){r.exec(`DELETE FROM ${D(i.name)} WHERE ${k(i)}`,...O(n,i));for(let e of a)this.#Le(String(e.instance))}}#Le(e){let t=this.#e,n=t.exec(`SELECT DISTINCT tbl, pk FROM __doync_membership WHERE instance = ?`,e);t.exec(`DELETE FROM __doync_membership WHERE instance = ?`,e),C(t,e);for(let e of n){let n=String(e.tbl),r=String(e.pk);if(t.exec(`SELECT 1 FROM __doync_membership WHERE tbl = ? AND pk = ? LIMIT 1`,n,r).length===0){let e=Se(this.#t,n);t.exec(`DELETE FROM ${D(e.name)} WHERE ${k(e)}`,...O(r,e))}}}#Re(e,t){let n=this.#j.get(e);if(n===void 0)throw Error(`doync: patch for unknown instance ${e} — a subscribeAck must precede its hydration poke`);let r=n.levels.find(e=>e.level===t);if(r===void 0)throw Error(`doync: instance ${e} has no Level ${t} in its subscribeAck`);return Se(this.#t,r.table)}#ze(e,t,n){if(this.#k.add(e),n===`reaped`){let e=this.#T.length;this.#B.push(t),this.#K(()=>this.#Ze(`server forgot this client (reaped) — dropped ${e} pending write${e===1?``:`s`} — ${t}`,`reaped`));return}this.#K(()=>V(this.#le(e),n=>{this.#pt(e,Error(t)),this.#st(n)}))}#Be(e){let t=e.serverVersion===void 0?``:` (server v${e.serverVersion})`;e.reason===`client-stale`?(this.#$e(`reload`,`schema client-stale: bundle v${this.#y} is behind the Mirror${t} — reload for the new bundle`),this.#nt()):(this.#$e(`server-behind`,`schema client-ahead: bundle v${this.#y} is ahead of the Mirror${t} — backing off until it deploys`),this.#rt(!1),this.#r.reconnect())}#Ve(e){let t=e.version;if(t>this.#y){this.#$e(`reload`,`schema directive v${t} is above the bundled track v${this.#y} — reload for the new bundle`),this.#nt();return}t<=this.#b||this.#K(()=>this.#He(t))}#He(e){let t=t=>`local migration to schema v${e} failed: ${q(t)}`,n;try{n=this.#te(()=>{M(this.#e,this.#t,this.#b,e)})}catch(e){return this.#Ze(t(e))}return we(n,t=>{this.#b=e,this.#st(new Set([...t,...this.#Qe()]))},e=>this.#Ze(t(e)))}resync(){this.#K(()=>this.#Ze(`resync() requested by the consumer`))}forget(){this.#K(()=>this.#Je(`forget() requested by the consumer`))}setLogoutBehavior(e){this.#Ue(P,e)}#Ue(e,t){this.#We(()=>v(this.#e,e,t))}#We(e){this.#K(()=>V(this.#te(e),()=>{}))}#Ge(e,t=this.#y){N(e,this.#t),e.exec(`DELETE FROM __doync_membership`),be(e),e.exec(`DELETE FROM __doync_pending`),e.exec(`DELETE FROM __doync_meta`),M(e,this.#t,0,t)}#Ke(e){this.#Ge(e),e.exec(`DELETE FROM __doync_prefs`)}#qe(e){let t=this.#e;this.#Xe(e),this.#s=this.#c(),g(t,`client_id`,this.#s),this.#u=null,this.#l=1,this.#f=0,this.#p=null,this.#T=[]}#Je(e){let t=this.#e,n=this.#te(()=>{this.#Ke(t),this.#qe(Error(`doync: ${e} — pending writes were forgotten`))});return this.#Ye(n,`forget`,`forgot the local store — ${e}`)}#Ye(e,t,n){return V(e,e=>{this.#b=this.#y,this.#j.clear(),this.#$e(t,n),this.#d&&(this.#rt(!1),this.#r.reconnect()),this.#st(new Set([...e,...this.#Qe()]))})}#Xe(e){for(let t of this.#E.keys())this.#ft(t,e),this.#pt(t,e);this.#D.clear(),this.#O.clear(),this.#k.clear(),this.#A.clear()}#Ze(e,t=`resync`){let n=this.#e,r=this.#te(()=>{this.#Ge(n),this.#qe(Error(`doync: ${e} — pending writes were dropped`))});return this.#Ye(r,t,t===`reaped`?`client state was reaped — ${e}`:`wiped and resyncing — ${e}`)}#Qe(){return this.#t.tables.map(e=>e.name)}onSchemaChange(e){return this.#C.add(e),()=>this.#C.delete(e)}#$e(e,t){let n={kind:e,message:t};this.#x=n,this.#S?.(n),this.#tt()}#et(){let e=this.#x?.kind;(e===`server-behind`||e===`resync`||e===`reaped`||e===`forget`)&&(this.#x=null,this.#tt())}#tt(){for(let e of this.#C)e()}#nt(){this.#w=!0,this.#rt(!1)}get connectionStatus(){return this.#h?`needs-auth`:this.#d?`connected`:this.#g??`disconnected`}onConnectionChange(e){return this.#v.add(e),()=>this.#v.delete(e)}#rt(e){this.#ot(()=>{this.#d=e,e&&(this.#g=null)})}#it(e){this.#ot(()=>{this.#g=e})}#at(e){this.#ot(()=>{this.#h=e})}#ot(e){let t=this.connectionStatus;if(e(),this.connectionStatus!==t)for(let e of this.#v)e()}#st(e){let t=G(e),n=new Set(this.#U);this.#U.clear();for(let e of this.#ct()){let r=e.readSet;(n.has(e)||r===void 0||[...r].some(e=>t.has(e)))&&e.recompute()&&e.notify()}}*#ct(){for(let e of this.#M.values())e.read!==null&&(yield e.read);for(let e of this.#I.values())e.read!==null&&(yield e.read)}#lt(e,t,n){let r=this.#M.get(e);if(r===void 0)return;r.phase=t,r.error=n;let i=Q(t,n);r.read!==null&&r.read.updateStatus(i)&&r.read.notify()}#ut(e,t){let n=this.#E.get(e);if(n!==void 0)return n;let r=this.#dt(t);return this.#E.set(e,r),r}#dt(e){let t,n,r,i,a=new Promise((e,r)=>{t=e,n=r}),o=new Promise((e,t)=>{r=e,i=t});return e&&(a.catch(()=>{}),o.catch(()=>{})),{pair:{client:a,server:o},resolveClient:t,rejectClient:n,resolveServer:r,rejectServer:i,clientSettled:!1,serverSettled:!1}}#ft(e,t){let n=this.#E.get(e);if(n===void 0){this.#B.push(`doync: settleClient for unknown mutation ${e} — no pending promise (a mutate() awaiting it would hang)`);return}n.clientSettled||(n.clientSettled=!0,t===null?n.resolveClient():n.rejectClient(t))}#pt(e,t){let n=this.#E.get(e);if(n===void 0){this.#B.push(`doync: settleServer for unknown mutation ${e} — no pending promise (a mutate() awaiting it would hang)`);return}n.serverSettled||(n.serverSettled=!0,t===null?n.resolveServer():n.rejectServer(t),n.clientSettled&&this.#E.delete(e))}};function B(e){return e instanceof Promise}function V(e,t){return e instanceof Promise?e.then(t):t(e)}function we(e,t,n){return e instanceof Promise?e.then(t,n):t(e)}var H=class{current(){return Y}status(){return X}onChange(){return()=>{}}retain(){}release(){}},Te=class{#e;#t=new Set;#n=!1;#r=!1;#i=Promise.withResolvers();#a=null;#o;#s;#c;constructor(e,t,n){this.#e=e,this.#o=t,this.#s=n.start,this.#c=n.drop}current(){return this.#l(),this.#e}onChange(e){return this.#l(),this.#t.add(e),()=>this.#t.delete(e)}get server(){return this.#l(),this.#i.promise}deliver(e){if(this.#r)return;let t=this.#o?this.#o(e):e;this.#e=t,this.#i.resolve(t);for(let e of this.#t)e()}settleError(e){this.#r||this.#i.reject(e)}dispose(){this.#r||this.#a===null&&(this.#a=setTimeout(()=>{this.#a=null,!this.#r&&(this.#r=!0,this.#t.clear(),this.#c())},J))}#l(){this.#r||(this.#a!==null&&(clearTimeout(this.#a),this.#a=null),!this.#n&&(this.#n=!0,this.#i=Promise.withResolvers(),this.#i.promise.catch(()=>{}),this.#s()))}};function U(e){return e===!1||e==null}function W(e,t,n){if(o(t))return{query:t.query,args:t.args,options:n};throw Ee(e,t)}function Ee(e,t){return Error(typeof t==`function`?`doync: client.${e} expected a BoundQuery — received a function; did you forget to call it?`:`doync: client.${e} expected a BoundQuery, got ${De(t)}`)}function De(e){if(e===null)return`null`;if(Array.isArray(e))return`an array`;let t=typeof e;if(t===`object`){let t=e.kind;return typeof t==`string`?`an object with kind "${t}"`:`an object`}return t}var Oe=class{current(){return Y}onChange(){return()=>{}}get server(){return new Promise(()=>{})}dispose(){}};const ke={cleanup(){}};function Ae(e){let t={};for(let[r,i]of Object.entries(e))t[r]=n(i);return t}function G(e){return new Set([...e].filter(e=>!s(e)))}function K(e){let t=Promise.reject(e),n=Promise.reject(e);return t.catch(()=>{}),n.catch(()=>{}),{client:t,server:n}}function q(e){return e instanceof Error?e.message:String(e)}const J=0,Y=Object.freeze([]),X=Object.freeze({status:`unknown`}),Z=Object.freeze({status:`complete`});function Q(e,t){return e===`complete`?Z:e===`error`?t===void 0?{status:`error`}:{status:`error`,error:t}:X}const je=()=>{let e=globalThis.crypto?.randomUUID?.();return e===void 0?`client-${Math.random().toString(16).slice(2)}-${Date.now().toString(16)}`:e},Me=[`schema_version`,`next_mutation_id`,`cookie`];function Ne(e){for(let t of Me){let n=h(e,t);if(n!==null&&!Number.isInteger(Number(n)))return t}return null}function Pe(e){return e.includes(`above the Origin head`)}function Fe(e){return Ie(e)}function Ie(e){e.logoutBehavior!==void 0&&(A(e.db),v(e.db,P,e.logoutBehavior));let t=$(e.authData,e.ctxValidationSchema);return new z({db:e.db,schema:e.schema,mutations:a(e.mutations),socket:e.socket,ctx:t.ctx,token:t.token,userId:t.userId,clientId:e.clientId,onSchemaEvent:e.onSchemaEvent})}function $(e,t){if(e===null)return{userId:null,token:void 0,ctx:null};let n=e.ctx;return t!==void 0&&(n=ee(t,e.ctx,`auth context`)),{userId:e.userId,token:e.token,ctx:n}}export{v as _,F as a,p as b,W as c,A as d,N as f,g,_ as h,z as i,K as l,h as m,Ie as n,P as o,j as p,$ as r,U as s,Fe as t,M as u,de as v,m as y};
|
|
16
|
-
//# sourceMappingURL=client-C97IzM56.js.map
|