@bitcobblers/wod-wiki-storage 0.35.2117 → 0.35.2119

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.
@@ -1,5 +1,5 @@
1
1
  import { Client } from '@libsql/client';
2
- import { a as StoreDef, R as RangeDTO, K as KeyDTO, e as DomainQueryResult, T as TxOp, I as IStorage, S as StoreName, b as IReadOnlyStore, c as StoreType, d as IReadWriteStore, D as DomainQuery, f as IStorageTransaction } from '../wire-Cfvz-I0h.cjs';
2
+ import { a as StoreDef, R as RangeDTO, K as KeyDTO, e as DomainQueryResult, T as TxOp, I as IStorage, S as StoreName, b as IReadOnlyStore, c as StoreType, d as IReadWriteStore, D as DomainQuery, f as IStorageTransaction } from '../wire-CiFcjo6_.cjs';
3
3
  import '@bitcobblers/wod-wiki-core';
4
4
  import '@bitcobblers/wod-wiki-lang';
5
5
 
@@ -90,7 +90,17 @@ declare function clearRows(conn: SqlConnection, def: StoreDef, wipe?: boolean):
90
90
  /** Wipe all user stores; system stores (memberships) survive and the internal
91
91
  * schema metadata table is not a store, so the version guard is untouched. */
92
92
  declare function wipeRows(conn: SqlConnection): Promise<void>;
93
- /** Internal schema metadata is not exposed or cleared by the store API. */
93
+ /** Internal schema metadata is not exposed or cleared by the store API.
94
+ *
95
+ * Version policy: the SQL DDL derives entirely from STORE_DEFS, so two
96
+ * schema versions are compatible iff their derived table sets are equal.
97
+ * - stored > DB_VERSION → refuse (never downgrade).
98
+ * - stored < DB_VERSION with EQUAL table sets (v29 → v30: defs unchanged,
99
+ * only browser-local sync stores were added) → bump the guard in place;
100
+ * no row is read, rewritten or erased.
101
+ * - stored < DB_VERSION with different tables → fail closed with the same
102
+ * actionable schema_incompatible error as before.
103
+ * - no guard + store tables → foreign database, refuse. */
94
104
  declare function initializeStore(db: Database): Promise<void>;
95
105
 
96
106
  /** Current Note and actionable-block SQL projections. */
@@ -172,4 +182,149 @@ declare class BrowserTursoStorage extends SqlStorage {
172
182
  constructor(settings: TursoSettings, options?: SqlStorageOptions);
173
183
  }
174
184
 
175
- export { BrowserTursoStorage, type Database, type LibsqlClient, MAX_BODY, SCHEMA_TABLE, type SqlConnection, type SqlRow, type SqlStatement, SqlStorage, type SqlStorageOptions, type SqlValue, StorageError, type TursoSettings, clearRows, countRows, decodeRowJson, deleteRows, encodeRowJson, getRow, getRows, handleDomainQuery, initializeDomain, initializeStore, libsqlDatabase, listRows, listRowsFromIndexMany, putRow, putRows, rebuildProjections, refreshDomain, storeDefinition, validateTursoUrl, wipeDomain, wipeRows };
185
+ /**
186
+ * Turso backup/sync protocol — the local-first sync tables layered on top of
187
+ * any libsql database. The browser data plane is always IndexedDB; a saved
188
+ * Turso target is a backup/sync destination, never the read/write provider.
189
+ *
190
+ * Design: the remote holds ONE op log (`_wodwiki_sync_ops`) plus a state row
191
+ * (`_wodwiki_sync_state`) carrying {schema, rev}. Every committed local
192
+ * transaction group appends one idempotent op-group (uuid op_id,
193
+ * INSERT-or-ignore per op); `rev` is assigned monotonically per NEWLY applied
194
+ * group — a retried group is recognized by its first op id, consumes no rev
195
+ * and appends nothing. Pulls replay ops with rev > cursor in deterministic
196
+ * (rev, idx) order. Tombstones (delete/clear/wipe) are ordinary ops —
197
+ * deletions propagate.
198
+ *
199
+ * Fetch atomicity: a pull window is a set of WHOLE revision groups. The rev
200
+ * boundary is chosen with a bounded subquery, then every row of those revs is
201
+ * returned — a group is never split, so the cursor never skips the rest of
202
+ * a group (one pathologically large group can exceed the nominal row bound;
203
+ * that is the unavoidable atomicity ceiling).
204
+ *
205
+ * ponytail: op-log replay pulls — a fresh browser replays the whole log
206
+ * (O(history)) instead of reading per-store current-state tables. Upgrade
207
+ * path: add per-store state tables rev-indexed by primary key and collapse
208
+ * the log into them periodically; the wire format (op_id, rev, mutation)
209
+ * stays unchanged.
210
+ *
211
+ * Never-downgrade rule: the state row's `schema` is the managing client's
212
+ * DB_VERSION at init time. Uploads verify `schema` INSIDE the write
213
+ * transaction (a stale probe must not append current payloads to an old or
214
+ * newer remote); an older remote log is migrated forward by the caller
215
+ * (transform payloads, never just rewrite the marker), a newer remote is
216
+ * never rewritten — the client refuses and keeps working locally.
217
+ */
218
+
219
+ declare const SYNC_OPS_TABLE = "_wodwiki_sync_ops";
220
+ declare const SYNC_STATE_TABLE = "_wodwiki_sync_state";
221
+ /** Pre-migration op log copies live here — the recoverable old source,
222
+ * retained after a schema migration replaces the active log. */
223
+ declare const SYNC_ARCHIVE_TABLE = "_wodwiki_sync_ops_archive";
224
+ /** One committed local transaction group, as journaled in IndexedDB. */
225
+ type SyncMutation = {
226
+ op: 'put';
227
+ store: StoreName;
228
+ key: KeyDTO;
229
+ value: unknown;
230
+ } | {
231
+ op: 'delete';
232
+ store: StoreName;
233
+ key: KeyDTO;
234
+ } | {
235
+ op: 'clear';
236
+ store: StoreName;
237
+ } | {
238
+ op: 'wipe';
239
+ };
240
+ interface SyncEntry {
241
+ /** Idempotency key — one uuid per committed local transaction group. */
242
+ id: string;
243
+ at: number;
244
+ ops: SyncMutation[];
245
+ }
246
+ interface StoredSyncOp {
247
+ opId: string;
248
+ rev: number;
249
+ idx: number;
250
+ at: number;
251
+ mutation: SyncMutation;
252
+ }
253
+ type SyncTargetKind =
254
+ /** No tables at all (beyond libsql internals): fresh database. */
255
+ 'empty'
256
+ /** Tables exist but neither sync state nor a legacy schema guard — not
257
+ * ours; initializing over unknown data is refused by the caller. */
258
+ | {
259
+ kind: 'unknown';
260
+ }
261
+ /** Legacy direct-Turso SqlStorage layout (`_wodwiki_schema` guard). */
262
+ | {
263
+ kind: 'legacy';
264
+ schemaVersion: number;
265
+ }
266
+ /** This sync protocol's layout; payload = state row. */
267
+ | {
268
+ kind: 'current';
269
+ schemaVersion: number;
270
+ rev: number;
271
+ };
272
+ /** Classify the sync target WITHOUT mutating it. */
273
+ declare function probeSyncTarget(db: Database): Promise<SyncTargetKind>;
274
+ /** Create the sync tables + state row. Only for empty targets; existing
275
+ * state (current, legacy or unknown) is never overwritten by init. */
276
+ declare function initSyncTarget(db: Database, schemaVersion: number): Promise<void>;
277
+ interface ApplySyncBatchOptions {
278
+ /** Schema the caller verified at probe time — rechecked INSIDE the write
279
+ * transaction so a schema change between probe and append aborts. */
280
+ expectSchema?: number;
281
+ /** Bump the state schema version in the SAME transaction (remote-schema
282
+ * migrations append converted payloads + move the marker atomically). */
283
+ toSchemaVersion?: number;
284
+ }
285
+ /**
286
+ * Append op-groups to the log in ONE SQL transaction, idempotently by
287
+ * group: a group whose first op id already exists is skipped entirely and
288
+ * consumes no rev (retries never duplicate, never allocate revisions).
289
+ * Returns the number of NEW groups committed — ack semantics for the
290
+ * uploader's watermark.
291
+ */
292
+ declare function applySyncBatch(db: Database, entries: SyncEntry[], opts?: ApplySyncBatchOptions): Promise<number>;
293
+ /**
294
+ * Replay window: ops with rev > afterRev, in deterministic commit order.
295
+ * The window covers WHOLE revision groups: up to `limit` distinct revs are
296
+ * chosen (bounded subquery), then every row of those revs is returned, so a
297
+ * cursor advanced to the last returned rev never splits a group. A single
298
+ * group larger than `limit` is returned whole — the atomicity ceiling.
299
+ */
300
+ declare function fetchSyncOps(db: Database, afterRev: number, limit: number): Promise<StoredSyncOp[]>;
301
+ /**
302
+ * Schema-migration replacement for the active op log, in ONE transaction:
303
+ * every previous op is copied into the archive table (the recoverable old
304
+ * source — nothing is destroyed), the active log is cleared, and the
305
+ * converted snapshot groups become the entire replayable history at
306
+ * rev 1..n with the schema marker moved forward atomically. Fresh browsers
307
+ * replay converted payloads only, so pulls never touch legacy row shapes.
308
+ */
309
+ declare function replaceSyncLog(db: Database, entries: SyncEntry[], toSchemaVersion: number): Promise<void>;
310
+ /** Migration-only raw replay: parsed op payloads WITHOUT store/key validation
311
+ * (old logs reference era store names like `segments`). Only
312
+ * migrateRemoteToCurrent consumes this — pulls use fetchSyncOps, which
313
+ * validates every row against the current schema. Binary cells revive. */
314
+ interface RawSyncOp {
315
+ op: string;
316
+ store: string;
317
+ key: unknown;
318
+ value?: unknown;
319
+ }
320
+ declare function readRawSyncOps(db: Database): Promise<RawSyncOp[]>;
321
+ /**
322
+ * Import rows from a legacy direct-Turso (SqlStorage) database into op-
323
+ * groups. Reads the per-store JSON `data` columns directly — the legacy
324
+ * schema guard may hold an older version SqlStorage refuses to open, so the
325
+ * rows are lifted raw, never through SqlStorage. Missing tables contribute
326
+ * no rows; nothing is written or deleted remotely.
327
+ */
328
+ declare function readLegacyRows(db: Database, table: string): Promise<unknown[]>;
329
+
330
+ export { type ApplySyncBatchOptions, BrowserTursoStorage, type Database, type LibsqlClient, MAX_BODY, type RawSyncOp, SCHEMA_TABLE, SYNC_ARCHIVE_TABLE, SYNC_OPS_TABLE, SYNC_STATE_TABLE, type SqlConnection, type SqlRow, type SqlStatement, SqlStorage, type SqlStorageOptions, type SqlValue, StorageError, type StoredSyncOp, type SyncEntry, type SyncMutation, type SyncTargetKind, type TursoSettings, applySyncBatch, clearRows, countRows, decodeRowJson, deleteRows, encodeRowJson, fetchSyncOps, getRow, getRows, handleDomainQuery, initSyncTarget, initializeDomain, initializeStore, libsqlDatabase, listRows, listRowsFromIndexMany, probeSyncTarget, putRow, putRows, readLegacyRows, readRawSyncOps, rebuildProjections, refreshDomain, replaceSyncLog, storeDefinition, validateTursoUrl, wipeDomain, wipeRows };
@@ -1,5 +1,5 @@
1
1
  import { Client } from '@libsql/client';
2
- import { a as StoreDef, R as RangeDTO, K as KeyDTO, e as DomainQueryResult, T as TxOp, I as IStorage, S as StoreName, b as IReadOnlyStore, c as StoreType, d as IReadWriteStore, D as DomainQuery, f as IStorageTransaction } from '../wire-Cfvz-I0h.js';
2
+ import { a as StoreDef, R as RangeDTO, K as KeyDTO, e as DomainQueryResult, T as TxOp, I as IStorage, S as StoreName, b as IReadOnlyStore, c as StoreType, d as IReadWriteStore, D as DomainQuery, f as IStorageTransaction } from '../wire-CiFcjo6_.js';
3
3
  import '@bitcobblers/wod-wiki-core';
4
4
  import '@bitcobblers/wod-wiki-lang';
5
5
 
@@ -90,7 +90,17 @@ declare function clearRows(conn: SqlConnection, def: StoreDef, wipe?: boolean):
90
90
  /** Wipe all user stores; system stores (memberships) survive and the internal
91
91
  * schema metadata table is not a store, so the version guard is untouched. */
92
92
  declare function wipeRows(conn: SqlConnection): Promise<void>;
93
- /** Internal schema metadata is not exposed or cleared by the store API. */
93
+ /** Internal schema metadata is not exposed or cleared by the store API.
94
+ *
95
+ * Version policy: the SQL DDL derives entirely from STORE_DEFS, so two
96
+ * schema versions are compatible iff their derived table sets are equal.
97
+ * - stored > DB_VERSION → refuse (never downgrade).
98
+ * - stored < DB_VERSION with EQUAL table sets (v29 → v30: defs unchanged,
99
+ * only browser-local sync stores were added) → bump the guard in place;
100
+ * no row is read, rewritten or erased.
101
+ * - stored < DB_VERSION with different tables → fail closed with the same
102
+ * actionable schema_incompatible error as before.
103
+ * - no guard + store tables → foreign database, refuse. */
94
104
  declare function initializeStore(db: Database): Promise<void>;
95
105
 
96
106
  /** Current Note and actionable-block SQL projections. */
@@ -172,4 +182,149 @@ declare class BrowserTursoStorage extends SqlStorage {
172
182
  constructor(settings: TursoSettings, options?: SqlStorageOptions);
173
183
  }
174
184
 
175
- export { BrowserTursoStorage, type Database, type LibsqlClient, MAX_BODY, SCHEMA_TABLE, type SqlConnection, type SqlRow, type SqlStatement, SqlStorage, type SqlStorageOptions, type SqlValue, StorageError, type TursoSettings, clearRows, countRows, decodeRowJson, deleteRows, encodeRowJson, getRow, getRows, handleDomainQuery, initializeDomain, initializeStore, libsqlDatabase, listRows, listRowsFromIndexMany, putRow, putRows, rebuildProjections, refreshDomain, storeDefinition, validateTursoUrl, wipeDomain, wipeRows };
185
+ /**
186
+ * Turso backup/sync protocol — the local-first sync tables layered on top of
187
+ * any libsql database. The browser data plane is always IndexedDB; a saved
188
+ * Turso target is a backup/sync destination, never the read/write provider.
189
+ *
190
+ * Design: the remote holds ONE op log (`_wodwiki_sync_ops`) plus a state row
191
+ * (`_wodwiki_sync_state`) carrying {schema, rev}. Every committed local
192
+ * transaction group appends one idempotent op-group (uuid op_id,
193
+ * INSERT-or-ignore per op); `rev` is assigned monotonically per NEWLY applied
194
+ * group — a retried group is recognized by its first op id, consumes no rev
195
+ * and appends nothing. Pulls replay ops with rev > cursor in deterministic
196
+ * (rev, idx) order. Tombstones (delete/clear/wipe) are ordinary ops —
197
+ * deletions propagate.
198
+ *
199
+ * Fetch atomicity: a pull window is a set of WHOLE revision groups. The rev
200
+ * boundary is chosen with a bounded subquery, then every row of those revs is
201
+ * returned — a group is never split, so the cursor never skips the rest of
202
+ * a group (one pathologically large group can exceed the nominal row bound;
203
+ * that is the unavoidable atomicity ceiling).
204
+ *
205
+ * ponytail: op-log replay pulls — a fresh browser replays the whole log
206
+ * (O(history)) instead of reading per-store current-state tables. Upgrade
207
+ * path: add per-store state tables rev-indexed by primary key and collapse
208
+ * the log into them periodically; the wire format (op_id, rev, mutation)
209
+ * stays unchanged.
210
+ *
211
+ * Never-downgrade rule: the state row's `schema` is the managing client's
212
+ * DB_VERSION at init time. Uploads verify `schema` INSIDE the write
213
+ * transaction (a stale probe must not append current payloads to an old or
214
+ * newer remote); an older remote log is migrated forward by the caller
215
+ * (transform payloads, never just rewrite the marker), a newer remote is
216
+ * never rewritten — the client refuses and keeps working locally.
217
+ */
218
+
219
+ declare const SYNC_OPS_TABLE = "_wodwiki_sync_ops";
220
+ declare const SYNC_STATE_TABLE = "_wodwiki_sync_state";
221
+ /** Pre-migration op log copies live here — the recoverable old source,
222
+ * retained after a schema migration replaces the active log. */
223
+ declare const SYNC_ARCHIVE_TABLE = "_wodwiki_sync_ops_archive";
224
+ /** One committed local transaction group, as journaled in IndexedDB. */
225
+ type SyncMutation = {
226
+ op: 'put';
227
+ store: StoreName;
228
+ key: KeyDTO;
229
+ value: unknown;
230
+ } | {
231
+ op: 'delete';
232
+ store: StoreName;
233
+ key: KeyDTO;
234
+ } | {
235
+ op: 'clear';
236
+ store: StoreName;
237
+ } | {
238
+ op: 'wipe';
239
+ };
240
+ interface SyncEntry {
241
+ /** Idempotency key — one uuid per committed local transaction group. */
242
+ id: string;
243
+ at: number;
244
+ ops: SyncMutation[];
245
+ }
246
+ interface StoredSyncOp {
247
+ opId: string;
248
+ rev: number;
249
+ idx: number;
250
+ at: number;
251
+ mutation: SyncMutation;
252
+ }
253
+ type SyncTargetKind =
254
+ /** No tables at all (beyond libsql internals): fresh database. */
255
+ 'empty'
256
+ /** Tables exist but neither sync state nor a legacy schema guard — not
257
+ * ours; initializing over unknown data is refused by the caller. */
258
+ | {
259
+ kind: 'unknown';
260
+ }
261
+ /** Legacy direct-Turso SqlStorage layout (`_wodwiki_schema` guard). */
262
+ | {
263
+ kind: 'legacy';
264
+ schemaVersion: number;
265
+ }
266
+ /** This sync protocol's layout; payload = state row. */
267
+ | {
268
+ kind: 'current';
269
+ schemaVersion: number;
270
+ rev: number;
271
+ };
272
+ /** Classify the sync target WITHOUT mutating it. */
273
+ declare function probeSyncTarget(db: Database): Promise<SyncTargetKind>;
274
+ /** Create the sync tables + state row. Only for empty targets; existing
275
+ * state (current, legacy or unknown) is never overwritten by init. */
276
+ declare function initSyncTarget(db: Database, schemaVersion: number): Promise<void>;
277
+ interface ApplySyncBatchOptions {
278
+ /** Schema the caller verified at probe time — rechecked INSIDE the write
279
+ * transaction so a schema change between probe and append aborts. */
280
+ expectSchema?: number;
281
+ /** Bump the state schema version in the SAME transaction (remote-schema
282
+ * migrations append converted payloads + move the marker atomically). */
283
+ toSchemaVersion?: number;
284
+ }
285
+ /**
286
+ * Append op-groups to the log in ONE SQL transaction, idempotently by
287
+ * group: a group whose first op id already exists is skipped entirely and
288
+ * consumes no rev (retries never duplicate, never allocate revisions).
289
+ * Returns the number of NEW groups committed — ack semantics for the
290
+ * uploader's watermark.
291
+ */
292
+ declare function applySyncBatch(db: Database, entries: SyncEntry[], opts?: ApplySyncBatchOptions): Promise<number>;
293
+ /**
294
+ * Replay window: ops with rev > afterRev, in deterministic commit order.
295
+ * The window covers WHOLE revision groups: up to `limit` distinct revs are
296
+ * chosen (bounded subquery), then every row of those revs is returned, so a
297
+ * cursor advanced to the last returned rev never splits a group. A single
298
+ * group larger than `limit` is returned whole — the atomicity ceiling.
299
+ */
300
+ declare function fetchSyncOps(db: Database, afterRev: number, limit: number): Promise<StoredSyncOp[]>;
301
+ /**
302
+ * Schema-migration replacement for the active op log, in ONE transaction:
303
+ * every previous op is copied into the archive table (the recoverable old
304
+ * source — nothing is destroyed), the active log is cleared, and the
305
+ * converted snapshot groups become the entire replayable history at
306
+ * rev 1..n with the schema marker moved forward atomically. Fresh browsers
307
+ * replay converted payloads only, so pulls never touch legacy row shapes.
308
+ */
309
+ declare function replaceSyncLog(db: Database, entries: SyncEntry[], toSchemaVersion: number): Promise<void>;
310
+ /** Migration-only raw replay: parsed op payloads WITHOUT store/key validation
311
+ * (old logs reference era store names like `segments`). Only
312
+ * migrateRemoteToCurrent consumes this — pulls use fetchSyncOps, which
313
+ * validates every row against the current schema. Binary cells revive. */
314
+ interface RawSyncOp {
315
+ op: string;
316
+ store: string;
317
+ key: unknown;
318
+ value?: unknown;
319
+ }
320
+ declare function readRawSyncOps(db: Database): Promise<RawSyncOp[]>;
321
+ /**
322
+ * Import rows from a legacy direct-Turso (SqlStorage) database into op-
323
+ * groups. Reads the per-store JSON `data` columns directly — the legacy
324
+ * schema guard may hold an older version SqlStorage refuses to open, so the
325
+ * rows are lifted raw, never through SqlStorage. Missing tables contribute
326
+ * no rows; nothing is written or deleted remotely.
327
+ */
328
+ declare function readLegacyRows(db: Database, table: string): Promise<unknown[]>;
329
+
330
+ export { type ApplySyncBatchOptions, BrowserTursoStorage, type Database, type LibsqlClient, MAX_BODY, type RawSyncOp, SCHEMA_TABLE, SYNC_ARCHIVE_TABLE, SYNC_OPS_TABLE, SYNC_STATE_TABLE, type SqlConnection, type SqlRow, type SqlStatement, SqlStorage, type SqlStorageOptions, type SqlValue, StorageError, type StoredSyncOp, type SyncEntry, type SyncMutation, type SyncTargetKind, type TursoSettings, applySyncBatch, clearRows, countRows, decodeRowJson, deleteRows, encodeRowJson, fetchSyncOps, getRow, getRows, handleDomainQuery, initSyncTarget, initializeDomain, initializeStore, libsqlDatabase, listRows, listRowsFromIndexMany, probeSyncTarget, putRow, putRows, readLegacyRows, readRawSyncOps, rebuildProjections, refreshDomain, replaceSyncLog, storeDefinition, validateTursoUrl, wipeDomain, wipeRows };