@bitcobblers/wod-wiki-storage 0.35.2129 → 0.36.2133
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-6ZTAWTAP.mjs +58 -0
- package/dist/chunk-6ZTAWTAP.mjs.map +1 -0
- package/dist/chunk-XRQKLSOT.mjs +15 -0
- package/dist/chunk-XRQKLSOT.mjs.map +1 -0
- package/dist/{chunk-7ZCBM5NS.mjs → chunk-YESCCCRF.mjs} +4 -15
- package/dist/chunk-YESCCCRF.mjs.map +1 -0
- package/dist/connection-DxuCLpRc.d.cts +38 -0
- package/dist/connection-DxuCLpRc.d.ts +38 -0
- package/dist/index.mjs +3 -2
- package/dist/index.mjs.map +1 -1
- package/dist/sql/index.cjs +72 -4
- package/dist/sql/index.cjs.map +1 -1
- package/dist/sql/index.d.cts +11 -37
- package/dist/sql/index.d.ts +11 -37
- package/dist/sql/index.mjs +77 -60
- package/dist/sql/index.mjs.map +1 -1
- package/dist/sql/node.cjs +197 -0
- package/dist/sql/node.cjs.map +1 -0
- package/dist/sql/node.d.cts +17 -0
- package/dist/sql/node.d.ts +17 -0
- package/dist/sql/node.mjs +129 -0
- package/dist/sql/node.mjs.map +1 -0
- package/package.json +14 -6
- package/dist/chunk-7ZCBM5NS.mjs.map +0 -1
package/dist/sql/index.d.cts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { S as SqlConnection, D as Database } from '../connection-DxuCLpRc.cjs';
|
|
2
|
+
export { L as LibsqlClient, a as SqlRow, b as SqlStatement, c as SqlValue, l as libsqlDatabase } from '../connection-DxuCLpRc.cjs';
|
|
2
3
|
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';
|
|
4
|
+
import '@libsql/client';
|
|
3
5
|
import '@bitcobblers/wod-wiki-core';
|
|
4
6
|
import '@bitcobblers/wod-wiki-lang';
|
|
5
7
|
|
|
@@ -15,41 +17,6 @@ declare class StorageError extends Error {
|
|
|
15
17
|
constructor(status: number, message: string, code?: string | undefined);
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
/**
|
|
19
|
-
* Connection contracts + a generic libsql adapter. The adapter takes a
|
|
20
|
-
* *structural* client so the browser passes @libsql/client/web and the server
|
|
21
|
-
* passes @libsql/client (node) — this module never imports either, keeping
|
|
22
|
-
* the browser graph free of native drivers.
|
|
23
|
-
*
|
|
24
|
-
* All operations are serialized through one promise chain: the underlying
|
|
25
|
-
* client shares a single connection, so concurrent transactions/reads could
|
|
26
|
-
* otherwise interleave on it. Transactions run on a transaction-owned
|
|
27
|
-
* connection (libsql interactive transaction), so writes inside a transaction
|
|
28
|
-
* commit or roll back atomically and are not visible outside it.
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
type SqlValue = string | number | null;
|
|
32
|
-
type SqlRow = Record<string, unknown>;
|
|
33
|
-
interface SqlStatement {
|
|
34
|
-
sql: string;
|
|
35
|
-
params?: SqlValue[];
|
|
36
|
-
}
|
|
37
|
-
interface SqlConnection {
|
|
38
|
-
query(sql: string, params?: SqlValue[]): Promise<SqlRow[]>;
|
|
39
|
-
exec(sql: string, params?: SqlValue[]): Promise<void>;
|
|
40
|
-
batch?(statements: SqlStatement[]): Promise<SqlRow[][]>;
|
|
41
|
-
}
|
|
42
|
-
interface Database extends SqlConnection {
|
|
43
|
-
readonly dialect: 'sqlite' | 'postgres';
|
|
44
|
-
transaction<T>(fn: (tx: SqlConnection) => Promise<T>): Promise<T>;
|
|
45
|
-
close(): Promise<void>;
|
|
46
|
-
}
|
|
47
|
-
/** Minimal surface used from a libsql client (node or web build) — the real
|
|
48
|
-
* @libsql/client types, type-only so the browser graph stays driver-free. */
|
|
49
|
-
type LibsqlClient = Pick<Client, 'execute' | 'transaction' | 'close'>;
|
|
50
|
-
/** Wrap a libsql client (node or web build) into the shared Database surface. */
|
|
51
|
-
declare function libsqlDatabase(client: LibsqlClient): Database;
|
|
52
|
-
|
|
53
20
|
/**
|
|
54
21
|
* Row codec for the SQL `data` column. Plain JSON.stringify destroys
|
|
55
22
|
* ArrayBuffer values ({}); attachment rows carry raw blobs, so encoding tags
|
|
@@ -116,6 +83,13 @@ declare function rebuildProjections(conn: SqlConnection): Promise<void>;
|
|
|
116
83
|
/** Boot-time derived state: DDL + rebuild only when the guard is incompatible
|
|
117
84
|
* (first run, projection version bump, or an interrupted prior rebuild). */
|
|
118
85
|
declare function initializeDomain(db: Database): Promise<void>;
|
|
86
|
+
/** Read-only readiness check (no DDL, no writes): both real guards — the
|
|
87
|
+
* store schema version row and the domain projection version row — must be
|
|
88
|
+
* current, and every store/projection table must exist. Missing table →
|
|
89
|
+
* db_not_initialized; version drift or corrupt guards → schema_incompatible;
|
|
90
|
+
* auth/network errors propagate untouched. Used by
|
|
91
|
+
* openCliDb(…, { initialize: false }). */
|
|
92
|
+
declare function verifyReadiness(db: Database): Promise<void>;
|
|
119
93
|
/** Clears derived tables after a data wipe (empty is a consistent state). */
|
|
120
94
|
declare function wipeDomain(conn: SqlConnection): Promise<void>;
|
|
121
95
|
declare const MAX_BODY: number;
|
|
@@ -327,4 +301,4 @@ declare function readRawSyncOps(db: Database): Promise<RawSyncOp[]>;
|
|
|
327
301
|
*/
|
|
328
302
|
declare function readLegacyRows(db: Database, table: string): Promise<unknown[]>;
|
|
329
303
|
|
|
330
|
-
export { type ApplySyncBatchOptions, BrowserTursoStorage,
|
|
304
|
+
export { type ApplySyncBatchOptions, BrowserTursoStorage, Database, MAX_BODY, type RawSyncOp, SCHEMA_TABLE, SYNC_ARCHIVE_TABLE, SYNC_OPS_TABLE, SYNC_STATE_TABLE, SqlConnection, SqlStorage, type SqlStorageOptions, StorageError, type StoredSyncOp, type SyncEntry, type SyncMutation, type SyncTargetKind, type TursoSettings, applySyncBatch, clearRows, countRows, decodeRowJson, deleteRows, encodeRowJson, fetchSyncOps, getRow, getRows, handleDomainQuery, initSyncTarget, initializeDomain, initializeStore, listRows, listRowsFromIndexMany, probeSyncTarget, putRow, putRows, readLegacyRows, readRawSyncOps, rebuildProjections, refreshDomain, replaceSyncLog, storeDefinition, validateTursoUrl, verifyReadiness, wipeDomain, wipeRows };
|
package/dist/sql/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { S as SqlConnection, D as Database } from '../connection-DxuCLpRc.js';
|
|
2
|
+
export { L as LibsqlClient, a as SqlRow, b as SqlStatement, c as SqlValue, l as libsqlDatabase } from '../connection-DxuCLpRc.js';
|
|
2
3
|
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';
|
|
4
|
+
import '@libsql/client';
|
|
3
5
|
import '@bitcobblers/wod-wiki-core';
|
|
4
6
|
import '@bitcobblers/wod-wiki-lang';
|
|
5
7
|
|
|
@@ -15,41 +17,6 @@ declare class StorageError extends Error {
|
|
|
15
17
|
constructor(status: number, message: string, code?: string | undefined);
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
/**
|
|
19
|
-
* Connection contracts + a generic libsql adapter. The adapter takes a
|
|
20
|
-
* *structural* client so the browser passes @libsql/client/web and the server
|
|
21
|
-
* passes @libsql/client (node) — this module never imports either, keeping
|
|
22
|
-
* the browser graph free of native drivers.
|
|
23
|
-
*
|
|
24
|
-
* All operations are serialized through one promise chain: the underlying
|
|
25
|
-
* client shares a single connection, so concurrent transactions/reads could
|
|
26
|
-
* otherwise interleave on it. Transactions run on a transaction-owned
|
|
27
|
-
* connection (libsql interactive transaction), so writes inside a transaction
|
|
28
|
-
* commit or roll back atomically and are not visible outside it.
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
type SqlValue = string | number | null;
|
|
32
|
-
type SqlRow = Record<string, unknown>;
|
|
33
|
-
interface SqlStatement {
|
|
34
|
-
sql: string;
|
|
35
|
-
params?: SqlValue[];
|
|
36
|
-
}
|
|
37
|
-
interface SqlConnection {
|
|
38
|
-
query(sql: string, params?: SqlValue[]): Promise<SqlRow[]>;
|
|
39
|
-
exec(sql: string, params?: SqlValue[]): Promise<void>;
|
|
40
|
-
batch?(statements: SqlStatement[]): Promise<SqlRow[][]>;
|
|
41
|
-
}
|
|
42
|
-
interface Database extends SqlConnection {
|
|
43
|
-
readonly dialect: 'sqlite' | 'postgres';
|
|
44
|
-
transaction<T>(fn: (tx: SqlConnection) => Promise<T>): Promise<T>;
|
|
45
|
-
close(): Promise<void>;
|
|
46
|
-
}
|
|
47
|
-
/** Minimal surface used from a libsql client (node or web build) — the real
|
|
48
|
-
* @libsql/client types, type-only so the browser graph stays driver-free. */
|
|
49
|
-
type LibsqlClient = Pick<Client, 'execute' | 'transaction' | 'close'>;
|
|
50
|
-
/** Wrap a libsql client (node or web build) into the shared Database surface. */
|
|
51
|
-
declare function libsqlDatabase(client: LibsqlClient): Database;
|
|
52
|
-
|
|
53
20
|
/**
|
|
54
21
|
* Row codec for the SQL `data` column. Plain JSON.stringify destroys
|
|
55
22
|
* ArrayBuffer values ({}); attachment rows carry raw blobs, so encoding tags
|
|
@@ -116,6 +83,13 @@ declare function rebuildProjections(conn: SqlConnection): Promise<void>;
|
|
|
116
83
|
/** Boot-time derived state: DDL + rebuild only when the guard is incompatible
|
|
117
84
|
* (first run, projection version bump, or an interrupted prior rebuild). */
|
|
118
85
|
declare function initializeDomain(db: Database): Promise<void>;
|
|
86
|
+
/** Read-only readiness check (no DDL, no writes): both real guards — the
|
|
87
|
+
* store schema version row and the domain projection version row — must be
|
|
88
|
+
* current, and every store/projection table must exist. Missing table →
|
|
89
|
+
* db_not_initialized; version drift or corrupt guards → schema_incompatible;
|
|
90
|
+
* auth/network errors propagate untouched. Used by
|
|
91
|
+
* openCliDb(…, { initialize: false }). */
|
|
92
|
+
declare function verifyReadiness(db: Database): Promise<void>;
|
|
119
93
|
/** Clears derived tables after a data wipe (empty is a consistent state). */
|
|
120
94
|
declare function wipeDomain(conn: SqlConnection): Promise<void>;
|
|
121
95
|
declare const MAX_BODY: number;
|
|
@@ -327,4 +301,4 @@ declare function readRawSyncOps(db: Database): Promise<RawSyncOp[]>;
|
|
|
327
301
|
*/
|
|
328
302
|
declare function readLegacyRows(db: Database, table: string): Promise<unknown[]>;
|
|
329
303
|
|
|
330
|
-
export { type ApplySyncBatchOptions, BrowserTursoStorage,
|
|
304
|
+
export { type ApplySyncBatchOptions, BrowserTursoStorage, Database, MAX_BODY, type RawSyncOp, SCHEMA_TABLE, SYNC_ARCHIVE_TABLE, SYNC_OPS_TABLE, SYNC_STATE_TABLE, SqlConnection, SqlStorage, type SqlStorageOptions, StorageError, type StoredSyncOp, type SyncEntry, type SyncMutation, type SyncTargetKind, type TursoSettings, applySyncBatch, clearRows, countRows, decodeRowJson, deleteRows, encodeRowJson, fetchSyncOps, getRow, getRows, handleDomainQuery, initSyncTarget, initializeDomain, initializeStore, listRows, listRowsFromIndexMany, probeSyncTarget, putRow, putRows, readLegacyRows, readRawSyncOps, rebuildProjections, refreshDomain, replaceSyncLog, storeDefinition, validateTursoUrl, verifyReadiness, wipeDomain, wipeRows };
|
package/dist/sql/index.mjs
CHANGED
|
@@ -1,61 +1,11 @@
|
|
|
1
|
-
import { STORE_DEFS,
|
|
2
|
-
|
|
1
|
+
import { STORE_DEFS, extractKeyPart, validateStorageRow, isRange, DB_VERSION, rowsEqual, validateStoredPins, DOMAIN_PROJECTION_VERSION, bufferToOps, stampUserOwned, bufferedGet, overlayRows, rangeFromIDB, isDirty, keyFromValue, bufferSlot, COLUMN_TYPES, keyInRange, compareKeys } from '../chunk-YESCCCRF.mjs';
|
|
2
|
+
import { libsqlDatabase } from '../chunk-6ZTAWTAP.mjs';
|
|
3
|
+
export { libsqlDatabase } from '../chunk-6ZTAWTAP.mjs';
|
|
4
|
+
import { StorageError } from '../chunk-XRQKLSOT.mjs';
|
|
5
|
+
export { StorageError } from '../chunk-XRQKLSOT.mjs';
|
|
3
6
|
import { catalogOfItem, sourceMatches } from '@bitcobblers/wod-wiki-wql';
|
|
4
7
|
import { createClient } from '@libsql/client/web';
|
|
5
8
|
|
|
6
|
-
// src/sql/connection.ts
|
|
7
|
-
function libsqlRows(result) {
|
|
8
|
-
return result.rows;
|
|
9
|
-
}
|
|
10
|
-
function libsqlDatabase(client) {
|
|
11
|
-
let chain = Promise.resolve();
|
|
12
|
-
const serialize = (fn) => {
|
|
13
|
-
const next = chain.then(fn, fn);
|
|
14
|
-
chain = next.then(() => void 0, () => void 0);
|
|
15
|
-
return next;
|
|
16
|
-
};
|
|
17
|
-
return {
|
|
18
|
-
dialect: "sqlite",
|
|
19
|
-
query: (sql, params = []) => serialize(() => client.execute({ sql, args: params }).then(libsqlRows)),
|
|
20
|
-
exec: async (sql, params = []) => {
|
|
21
|
-
await serialize(() => client.execute({ sql, args: params }));
|
|
22
|
-
},
|
|
23
|
-
transaction(fn) {
|
|
24
|
-
return serialize(async () => {
|
|
25
|
-
const tx = await client.transaction("write");
|
|
26
|
-
try {
|
|
27
|
-
const txConn = {
|
|
28
|
-
query: (sql, params = []) => tx.execute({ sql, args: params }).then(libsqlRows),
|
|
29
|
-
exec: async (sql, params = []) => {
|
|
30
|
-
await tx.execute({ sql, args: params });
|
|
31
|
-
},
|
|
32
|
-
batch: async (statements) => (await tx.batch(statements.map(({ sql, params = [] }) => ({ sql, args: params })))).map(libsqlRows)
|
|
33
|
-
};
|
|
34
|
-
const result = await fn(txConn);
|
|
35
|
-
await tx.commit();
|
|
36
|
-
return result;
|
|
37
|
-
} catch (err) {
|
|
38
|
-
try {
|
|
39
|
-
await tx.rollback();
|
|
40
|
-
} catch {
|
|
41
|
-
}
|
|
42
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
43
|
-
for (const code of ["revision_conflict", "transaction_conflict", "invalid_session_pin"]) {
|
|
44
|
-
if (message.includes(code)) throw new StorageError(409, message, code);
|
|
45
|
-
}
|
|
46
|
-
throw err;
|
|
47
|
-
} finally {
|
|
48
|
-
tx.close();
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
},
|
|
52
|
-
close: async () => {
|
|
53
|
-
await chain;
|
|
54
|
-
client.close();
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
9
|
// src/sql/codec.ts
|
|
60
10
|
var TAG = "$binary";
|
|
61
11
|
var LEN = "$bytes";
|
|
@@ -581,7 +531,7 @@ async function ensureStoreTables(conn, dialect, def) {
|
|
|
581
531
|
BEGIN SELECT RAISE(ABORT, 'invalid_session_pin: Session pin is immutable'); END`);
|
|
582
532
|
}
|
|
583
533
|
if (dialect === "postgres" && ["notes", "block_revisions", "sessions"].includes(def.name)) {
|
|
584
|
-
const condition = def.name === "block_revisions" ? `EXISTS (SELECT 1 FROM "block_revisions"
|
|
534
|
+
const condition = def.name === "block_revisions" ? `EXISTS (SELECT 1 FROM "block_revisions" saved WHERE saved."k0" = NEW."k0" AND saved."k1" = NEW."k1" AND saved."k2" = NEW."k2" AND saved."data" <> NEW."data")` : def.name === "notes" ? `(NEW."data"::jsonb->>'sourceRevision')::bigint < (OLD."data"::jsonb->>'sourceRevision')::bigint OR ((NEW."data"::jsonb->'rawContent' IS DISTINCT FROM OLD."data"::jsonb->'rawContent' OR NEW."data"::jsonb->'blocks' IS DISTINCT FROM OLD."data"::jsonb->'blocks') AND (NEW."data"::jsonb->>'sourceRevision')::bigint <= (OLD."data"::jsonb->>'sourceRevision')::bigint)` : `NEW."data"::jsonb->'noteId' IS DISTINCT FROM OLD."data"::jsonb->'noteId' OR NEW."data"::jsonb->'blockId' IS DISTINCT FROM OLD."data"::jsonb->'blockId' OR NEW."data"::jsonb->'blockVersion' IS DISTINCT FROM OLD."data"::jsonb->'blockVersion'`;
|
|
585
535
|
const code = def.name === "block_revisions" ? "revision_conflict" : def.name === "notes" ? "transaction_conflict" : "invalid_session_pin";
|
|
586
536
|
const guard = `${def.name}_guard`;
|
|
587
537
|
await conn.exec(`CREATE OR REPLACE FUNCTION "${guard}"() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN IF ${condition} THEN RAISE EXCEPTION '${code}'; END IF; RETURN NEW; END; $$`);
|
|
@@ -681,7 +631,7 @@ function ensureDdl(db) {
|
|
|
681
631
|
}
|
|
682
632
|
var DOMAIN_NOTE_COLS = ["note_id", "note_type", "catalog", "source_id", "source_path", "title", "title_search", "created_at", "date", "text_search", "journal", "payload"];
|
|
683
633
|
var QUERY_BLOCK_COLS = ["occurrence_id", "source_note_id", "parent_note_id", "content_id", "section_key", "ordinal", "data_type", "source_id", "source_path", "catalog", "effective_date", "created_at", "note_title", "normalized_text", "journal", "payload"];
|
|
684
|
-
var conflictUpdate = (cols, keys) => `ON CONFLICT (${keys.map((k) => `"${k}"`).join(", ")}) DO UPDATE SET ` + cols.filter((c) => !keys.includes(c)).map((c) => `"${c}" = excluded."${c}"`).join(",") + ` WHERE ` + cols.filter((col) => !keys.includes(col)).map((col) => `"${col}" IS DISTINCT FROM excluded."${col}"`).join(" OR ");
|
|
634
|
+
var conflictUpdate = (table, cols, keys) => `ON CONFLICT (${keys.map((k) => `"${k}"`).join(", ")}) DO UPDATE SET ` + cols.filter((c) => !keys.includes(c)).map((c) => `"${c}" = excluded."${c}"`).join(",") + ` WHERE ` + cols.filter((col) => !keys.includes(col)).map((col) => `"${table}"."${col}" IS DISTINCT FROM excluded."${col}"`).join(" OR ");
|
|
685
635
|
function domainNoteRow(note) {
|
|
686
636
|
const id = text(note.id);
|
|
687
637
|
if (!id) return void 0;
|
|
@@ -703,7 +653,7 @@ function domainNoteRow(note) {
|
|
|
703
653
|
}
|
|
704
654
|
async function upsertDomainNotes(conn, notes) {
|
|
705
655
|
const rows = notes.map(domainNoteRow).filter((r) => r !== void 0);
|
|
706
|
-
await batchInsert(conn, "domain_note", [...DOMAIN_NOTE_COLS], rows, conflictUpdate(DOMAIN_NOTE_COLS, ["note_id"]));
|
|
656
|
+
await batchInsert(conn, "domain_note", [...DOMAIN_NOTE_COLS], rows, conflictUpdate("domain_note", DOMAIN_NOTE_COLS, ["note_id"]));
|
|
707
657
|
}
|
|
708
658
|
function queryBlockRow(block, parent) {
|
|
709
659
|
const id = text(block.id);
|
|
@@ -732,7 +682,7 @@ function queryBlockRow(block, parent) {
|
|
|
732
682
|
}
|
|
733
683
|
async function upsertQueryBlocks(conn, blocks) {
|
|
734
684
|
const rows = blocks.map(([b, p]) => queryBlockRow(b, p)).filter((r) => r !== void 0);
|
|
735
|
-
await batchInsert(conn, "query_block", [...QUERY_BLOCK_COLS], rows, conflictUpdate(QUERY_BLOCK_COLS, ["occurrence_id"]));
|
|
685
|
+
await batchInsert(conn, "query_block", [...QUERY_BLOCK_COLS], rows, conflictUpdate("query_block", QUERY_BLOCK_COLS, ["occurrence_id"]));
|
|
736
686
|
}
|
|
737
687
|
function indexNoteIdentities(notes) {
|
|
738
688
|
const byNoteId = /* @__PURE__ */ new Map();
|
|
@@ -932,6 +882,73 @@ async function initializeDomain(db) {
|
|
|
932
882
|
await rebuildProjections(tx);
|
|
933
883
|
});
|
|
934
884
|
}
|
|
885
|
+
async function verifyReadiness(db) {
|
|
886
|
+
const isMissingRelation = (error) => {
|
|
887
|
+
if (typeof error !== "object" || error === null) return false;
|
|
888
|
+
if ("errno" in error && error.errno === "42P01") return true;
|
|
889
|
+
if ("code" in error && error.code === "42P01") return true;
|
|
890
|
+
return "code" in error && error.code === "SQLITE_ERROR" && /no such table/i.test(error instanceof Error ? error.message : String(error));
|
|
891
|
+
};
|
|
892
|
+
const readGuard = async (key) => {
|
|
893
|
+
const rows = await db.query(`SELECT "value" FROM "${SCHEMA_TABLE}" WHERE "key" = ?`, [key]);
|
|
894
|
+
if (!rows.length || typeof rows[0].value !== "string") return void 0;
|
|
895
|
+
try {
|
|
896
|
+
return JSON.parse(rows[0].value);
|
|
897
|
+
} catch {
|
|
898
|
+
throw new StorageError(500, `database guard "${key}" is corrupt; re-run initialization`, "schema_incompatible");
|
|
899
|
+
}
|
|
900
|
+
};
|
|
901
|
+
let schemaGuard;
|
|
902
|
+
let projectionGuard;
|
|
903
|
+
try {
|
|
904
|
+
schemaGuard = await readGuard("schema");
|
|
905
|
+
projectionGuard = await readGuard(PROJECTION_GUARD_KEY);
|
|
906
|
+
} catch (error) {
|
|
907
|
+
if (isMissingRelation(error)) {
|
|
908
|
+
throw new StorageError(500, "database is not initialized (schema guard table missing)", "db_not_initialized");
|
|
909
|
+
}
|
|
910
|
+
throw error;
|
|
911
|
+
}
|
|
912
|
+
const schemaVersion = schemaGuard?.version;
|
|
913
|
+
const projectionVersion = projectionGuard?.version;
|
|
914
|
+
if (typeof schemaVersion !== "number") {
|
|
915
|
+
throw new StorageError(500, "database is not initialized (no schema guard row)", "db_not_initialized");
|
|
916
|
+
}
|
|
917
|
+
if (typeof projectionVersion !== "number") {
|
|
918
|
+
throw new StorageError(500, "database is not initialized (projections never built)", "db_not_initialized");
|
|
919
|
+
}
|
|
920
|
+
if (schemaVersion > DB_VERSION) {
|
|
921
|
+
throw new StorageError(
|
|
922
|
+
500,
|
|
923
|
+
`database schema v${schemaVersion} is newer than this server supports (v${DB_VERSION}); refusing to downgrade`,
|
|
924
|
+
"schema_incompatible"
|
|
925
|
+
);
|
|
926
|
+
}
|
|
927
|
+
if (schemaVersion !== DB_VERSION) {
|
|
928
|
+
throw new StorageError(
|
|
929
|
+
500,
|
|
930
|
+
`database schema v${schemaVersion} is incompatible with v${DB_VERSION}; re-run initialization`,
|
|
931
|
+
"schema_incompatible"
|
|
932
|
+
);
|
|
933
|
+
}
|
|
934
|
+
if (projectionVersion !== DOMAIN_PROJECTION_VERSION) {
|
|
935
|
+
throw new StorageError(
|
|
936
|
+
500,
|
|
937
|
+
`database projections v${projectionVersion} are incompatible with v${DOMAIN_PROJECTION_VERSION}; re-run initialization`,
|
|
938
|
+
"schema_incompatible"
|
|
939
|
+
);
|
|
940
|
+
}
|
|
941
|
+
for (const table of [...STORE_DEFS.map((def) => def.name), ...TABLES]) {
|
|
942
|
+
try {
|
|
943
|
+
await db.query(`SELECT * FROM "${table}" LIMIT 0`);
|
|
944
|
+
} catch (error) {
|
|
945
|
+
if (isMissingRelation(error)) {
|
|
946
|
+
throw new StorageError(500, `database is not initialized (missing table: ${table})`, "db_not_initialized");
|
|
947
|
+
}
|
|
948
|
+
throw error;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
}
|
|
935
952
|
async function wipeDomain(conn) {
|
|
936
953
|
for (const t of TABLES) await conn.exec(`DELETE FROM "${t}"`);
|
|
937
954
|
}
|
|
@@ -1857,6 +1874,6 @@ async function readLegacyRows(db, table) {
|
|
|
1857
1874
|
return rows.map((row) => decodeRowJson(String(row.data), BINARY_FIELD2[table]));
|
|
1858
1875
|
}
|
|
1859
1876
|
|
|
1860
|
-
export { BrowserTursoStorage, MAX_BODY, SCHEMA_TABLE, SYNC_ARCHIVE_TABLE, SYNC_OPS_TABLE, SYNC_STATE_TABLE, SqlStorage, applySyncBatch, clearRows, countRows, decodeRowJson, deleteRows, encodeRowJson, fetchSyncOps, getRow, getRows, handleDomainQuery, initSyncTarget, initializeDomain, initializeStore,
|
|
1877
|
+
export { BrowserTursoStorage, MAX_BODY, SCHEMA_TABLE, SYNC_ARCHIVE_TABLE, SYNC_OPS_TABLE, SYNC_STATE_TABLE, SqlStorage, applySyncBatch, clearRows, countRows, decodeRowJson, deleteRows, encodeRowJson, fetchSyncOps, getRow, getRows, handleDomainQuery, initSyncTarget, initializeDomain, initializeStore, listRows, listRowsFromIndexMany, probeSyncTarget, putRow, putRows, readLegacyRows, readRawSyncOps, rebuildProjections, refreshDomain, replaceSyncLog, storeDefinition, validateTursoUrl, verifyReadiness, wipeDomain, wipeRows };
|
|
1861
1878
|
//# sourceMappingURL=index.mjs.map
|
|
1862
1879
|
//# sourceMappingURL=index.mjs.map
|