@bitcobblers/wod-wiki-storage 0.39.2142 → 0.40.2144
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/dist/chunk-IFLOX2TK.mjs +874 -0
- package/dist/chunk-IFLOX2TK.mjs.map +1 -0
- package/dist/{chunk-NUJEAUAK.mjs → chunk-IMNG2HY5.mjs} +4 -131
- package/dist/chunk-IMNG2HY5.mjs.map +1 -0
- package/dist/chunk-JFVXIJJI.mjs +134 -0
- package/dist/chunk-JFVXIJJI.mjs.map +1 -0
- package/dist/chunk-MOGQICXM.mjs +43 -0
- package/dist/chunk-MOGQICXM.mjs.map +1 -0
- package/dist/idb/index.cjs +1462 -0
- package/dist/idb/index.cjs.map +1 -0
- package/dist/idb/index.d.cts +156 -0
- package/dist/idb/index.d.ts +156 -0
- package/dist/idb/index.mjs +1079 -0
- package/dist/idb/index.mjs.map +1 -0
- package/dist/index.cjs +47 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.mjs +5 -2
- package/dist/index.mjs.map +1 -1
- package/dist/policy-CPscN81J.d.ts +49 -0
- package/dist/policy-DRYF6Y8i.d.cts +49 -0
- package/dist/sql/index.cjs +241 -38
- package/dist/sql/index.cjs.map +1 -1
- package/dist/sql/index.d.cts +64 -132
- package/dist/sql/index.d.ts +64 -132
- package/dist/sql/index.mjs +188 -852
- package/dist/sql/index.mjs.map +1 -1
- package/dist/sync-Bjj_c1ea.d.ts +141 -0
- package/dist/sync-DG4Z-szj.d.cts +141 -0
- package/dist/{wire-CKJDK_Nq.d.cts → wire-DGYxXt3I.d.cts} +2 -2
- package/dist/{wire-CKJDK_Nq.d.ts → wire-DGYxXt3I.d.ts} +2 -2
- package/package.json +14 -7
- package/dist/chunk-NUJEAUAK.mjs.map +0 -1
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { IDBPDatabase, IDBPTransaction } from 'idb';
|
|
2
|
+
import { I as IStorage, S as StoreName, a as IReadOnlyStore, b as StoreType, c as IReadWriteStore, d as IStorageTransaction } from '../wire-DGYxXt3I.cjs';
|
|
3
|
+
import { U as UserScopeContext } from '../policy-DRYF6Y8i.cjs';
|
|
4
|
+
import { S as SyncMutation, a as SyncEntry } from '../sync-DG4Z-szj.cjs';
|
|
5
|
+
import { D as Database } from '../connection-DxuCLpRc.cjs';
|
|
6
|
+
import '@bitcobblers/wod-wiki-core';
|
|
7
|
+
import '@bitcobblers/wod-wiki-lang';
|
|
8
|
+
import '@libsql/client';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* IndexedDB adapter — the browser data plane (moved verbatim from the
|
|
12
|
+
* playground app; the shared user policy and the schema32 sync cutover live
|
|
13
|
+
* here now). Local-first invariants:
|
|
14
|
+
*
|
|
15
|
+
* - Every committed local transaction group is durable in `sync_outbox`,
|
|
16
|
+
* written in the SAME native transaction as the data writes.
|
|
17
|
+
* - Snapshots (`snapshotRows`, bootstrap, conversion) are policy-compliant:
|
|
18
|
+
* they carry user data only, per the shared policy in `../policy`.
|
|
19
|
+
* - `sync_state` holds pull cursors, upload watermarks and frozen
|
|
20
|
+
* bootstrap runs (durable retry identities), all per backup target.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
declare const IDB_DB_NAME = "wodwiki-db";
|
|
24
|
+
type Mode = 'readonly' | 'readwrite';
|
|
25
|
+
/** Native tx handle; write methods are guarded at runtime by `mutable`, so
|
|
26
|
+
* the handle is typed readwrite to keep put/delete/clear defined. */
|
|
27
|
+
type Tx = IDBPTransaction<unknown, string, 'readwrite'>;
|
|
28
|
+
declare function subscribeOutboxWrites(listener: () => void): () => void;
|
|
29
|
+
declare class IndexedDBStorage implements IStorage {
|
|
30
|
+
private readonly options;
|
|
31
|
+
private opening?;
|
|
32
|
+
constructor(options?: {
|
|
33
|
+
getUserId?: () => string;
|
|
34
|
+
/** Called just before a schema migration runs (oldVersion < DB_VERSION). */
|
|
35
|
+
onUpgradeStart?: (fromVersion: number) => void;
|
|
36
|
+
/** Database file name; the sync engine migrates scratch copies under
|
|
37
|
+
* their own name so a remote-schema conversion never touches the
|
|
38
|
+
* live database. Defaults to the app database. */
|
|
39
|
+
dbName?: string;
|
|
40
|
+
});
|
|
41
|
+
open(): Promise<IDBPDatabase>;
|
|
42
|
+
stamp(store: StoreName, value: unknown): unknown;
|
|
43
|
+
/** User-scope context (proven seed note ids) from the notes of `tx` —
|
|
44
|
+
* journal-time ownership classification reads it INSIDE the same
|
|
45
|
+
* transaction, so a seed import's note writes are visible to the link
|
|
46
|
+
* writes that follow in the same commit. Internal seam for IDBStore. */
|
|
47
|
+
policyContext(tx?: Tx): Promise<UserScopeContext>;
|
|
48
|
+
readonly<K extends StoreName>(store: K): IReadOnlyStore<StoreType<K>>;
|
|
49
|
+
readwrite<K extends StoreName>(store: K): IReadWriteStore<StoreType<K>>;
|
|
50
|
+
transaction<K extends StoreName, R>(stores: K[], mode: Mode, fn: (tx: IStorageTransaction) => Promise<R>): Promise<R>;
|
|
51
|
+
wipeUserData(): Promise<void>;
|
|
52
|
+
wipe(): Promise<void>;
|
|
53
|
+
/** Pending committed transaction groups, in commit order. */
|
|
54
|
+
readOutbox(afterSeq: number, limit: number): Promise<{
|
|
55
|
+
seq: number;
|
|
56
|
+
id: string;
|
|
57
|
+
at: number;
|
|
58
|
+
ops: SyncMutation[];
|
|
59
|
+
}[]>;
|
|
60
|
+
/** Drop acknowledged groups. Callers pass only the contiguous acked
|
|
61
|
+
* watermark — a failed upload never truncates pending writes. */
|
|
62
|
+
ackOutbox(upToSeq: number): Promise<void>;
|
|
63
|
+
getSyncState<T>(key: string): Promise<T | undefined>;
|
|
64
|
+
setSyncState(key: string, value: unknown): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Freeze ONE durable bootstrap run for `key` (per backup target): a
|
|
67
|
+
* policy-compliant snapshot of the current rows, chunked into ≤500-op /
|
|
68
|
+
* ≤~1MB entries with a unique run UUID and stable chunk ids, persisted in
|
|
69
|
+
* `sync_state[key]` in the SAME readwrite transaction that reads the data
|
|
70
|
+
* — so a retry returns the byte-identical frozen entries (idempotent
|
|
71
|
+
* remote replays), and a crash before the commit freezes nothing. No
|
|
72
|
+
* network happens here.
|
|
73
|
+
*
|
|
74
|
+
* Pending outbox groups are read INSIDE the same transaction: their
|
|
75
|
+
* touched keys/stores are excluded from the snapshot so the journal (which
|
|
76
|
+
* ships after the bootstrap, in commit order) stays the last writer and
|
|
77
|
+
* nothing ships twice. A pending wipe freezes an empty run — the journal
|
|
78
|
+
* wipe itself still ships and decides the remote's end state.
|
|
79
|
+
*
|
|
80
|
+
* The engine deletes the frozen run (`db.delete('sync_state', key)`) only
|
|
81
|
+
* after the remote commit; until then every retry replays these entries.
|
|
82
|
+
*/
|
|
83
|
+
captureSyncBootstrap(key: string): Promise<SyncEntry[]>;
|
|
84
|
+
/**
|
|
85
|
+
* Validate every stored pin (note blocks + session pins against
|
|
86
|
+
* block_revisions) in ONE consistent readonly read — the post-restore
|
|
87
|
+
* gate: a replayed backup with missing history fails loudly here instead
|
|
88
|
+
* of surfacing later as broken sessions.
|
|
89
|
+
*/
|
|
90
|
+
validateSyncState(): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Apply remotely committed mutations locally (pull/replay) WITHOUT
|
|
93
|
+
* journaling — a pulled mutation must never re-enter the outbox. Runs in
|
|
94
|
+
* one native transaction together with the cursor update.
|
|
95
|
+
*
|
|
96
|
+
* Unsent-edit overlay: pending outbox groups (committed local writes not
|
|
97
|
+
* yet acknowledged remotely) are read INSIDE the same transaction and
|
|
98
|
+
* replayed after the remote rows — a local edit/delete/clear/wipe that
|
|
99
|
+
* committed while the pull was on the network stays the visible state;
|
|
100
|
+
* the remote row is backed up locally, not clobbered over the user.
|
|
101
|
+
*
|
|
102
|
+
* Conflict policy (deterministic, history-preserving):
|
|
103
|
+
* - notes: an incoming row with a LOWER sourceRevision than the existing
|
|
104
|
+
* row is stale — skipped, never clobbers newer history.
|
|
105
|
+
* - block_revisions: same key with different contents keeps BOTH rows —
|
|
106
|
+
* the incoming version is re-keyed to the next free version for that
|
|
107
|
+
* block. Immutable history is never silently replaced.
|
|
108
|
+
* - memberships (system): remote mutations are skipped — identity truth
|
|
109
|
+
* stays local and snapshot/upload never include them.
|
|
110
|
+
*
|
|
111
|
+
* Returns committed-boundary counts of canonical consumer records (notes +
|
|
112
|
+
* efforts only; internal/journal rows never reach the sync toast).
|
|
113
|
+
* `cursorKey` keeps cursors per backup target.
|
|
114
|
+
*/
|
|
115
|
+
applySyncMutations(mutations: SyncMutation[], cursorRev: number | null, cursorKey?: string): Promise<{
|
|
116
|
+
added: number;
|
|
117
|
+
updated: number;
|
|
118
|
+
}>;
|
|
119
|
+
/**
|
|
120
|
+
* Consistent atomic snapshot, policy-compliant (shared user policy): only
|
|
121
|
+
* user-scope rows of the non-system stores, read in ONE readonly
|
|
122
|
+
* transaction — the backup never mixes the pre/post state of a concurrent
|
|
123
|
+
* local commit. System stores (memberships) are excluded: they never sync.
|
|
124
|
+
* Use `snapshotAllRows` for the lossless (unfiltered) form.
|
|
125
|
+
*/
|
|
126
|
+
snapshotRows(): Promise<{
|
|
127
|
+
store: StoreName;
|
|
128
|
+
rows: unknown[];
|
|
129
|
+
}[]>;
|
|
130
|
+
/** Lossless snapshot of every NON-SYSTEM store (meta included) in one
|
|
131
|
+
* readonly transaction — local export / restore emptiness checks. A
|
|
132
|
+
* freshly initialized database may hold a default membership, so the
|
|
133
|
+
* system store is excluded from both uses. */
|
|
134
|
+
snapshotAllRows(): Promise<{
|
|
135
|
+
store: StoreName;
|
|
136
|
+
rows: unknown[];
|
|
137
|
+
}[]>;
|
|
138
|
+
close(): Promise<void>;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Convert an older backup into policy-compliant current-schema mutations
|
|
142
|
+
* WITHOUT touching the source:
|
|
143
|
+
*
|
|
144
|
+
* 1. Lift the source data as ordered scratch ops (op-log replay in log
|
|
145
|
+
* order, or legacy direct-Turso per-store rows incl. segments/results).
|
|
146
|
+
* 2. Replay them into a unique scratch IndexedDB created AT `fromVersion`,
|
|
147
|
+
* then open it through IndexedDBStorage — the same versioned migration
|
|
148
|
+
* chain the browser runs locally rebuilds segments-era rows into
|
|
149
|
+
* note-owned blocks, revisions, sessions and events.
|
|
150
|
+
* 3. Validate strictly (all note/session pins, binary payloads, derivable
|
|
151
|
+
* keys — any miss fails the copy) and return policy-compliant PUTS ONLY
|
|
152
|
+
* (the caller applies them to a fresh, reserved target).
|
|
153
|
+
*/
|
|
154
|
+
declare function convertSyncSource(db: Database, fromVersion: number, legacy: boolean): Promise<SyncMutation[]>;
|
|
155
|
+
|
|
156
|
+
export { IDB_DB_NAME, IndexedDBStorage, convertSyncSource, subscribeOutboxWrites };
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { IDBPDatabase, IDBPTransaction } from 'idb';
|
|
2
|
+
import { I as IStorage, S as StoreName, a as IReadOnlyStore, b as StoreType, c as IReadWriteStore, d as IStorageTransaction } from '../wire-DGYxXt3I.js';
|
|
3
|
+
import { U as UserScopeContext } from '../policy-CPscN81J.js';
|
|
4
|
+
import { S as SyncMutation, a as SyncEntry } from '../sync-Bjj_c1ea.js';
|
|
5
|
+
import { D as Database } from '../connection-DxuCLpRc.js';
|
|
6
|
+
import '@bitcobblers/wod-wiki-core';
|
|
7
|
+
import '@bitcobblers/wod-wiki-lang';
|
|
8
|
+
import '@libsql/client';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* IndexedDB adapter — the browser data plane (moved verbatim from the
|
|
12
|
+
* playground app; the shared user policy and the schema32 sync cutover live
|
|
13
|
+
* here now). Local-first invariants:
|
|
14
|
+
*
|
|
15
|
+
* - Every committed local transaction group is durable in `sync_outbox`,
|
|
16
|
+
* written in the SAME native transaction as the data writes.
|
|
17
|
+
* - Snapshots (`snapshotRows`, bootstrap, conversion) are policy-compliant:
|
|
18
|
+
* they carry user data only, per the shared policy in `../policy`.
|
|
19
|
+
* - `sync_state` holds pull cursors, upload watermarks and frozen
|
|
20
|
+
* bootstrap runs (durable retry identities), all per backup target.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
declare const IDB_DB_NAME = "wodwiki-db";
|
|
24
|
+
type Mode = 'readonly' | 'readwrite';
|
|
25
|
+
/** Native tx handle; write methods are guarded at runtime by `mutable`, so
|
|
26
|
+
* the handle is typed readwrite to keep put/delete/clear defined. */
|
|
27
|
+
type Tx = IDBPTransaction<unknown, string, 'readwrite'>;
|
|
28
|
+
declare function subscribeOutboxWrites(listener: () => void): () => void;
|
|
29
|
+
declare class IndexedDBStorage implements IStorage {
|
|
30
|
+
private readonly options;
|
|
31
|
+
private opening?;
|
|
32
|
+
constructor(options?: {
|
|
33
|
+
getUserId?: () => string;
|
|
34
|
+
/** Called just before a schema migration runs (oldVersion < DB_VERSION). */
|
|
35
|
+
onUpgradeStart?: (fromVersion: number) => void;
|
|
36
|
+
/** Database file name; the sync engine migrates scratch copies under
|
|
37
|
+
* their own name so a remote-schema conversion never touches the
|
|
38
|
+
* live database. Defaults to the app database. */
|
|
39
|
+
dbName?: string;
|
|
40
|
+
});
|
|
41
|
+
open(): Promise<IDBPDatabase>;
|
|
42
|
+
stamp(store: StoreName, value: unknown): unknown;
|
|
43
|
+
/** User-scope context (proven seed note ids) from the notes of `tx` —
|
|
44
|
+
* journal-time ownership classification reads it INSIDE the same
|
|
45
|
+
* transaction, so a seed import's note writes are visible to the link
|
|
46
|
+
* writes that follow in the same commit. Internal seam for IDBStore. */
|
|
47
|
+
policyContext(tx?: Tx): Promise<UserScopeContext>;
|
|
48
|
+
readonly<K extends StoreName>(store: K): IReadOnlyStore<StoreType<K>>;
|
|
49
|
+
readwrite<K extends StoreName>(store: K): IReadWriteStore<StoreType<K>>;
|
|
50
|
+
transaction<K extends StoreName, R>(stores: K[], mode: Mode, fn: (tx: IStorageTransaction) => Promise<R>): Promise<R>;
|
|
51
|
+
wipeUserData(): Promise<void>;
|
|
52
|
+
wipe(): Promise<void>;
|
|
53
|
+
/** Pending committed transaction groups, in commit order. */
|
|
54
|
+
readOutbox(afterSeq: number, limit: number): Promise<{
|
|
55
|
+
seq: number;
|
|
56
|
+
id: string;
|
|
57
|
+
at: number;
|
|
58
|
+
ops: SyncMutation[];
|
|
59
|
+
}[]>;
|
|
60
|
+
/** Drop acknowledged groups. Callers pass only the contiguous acked
|
|
61
|
+
* watermark — a failed upload never truncates pending writes. */
|
|
62
|
+
ackOutbox(upToSeq: number): Promise<void>;
|
|
63
|
+
getSyncState<T>(key: string): Promise<T | undefined>;
|
|
64
|
+
setSyncState(key: string, value: unknown): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Freeze ONE durable bootstrap run for `key` (per backup target): a
|
|
67
|
+
* policy-compliant snapshot of the current rows, chunked into ≤500-op /
|
|
68
|
+
* ≤~1MB entries with a unique run UUID and stable chunk ids, persisted in
|
|
69
|
+
* `sync_state[key]` in the SAME readwrite transaction that reads the data
|
|
70
|
+
* — so a retry returns the byte-identical frozen entries (idempotent
|
|
71
|
+
* remote replays), and a crash before the commit freezes nothing. No
|
|
72
|
+
* network happens here.
|
|
73
|
+
*
|
|
74
|
+
* Pending outbox groups are read INSIDE the same transaction: their
|
|
75
|
+
* touched keys/stores are excluded from the snapshot so the journal (which
|
|
76
|
+
* ships after the bootstrap, in commit order) stays the last writer and
|
|
77
|
+
* nothing ships twice. A pending wipe freezes an empty run — the journal
|
|
78
|
+
* wipe itself still ships and decides the remote's end state.
|
|
79
|
+
*
|
|
80
|
+
* The engine deletes the frozen run (`db.delete('sync_state', key)`) only
|
|
81
|
+
* after the remote commit; until then every retry replays these entries.
|
|
82
|
+
*/
|
|
83
|
+
captureSyncBootstrap(key: string): Promise<SyncEntry[]>;
|
|
84
|
+
/**
|
|
85
|
+
* Validate every stored pin (note blocks + session pins against
|
|
86
|
+
* block_revisions) in ONE consistent readonly read — the post-restore
|
|
87
|
+
* gate: a replayed backup with missing history fails loudly here instead
|
|
88
|
+
* of surfacing later as broken sessions.
|
|
89
|
+
*/
|
|
90
|
+
validateSyncState(): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Apply remotely committed mutations locally (pull/replay) WITHOUT
|
|
93
|
+
* journaling — a pulled mutation must never re-enter the outbox. Runs in
|
|
94
|
+
* one native transaction together with the cursor update.
|
|
95
|
+
*
|
|
96
|
+
* Unsent-edit overlay: pending outbox groups (committed local writes not
|
|
97
|
+
* yet acknowledged remotely) are read INSIDE the same transaction and
|
|
98
|
+
* replayed after the remote rows — a local edit/delete/clear/wipe that
|
|
99
|
+
* committed while the pull was on the network stays the visible state;
|
|
100
|
+
* the remote row is backed up locally, not clobbered over the user.
|
|
101
|
+
*
|
|
102
|
+
* Conflict policy (deterministic, history-preserving):
|
|
103
|
+
* - notes: an incoming row with a LOWER sourceRevision than the existing
|
|
104
|
+
* row is stale — skipped, never clobbers newer history.
|
|
105
|
+
* - block_revisions: same key with different contents keeps BOTH rows —
|
|
106
|
+
* the incoming version is re-keyed to the next free version for that
|
|
107
|
+
* block. Immutable history is never silently replaced.
|
|
108
|
+
* - memberships (system): remote mutations are skipped — identity truth
|
|
109
|
+
* stays local and snapshot/upload never include them.
|
|
110
|
+
*
|
|
111
|
+
* Returns committed-boundary counts of canonical consumer records (notes +
|
|
112
|
+
* efforts only; internal/journal rows never reach the sync toast).
|
|
113
|
+
* `cursorKey` keeps cursors per backup target.
|
|
114
|
+
*/
|
|
115
|
+
applySyncMutations(mutations: SyncMutation[], cursorRev: number | null, cursorKey?: string): Promise<{
|
|
116
|
+
added: number;
|
|
117
|
+
updated: number;
|
|
118
|
+
}>;
|
|
119
|
+
/**
|
|
120
|
+
* Consistent atomic snapshot, policy-compliant (shared user policy): only
|
|
121
|
+
* user-scope rows of the non-system stores, read in ONE readonly
|
|
122
|
+
* transaction — the backup never mixes the pre/post state of a concurrent
|
|
123
|
+
* local commit. System stores (memberships) are excluded: they never sync.
|
|
124
|
+
* Use `snapshotAllRows` for the lossless (unfiltered) form.
|
|
125
|
+
*/
|
|
126
|
+
snapshotRows(): Promise<{
|
|
127
|
+
store: StoreName;
|
|
128
|
+
rows: unknown[];
|
|
129
|
+
}[]>;
|
|
130
|
+
/** Lossless snapshot of every NON-SYSTEM store (meta included) in one
|
|
131
|
+
* readonly transaction — local export / restore emptiness checks. A
|
|
132
|
+
* freshly initialized database may hold a default membership, so the
|
|
133
|
+
* system store is excluded from both uses. */
|
|
134
|
+
snapshotAllRows(): Promise<{
|
|
135
|
+
store: StoreName;
|
|
136
|
+
rows: unknown[];
|
|
137
|
+
}[]>;
|
|
138
|
+
close(): Promise<void>;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Convert an older backup into policy-compliant current-schema mutations
|
|
142
|
+
* WITHOUT touching the source:
|
|
143
|
+
*
|
|
144
|
+
* 1. Lift the source data as ordered scratch ops (op-log replay in log
|
|
145
|
+
* order, or legacy direct-Turso per-store rows incl. segments/results).
|
|
146
|
+
* 2. Replay them into a unique scratch IndexedDB created AT `fromVersion`,
|
|
147
|
+
* then open it through IndexedDBStorage — the same versioned migration
|
|
148
|
+
* chain the browser runs locally rebuilds segments-era rows into
|
|
149
|
+
* note-owned blocks, revisions, sessions and events.
|
|
150
|
+
* 3. Validate strictly (all note/session pins, binary payloads, derivable
|
|
151
|
+
* keys — any miss fails the copy) and return policy-compliant PUTS ONLY
|
|
152
|
+
* (the caller applies them to a fresh, reserved target).
|
|
153
|
+
*/
|
|
154
|
+
declare function convertSyncSource(db: Database, fromVersion: number, legacy: boolean): Promise<SyncMutation[]>;
|
|
155
|
+
|
|
156
|
+
export { IDB_DB_NAME, IndexedDBStorage, convertSyncSource, subscribeOutboxWrites };
|