@optimystic/db-p2p-storage-ns 0.24.2 → 0.25.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 +6 -5
- package/dist/src/db.d.ts +6 -3
- package/dist/src/db.d.ts.map +1 -1
- package/dist/src/db.js +12 -2
- package/dist/src/db.js.map +1 -1
- package/dist/src/ns-opener.js +1 -1
- package/dist/src/ns-opener.js.map +1 -1
- package/dist/src/sqlite-storage.d.ts +9 -5
- package/dist/src/sqlite-storage.d.ts.map +1 -1
- package/dist/src/sqlite-storage.js +23 -5
- package/dist/src/sqlite-storage.js.map +1 -1
- package/package.json +3 -3
- package/src/db.ts +12 -2
- package/src/ns-opener.ts +1 -1
- package/src/sqlite-storage.ts +243 -217
package/README.md
CHANGED
|
@@ -5,10 +5,10 @@ Android, native — not React Native). Provides:
|
|
|
5
5
|
|
|
6
6
|
- **`SqliteRawStorage`** — the `IRawStorage` a NativeScript node uses to
|
|
7
7
|
persist block metadata, revisions, pending transactions, committed
|
|
8
|
-
transactions, and materialized blocks across app restarts.
|
|
9
|
-
shell over the shared `KvRawStorage` kernel driven by
|
|
10
|
-
the kernel owns all JSON serialization, the driver
|
|
11
|
-
stores onto the
|
|
8
|
+
transactions, commit proofs, and materialized blocks across app restarts.
|
|
9
|
+
It is a thin shell over the shared `KvRawStorage` kernel driven by
|
|
10
|
+
`SqliteStoreDriver`: the kernel owns all JSON serialization, the driver
|
|
11
|
+
maps the six logical stores onto the six SQLite tables.
|
|
12
12
|
- **`SqliteKVStore`** — implements `IKVStore` for the persistent transaction
|
|
13
13
|
state used to recover crashed two-phase commits.
|
|
14
14
|
- **`loadOrCreateNSPeerKey`** — generates an Ed25519 libp2p private key on
|
|
@@ -75,7 +75,7 @@ the mutex to preserve read concurrency.
|
|
|
75
75
|
## Persistence model
|
|
76
76
|
|
|
77
77
|
The package opens a single SQLite database (`optimystic.sqlite` by default
|
|
78
|
-
in the NativeScript app's documents directory) with
|
|
78
|
+
in the NativeScript app's documents directory) with seven tables. The six
|
|
79
79
|
block-storage tables keep their original columns and keys, but their value
|
|
80
80
|
columns are now **BLOB**: `SqliteStoreDriver` binds/reads the kernel's raw
|
|
81
81
|
`Uint8Array` bytes and the shared `KvRawStorage` kernel owns the JSON/UTF-8
|
|
@@ -90,6 +90,7 @@ into; keys stay TEXT/INTEGER.
|
|
|
90
90
|
| `revisions` | `(block_id, rev)` | `BLOB` (`action_id` col) | `ActionId` |
|
|
91
91
|
| `pending` | `(block_id, action_id)` | `BLOB` | `Transform` |
|
|
92
92
|
| `transactions` | `(block_id, action_id)` | `BLOB` | `Transform` |
|
|
93
|
+
| `proofs` | `(block_id, rev)` | `BLOB` | `BlockCommitProof` |
|
|
93
94
|
| `materialized` | `(block_id, action_id)` | `BLOB` | `IBlock` |
|
|
94
95
|
| `kv` | `key` | `s_val` (TEXT) or `b_val` (BLOB) | — (not kernel-backed) |
|
|
95
96
|
|
package/dist/src/db.d.ts
CHANGED
|
@@ -81,7 +81,7 @@ export declare const DEFAULT_DB_VERSION = 1;
|
|
|
81
81
|
/**
|
|
82
82
|
* Schema for the NativeScript storage backend.
|
|
83
83
|
*
|
|
84
|
-
* Mirrors the IndexedDB object stores 1:1. The
|
|
84
|
+
* Mirrors the IndexedDB object stores 1:1. The six block-storage stores keep
|
|
85
85
|
* their original columns and keys, but their value columns are now BLOB: the
|
|
86
86
|
* shared `KvRawStorage` kernel (driven by `SqliteStoreDriver`) owns all JSON /
|
|
87
87
|
* UTF-8 (de)serialization, so the driver only ever binds/reads the kernel's raw
|
|
@@ -93,6 +93,9 @@ export declare const DEFAULT_DB_VERSION = 1;
|
|
|
93
93
|
* holds the kernel's encoded `ActionId` bytes (BLOB).
|
|
94
94
|
* - `pending` → uncommitted transform bytes keyed by `(block_id, action_id)`.
|
|
95
95
|
* - `transactions` → committed transform bytes keyed by `(block_id, action_id)`.
|
|
96
|
+
* - `proofs` → `BlockCommitProof` bytes keyed by `(block_id, rev)` — the same key
|
|
97
|
+
* shape as `revisions`, deliberately NOT the action keyspace (an action id is
|
|
98
|
+
* caller-chosen, so no reserved id could be relied on).
|
|
96
99
|
* - `materialized` → materialized block bytes keyed by `(block_id, action_id)`.
|
|
97
100
|
* - `kv` → generic string keyspace shared by `IKVStore` (`s_val`) and the
|
|
98
101
|
* identity helper (`b_val`). NOT kernel-backed; unchanged. The two columns
|
|
@@ -105,9 +108,9 @@ export declare const DEFAULT_DB_VERSION = 1;
|
|
|
105
108
|
* throwing). There is no migration. Safe today because this backend is
|
|
106
109
|
* NativeScript-only with no shipped production data; if a build ever ships to
|
|
107
110
|
* devices that later upgrade, add a `user_version` bump that drops+recreates
|
|
108
|
-
* these
|
|
111
|
+
* these six tables (or a real migration) before assuming BLOB rows.
|
|
109
112
|
*/
|
|
110
|
-
export declare const SCHEMA_SQL = "\nCREATE TABLE IF NOT EXISTS metadata (\n\tblock_id TEXT PRIMARY KEY,\n\tvalue BLOB NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS revisions (\n\tblock_id TEXT NOT NULL,\n\trev INTEGER NOT NULL,\n\taction_id BLOB NOT NULL,\n\tPRIMARY KEY (block_id, rev)\n);\n\nCREATE TABLE IF NOT EXISTS pending (\n\tblock_id TEXT NOT NULL,\n\taction_id TEXT NOT NULL,\n\tvalue BLOB NOT NULL,\n\tPRIMARY KEY (block_id, action_id)\n);\n\nCREATE TABLE IF NOT EXISTS transactions (\n\tblock_id TEXT NOT NULL,\n\taction_id TEXT NOT NULL,\n\tvalue BLOB NOT NULL,\n\tPRIMARY KEY (block_id, action_id)\n);\n\nCREATE TABLE IF NOT EXISTS materialized (\n\tblock_id TEXT NOT NULL,\n\taction_id TEXT NOT NULL,\n\tvalue BLOB NOT NULL,\n\tPRIMARY KEY (block_id, action_id)\n);\n\nCREATE TABLE IF NOT EXISTS kv (\n\tkey TEXT PRIMARY KEY,\n\ts_val TEXT,\n\tb_val BLOB\n);\n";
|
|
113
|
+
export declare const SCHEMA_SQL = "\nCREATE TABLE IF NOT EXISTS metadata (\n\tblock_id TEXT PRIMARY KEY,\n\tvalue BLOB NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS revisions (\n\tblock_id TEXT NOT NULL,\n\trev INTEGER NOT NULL,\n\taction_id BLOB NOT NULL,\n\tPRIMARY KEY (block_id, rev)\n);\n\nCREATE TABLE IF NOT EXISTS pending (\n\tblock_id TEXT NOT NULL,\n\taction_id TEXT NOT NULL,\n\tvalue BLOB NOT NULL,\n\tPRIMARY KEY (block_id, action_id)\n);\n\nCREATE TABLE IF NOT EXISTS transactions (\n\tblock_id TEXT NOT NULL,\n\taction_id TEXT NOT NULL,\n\tvalue BLOB NOT NULL,\n\tPRIMARY KEY (block_id, action_id)\n);\n\nCREATE TABLE IF NOT EXISTS proofs (\n\tblock_id TEXT NOT NULL,\n\trev INTEGER NOT NULL,\n\tvalue BLOB NOT NULL,\n\tPRIMARY KEY (block_id, rev)\n);\n\nCREATE TABLE IF NOT EXISTS materialized (\n\tblock_id TEXT NOT NULL,\n\taction_id TEXT NOT NULL,\n\tvalue BLOB NOT NULL,\n\tPRIMARY KEY (block_id, action_id)\n);\n\nCREATE TABLE IF NOT EXISTS kv (\n\tkey TEXT PRIMARY KEY,\n\ts_val TEXT,\n\tb_val BLOB\n);\n";
|
|
111
114
|
/**
|
|
112
115
|
* Apply pragmas, run the schema DDL, and stamp `user_version` so future
|
|
113
116
|
* migrations can branch on it. Idempotent — safe to call on every open.
|
package/dist/src/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,kFAAkF;AAClF,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;AAE9D,oEAAoE;AACpE,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC/B,0EAA0E;IAC1E,GAAG,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,gEAAgE;IAChE,GAAG,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IAC9D,oFAAoF;IACpF,GAAG,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;CACpD;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,iBAAiB;IACjC,6EAA6E;IAC7E,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAAC;CACtC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,QAAQ;IACxB,yFAAyF;IACzF,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,2FAA2F;IAC3F,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAAC;IACtC;;;;;;;;;;OAUG;IACH,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACtE,qCAAqC;IACrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,eAAO,MAAM,eAAe,sBAAsB,CAAC;AACnD,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,kFAAkF;AAClF,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;AAE9D,oEAAoE;AACpE,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC/B,0EAA0E;IAC1E,GAAG,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,gEAAgE;IAChE,GAAG,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IAC9D,oFAAoF;IACpF,GAAG,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;CACpD;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,iBAAiB;IACjC,6EAA6E;IAC7E,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAAC;CACtC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,QAAQ;IACxB,yFAAyF;IACzF,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,2FAA2F;IAC3F,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAAC;IACtC;;;;;;;;;;OAUG;IACH,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACtE,qCAAqC;IACrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,eAAO,MAAM,eAAe,sBAAsB,CAAC;AACnD,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,UAAU,mhCA8CtB,CAAC;AAQF;;;GAGG;AACH,wBAAsB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,GAAE,MAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAUnG;AAED;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC"}
|
package/dist/src/db.js
CHANGED
|
@@ -15,7 +15,7 @@ export const DEFAULT_DB_VERSION = 1;
|
|
|
15
15
|
/**
|
|
16
16
|
* Schema for the NativeScript storage backend.
|
|
17
17
|
*
|
|
18
|
-
* Mirrors the IndexedDB object stores 1:1. The
|
|
18
|
+
* Mirrors the IndexedDB object stores 1:1. The six block-storage stores keep
|
|
19
19
|
* their original columns and keys, but their value columns are now BLOB: the
|
|
20
20
|
* shared `KvRawStorage` kernel (driven by `SqliteStoreDriver`) owns all JSON /
|
|
21
21
|
* UTF-8 (de)serialization, so the driver only ever binds/reads the kernel's raw
|
|
@@ -27,6 +27,9 @@ export const DEFAULT_DB_VERSION = 1;
|
|
|
27
27
|
* holds the kernel's encoded `ActionId` bytes (BLOB).
|
|
28
28
|
* - `pending` → uncommitted transform bytes keyed by `(block_id, action_id)`.
|
|
29
29
|
* - `transactions` → committed transform bytes keyed by `(block_id, action_id)`.
|
|
30
|
+
* - `proofs` → `BlockCommitProof` bytes keyed by `(block_id, rev)` — the same key
|
|
31
|
+
* shape as `revisions`, deliberately NOT the action keyspace (an action id is
|
|
32
|
+
* caller-chosen, so no reserved id could be relied on).
|
|
30
33
|
* - `materialized` → materialized block bytes keyed by `(block_id, action_id)`.
|
|
31
34
|
* - `kv` → generic string keyspace shared by `IKVStore` (`s_val`) and the
|
|
32
35
|
* identity helper (`b_val`). NOT kernel-backed; unchanged. The two columns
|
|
@@ -39,7 +42,7 @@ export const DEFAULT_DB_VERSION = 1;
|
|
|
39
42
|
* throwing). There is no migration. Safe today because this backend is
|
|
40
43
|
* NativeScript-only with no shipped production data; if a build ever ships to
|
|
41
44
|
* devices that later upgrade, add a `user_version` bump that drops+recreates
|
|
42
|
-
* these
|
|
45
|
+
* these six tables (or a real migration) before assuming BLOB rows.
|
|
43
46
|
*/
|
|
44
47
|
export const SCHEMA_SQL = `
|
|
45
48
|
CREATE TABLE IF NOT EXISTS metadata (
|
|
@@ -68,6 +71,13 @@ CREATE TABLE IF NOT EXISTS transactions (
|
|
|
68
71
|
PRIMARY KEY (block_id, action_id)
|
|
69
72
|
);
|
|
70
73
|
|
|
74
|
+
CREATE TABLE IF NOT EXISTS proofs (
|
|
75
|
+
block_id TEXT NOT NULL,
|
|
76
|
+
rev INTEGER NOT NULL,
|
|
77
|
+
value BLOB NOT NULL,
|
|
78
|
+
PRIMARY KEY (block_id, rev)
|
|
79
|
+
);
|
|
80
|
+
|
|
71
81
|
CREATE TABLE IF NOT EXISTS materialized (
|
|
72
82
|
block_id TEXT NOT NULL,
|
|
73
83
|
action_id TEXT NOT NULL,
|
package/dist/src/db.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAyEH,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AACnD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAEpC
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAyEH,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AACnD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8CzB,CAAC;AAEF,+EAA+E;AAC/E,MAAM,WAAW,GAAG;;;CAGnB,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,EAAY,EAAE,UAAkB,kBAAkB;IACnF,0EAA0E;IAC1E,6EAA6E;IAC7E,4EAA4E;IAC5E,4EAA4E;IAC5E,iFAAiF;IACjF,MAAM,EAAE,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,GAAG,EAAE,CAAC;IACpD,MAAM,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC3B,MAAM,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1B,MAAM,EAAE,CAAC,IAAI,CAAC,yBAAyB,OAAO,EAAE,CAAC,CAAC;AACnD,CAAC"}
|
package/dist/src/ns-opener.js
CHANGED
|
@@ -120,7 +120,7 @@ class NSPluginStatement {
|
|
|
120
120
|
// concurrency. A read issued while a write transaction is open on this same
|
|
121
121
|
// connection observes that transaction's UNCOMMITTED rows (read-your-connection
|
|
122
122
|
// semantics). Fine today: the only transaction writer is same-block promote
|
|
123
|
-
// under the
|
|
123
|
+
// under the block's write latch, and cross-block reads are independent. If a future
|
|
124
124
|
// caller reads a block on this connection while another op's transaction on the
|
|
125
125
|
// same rows is mid-flight, it may see uncommitted state — serialize reads too if
|
|
126
126
|
// that ever matters.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ns-opener.js","sourceRoot":"","sources":["../../src/ns-opener.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ns-opener.js","sourceRoot":"","sources":["../../src/ns-opener.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { ActionId, BlockId } from '@optimystic/db-core';
|
|
2
|
-
import { KvRawStorage, type RawStoreDriver } from '@optimystic/db-p2p';
|
|
2
|
+
import { KvRawStorage, type RawStoreDriver, type StoreIdentity } from '@optimystic/db-p2p';
|
|
3
3
|
import type { SqliteDb } from './db.js';
|
|
4
4
|
/**
|
|
5
|
-
* SQLite {@link RawStoreDriver}: the
|
|
6
|
-
* the
|
|
7
|
-
* `materialized`) with their original columns and keys.
|
|
8
|
-
* not a storage-format change at the SQL level.
|
|
5
|
+
* SQLite {@link RawStoreDriver}: the six logical block-storage stores mapped to
|
|
6
|
+
* the six relational tables (`metadata`, `revisions`, `pending`, `transactions`,
|
|
7
|
+
* `proofs`, `materialized`) with their original columns and keys.
|
|
9
8
|
*
|
|
10
9
|
* `KvRawStorage` now owns all JSON serialization, so this driver only ever
|
|
11
10
|
* reads/writes `Uint8Array` values: the value columns are BLOB and SQLite binds
|
|
@@ -22,7 +21,9 @@ import type { SqliteDb } from './db.js';
|
|
|
22
21
|
export declare class SqliteStoreDriver implements RawStoreDriver {
|
|
23
22
|
private readonly db;
|
|
24
23
|
private readonly stmts;
|
|
24
|
+
private readonly identity;
|
|
25
25
|
constructor(db: SqliteDb);
|
|
26
|
+
storeIdentity(): StoreIdentity;
|
|
26
27
|
getMetadata(blockId: BlockId): Promise<Uint8Array | undefined>;
|
|
27
28
|
putMetadata(blockId: BlockId, value: Uint8Array): Promise<void>;
|
|
28
29
|
getRevision(blockId: BlockId, rev: number): Promise<Uint8Array | undefined>;
|
|
@@ -34,6 +35,8 @@ export declare class SqliteStoreDriver implements RawStoreDriver {
|
|
|
34
35
|
listPendingActionIds(blockId: BlockId): AsyncIterable<ActionId>;
|
|
35
36
|
getTransaction(blockId: BlockId, actionId: ActionId): Promise<Uint8Array | undefined>;
|
|
36
37
|
putTransaction(blockId: BlockId, actionId: ActionId, value: Uint8Array): Promise<void>;
|
|
38
|
+
getProof(blockId: BlockId, rev: number): Promise<Uint8Array | undefined>;
|
|
39
|
+
putProof(blockId: BlockId, rev: number, value: Uint8Array): Promise<void>;
|
|
37
40
|
getMaterialized(blockId: BlockId, actionId: ActionId): Promise<Uint8Array | undefined>;
|
|
38
41
|
putMaterialized(blockId: BlockId, actionId: ActionId, value: Uint8Array): Promise<void>;
|
|
39
42
|
deleteMaterialized(blockId: BlockId, actionId: ActionId): Promise<void>;
|
|
@@ -56,6 +59,7 @@ export declare class SqliteStoreDriver implements RawStoreDriver {
|
|
|
56
59
|
export declare class SqliteRawStorage extends KvRawStorage {
|
|
57
60
|
listBlockIds: () => AsyncIterable<BlockId>;
|
|
58
61
|
getApproximateBytesUsed: () => Promise<number>;
|
|
62
|
+
getStoreIdentity: () => StoreIdentity;
|
|
59
63
|
constructor(db: SqliteDb);
|
|
60
64
|
}
|
|
61
65
|
//# sourceMappingURL=sqlite-storage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-storage.d.ts","sourceRoot":"","sources":["../../src/sqlite-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"sqlite-storage.d.ts","sourceRoot":"","sources":["../../src/sqlite-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { KvRawStorage } from '@optimystic/db-p2p';
|
|
1
|
+
import { KvRawStorage, identityForHandle } from '@optimystic/db-p2p';
|
|
2
2
|
import { createLogger } from './logger.js';
|
|
3
3
|
const log = createLogger('storage:sqlite');
|
|
4
4
|
/**
|
|
5
|
-
* SQLite {@link RawStoreDriver}: the
|
|
6
|
-
* the
|
|
7
|
-
* `materialized`) with their original columns and keys.
|
|
8
|
-
* not a storage-format change at the SQL level.
|
|
5
|
+
* SQLite {@link RawStoreDriver}: the six logical block-storage stores mapped to
|
|
6
|
+
* the six relational tables (`metadata`, `revisions`, `pending`, `transactions`,
|
|
7
|
+
* `proofs`, `materialized`) with their original columns and keys.
|
|
9
8
|
*
|
|
10
9
|
* `KvRawStorage` now owns all JSON serialization, so this driver only ever
|
|
11
10
|
* reads/writes `Uint8Array` values: the value columns are BLOB and SQLite binds
|
|
@@ -22,8 +21,14 @@ const log = createLogger('storage:sqlite');
|
|
|
22
21
|
export class SqliteStoreDriver {
|
|
23
22
|
db;
|
|
24
23
|
stmts;
|
|
24
|
+
// NOTE: identity is the HANDLE object, so two handles opened over the same SQLite FILE read
|
|
25
|
+
// as two identities. Resolving that would mean naming the underlying database file, which
|
|
26
|
+
// `SqliteDb` does not expose. The package opener (`ns-opener.ts`) hands out one handle per
|
|
27
|
+
// file in practice, so this is the reachable case, not the complete one.
|
|
28
|
+
identity;
|
|
25
29
|
constructor(db) {
|
|
26
30
|
this.db = db;
|
|
31
|
+
this.identity = identityForHandle('sqlite-handle', db);
|
|
27
32
|
this.stmts = {
|
|
28
33
|
getMetadata: db.prepare('SELECT value FROM metadata WHERE block_id = ?'),
|
|
29
34
|
saveMetadata: db.prepare('INSERT OR REPLACE INTO metadata (block_id, value) VALUES (?, ?)'),
|
|
@@ -42,6 +47,8 @@ export class SqliteStoreDriver {
|
|
|
42
47
|
listBlockIds: db.prepare('SELECT block_id FROM metadata'),
|
|
43
48
|
getTransaction: db.prepare('SELECT value FROM transactions WHERE block_id = ? AND action_id = ?'),
|
|
44
49
|
saveTransaction: db.prepare('INSERT OR REPLACE INTO transactions (block_id, action_id, value) VALUES (?, ?, ?)'),
|
|
50
|
+
getProof: db.prepare('SELECT value FROM proofs WHERE block_id = ? AND rev = ?'),
|
|
51
|
+
saveProof: db.prepare('INSERT OR REPLACE INTO proofs (block_id, rev, value) VALUES (?, ?, ?)'),
|
|
45
52
|
getMaterialized: db.prepare('SELECT value FROM materialized WHERE block_id = ? AND action_id = ?'),
|
|
46
53
|
saveMaterialized: db.prepare('INSERT OR REPLACE INTO materialized (block_id, action_id, value) VALUES (?, ?, ?)'),
|
|
47
54
|
deleteMaterialized: db.prepare('DELETE FROM materialized WHERE block_id = ? AND action_id = ?'),
|
|
@@ -49,6 +56,9 @@ export class SqliteStoreDriver {
|
|
|
49
56
|
pageSize: db.prepare('PRAGMA page_size'),
|
|
50
57
|
};
|
|
51
58
|
}
|
|
59
|
+
storeIdentity() {
|
|
60
|
+
return this.identity;
|
|
61
|
+
}
|
|
52
62
|
// --- metadata ---
|
|
53
63
|
async getMetadata(blockId) {
|
|
54
64
|
const row = await this.stmts.getMetadata.get(blockId);
|
|
@@ -100,6 +110,14 @@ export class SqliteStoreDriver {
|
|
|
100
110
|
async putTransaction(blockId, actionId, value) {
|
|
101
111
|
await this.stmts.saveTransaction.run(blockId, actionId, value);
|
|
102
112
|
}
|
|
113
|
+
// --- proofs (keyed (block_id, rev) like revisions; no delete — see RawStoreDriver.getProof) ---
|
|
114
|
+
async getProof(blockId, rev) {
|
|
115
|
+
const row = await this.stmts.getProof.get(blockId, rev);
|
|
116
|
+
return row ? row.value : undefined;
|
|
117
|
+
}
|
|
118
|
+
async putProof(blockId, rev, value) {
|
|
119
|
+
await this.stmts.saveProof.run(blockId, rev, value);
|
|
120
|
+
}
|
|
103
121
|
// --- materialized ---
|
|
104
122
|
async getMaterialized(blockId, actionId) {
|
|
105
123
|
const row = await this.stmts.getMaterialized.get(blockId, actionId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-storage.js","sourceRoot":"","sources":["../../src/sqlite-storage.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"sqlite-storage.js","sourceRoot":"","sources":["../../src/sqlite-storage.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optimystic/db-p2p-storage-ns",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "NativeScript SQLite storage backend for @optimystic/db-p2p",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -53,8 +53,8 @@
|
|
|
53
53
|
"typescript": "^5.9.3"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@optimystic/db-core": "^0.
|
|
57
|
-
"@optimystic/db-p2p": "^0.
|
|
56
|
+
"@optimystic/db-core": "^0.25.0",
|
|
57
|
+
"@optimystic/db-p2p": "^0.25.0",
|
|
58
58
|
"debug": "^4.4.3"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
package/src/db.ts
CHANGED
|
@@ -88,7 +88,7 @@ export const DEFAULT_DB_VERSION = 1;
|
|
|
88
88
|
/**
|
|
89
89
|
* Schema for the NativeScript storage backend.
|
|
90
90
|
*
|
|
91
|
-
* Mirrors the IndexedDB object stores 1:1. The
|
|
91
|
+
* Mirrors the IndexedDB object stores 1:1. The six block-storage stores keep
|
|
92
92
|
* their original columns and keys, but their value columns are now BLOB: the
|
|
93
93
|
* shared `KvRawStorage` kernel (driven by `SqliteStoreDriver`) owns all JSON /
|
|
94
94
|
* UTF-8 (de)serialization, so the driver only ever binds/reads the kernel's raw
|
|
@@ -100,6 +100,9 @@ export const DEFAULT_DB_VERSION = 1;
|
|
|
100
100
|
* holds the kernel's encoded `ActionId` bytes (BLOB).
|
|
101
101
|
* - `pending` → uncommitted transform bytes keyed by `(block_id, action_id)`.
|
|
102
102
|
* - `transactions` → committed transform bytes keyed by `(block_id, action_id)`.
|
|
103
|
+
* - `proofs` → `BlockCommitProof` bytes keyed by `(block_id, rev)` — the same key
|
|
104
|
+
* shape as `revisions`, deliberately NOT the action keyspace (an action id is
|
|
105
|
+
* caller-chosen, so no reserved id could be relied on).
|
|
103
106
|
* - `materialized` → materialized block bytes keyed by `(block_id, action_id)`.
|
|
104
107
|
* - `kv` → generic string keyspace shared by `IKVStore` (`s_val`) and the
|
|
105
108
|
* identity helper (`b_val`). NOT kernel-backed; unchanged. The two columns
|
|
@@ -112,7 +115,7 @@ export const DEFAULT_DB_VERSION = 1;
|
|
|
112
115
|
* throwing). There is no migration. Safe today because this backend is
|
|
113
116
|
* NativeScript-only with no shipped production data; if a build ever ships to
|
|
114
117
|
* devices that later upgrade, add a `user_version` bump that drops+recreates
|
|
115
|
-
* these
|
|
118
|
+
* these six tables (or a real migration) before assuming BLOB rows.
|
|
116
119
|
*/
|
|
117
120
|
export const SCHEMA_SQL = `
|
|
118
121
|
CREATE TABLE IF NOT EXISTS metadata (
|
|
@@ -141,6 +144,13 @@ CREATE TABLE IF NOT EXISTS transactions (
|
|
|
141
144
|
PRIMARY KEY (block_id, action_id)
|
|
142
145
|
);
|
|
143
146
|
|
|
147
|
+
CREATE TABLE IF NOT EXISTS proofs (
|
|
148
|
+
block_id TEXT NOT NULL,
|
|
149
|
+
rev INTEGER NOT NULL,
|
|
150
|
+
value BLOB NOT NULL,
|
|
151
|
+
PRIMARY KEY (block_id, rev)
|
|
152
|
+
);
|
|
153
|
+
|
|
144
154
|
CREATE TABLE IF NOT EXISTS materialized (
|
|
145
155
|
block_id TEXT NOT NULL,
|
|
146
156
|
action_id TEXT NOT NULL,
|
package/src/ns-opener.ts
CHANGED
|
@@ -142,7 +142,7 @@ class NSPluginStatement implements SqliteStatement {
|
|
|
142
142
|
// concurrency. A read issued while a write transaction is open on this same
|
|
143
143
|
// connection observes that transaction's UNCOMMITTED rows (read-your-connection
|
|
144
144
|
// semantics). Fine today: the only transaction writer is same-block promote
|
|
145
|
-
// under the
|
|
145
|
+
// under the block's write latch, and cross-block reads are independent. If a future
|
|
146
146
|
// caller reads a block on this connection while another op's transaction on the
|
|
147
147
|
// same rows is mid-flight, it may see uncommitted state — serialize reads too if
|
|
148
148
|
// that ever matters.
|
package/src/sqlite-storage.ts
CHANGED
|
@@ -1,217 +1,243 @@
|
|
|
1
|
-
import type { ActionId, BlockId } from '@optimystic/db-core';
|
|
2
|
-
import { KvRawStorage, type RawStoreDriver } from '@optimystic/db-p2p';
|
|
3
|
-
import type { SqliteDb, SqliteStatement } from './db.js';
|
|
4
|
-
import { createLogger } from './logger.js';
|
|
5
|
-
|
|
6
|
-
const log = createLogger('storage:sqlite');
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* SQLite {@link RawStoreDriver}: the
|
|
10
|
-
* the
|
|
11
|
-
* `materialized`) with their original columns and keys.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* `
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
await
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
async
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
await this.stmts.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
async
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
*
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
1
|
+
import type { ActionId, BlockId } from '@optimystic/db-core';
|
|
2
|
+
import { KvRawStorage, identityForHandle, type RawStoreDriver, type StoreIdentity } from '@optimystic/db-p2p';
|
|
3
|
+
import type { SqliteDb, SqliteStatement } from './db.js';
|
|
4
|
+
import { createLogger } from './logger.js';
|
|
5
|
+
|
|
6
|
+
const log = createLogger('storage:sqlite');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* SQLite {@link RawStoreDriver}: the six logical block-storage stores mapped to
|
|
10
|
+
* the six relational tables (`metadata`, `revisions`, `pending`, `transactions`,
|
|
11
|
+
* `proofs`, `materialized`) with their original columns and keys.
|
|
12
|
+
*
|
|
13
|
+
* `KvRawStorage` now owns all JSON serialization, so this driver only ever
|
|
14
|
+
* reads/writes `Uint8Array` values: the value columns are BLOB and SQLite binds
|
|
15
|
+
* a `Uint8Array` as a BLOB and returns it as a `Uint8Array`, so no codec lives
|
|
16
|
+
* here (a TEXT column would risk UTF-8 coercion corrupting non-ASCII JSON bytes).
|
|
17
|
+
* Everything SQLite-specific stays: each CRUD op goes through a prepared
|
|
18
|
+
* statement bound once in the constructor; range/list queries drain their rows
|
|
19
|
+
* (`.all(...)`) before yielding so no cursor straddles a consumer's `await`; and
|
|
20
|
+
* `promote` runs as a single `db.transaction(fn)` — `BEGIN IMMEDIATE; INSERT…;
|
|
21
|
+
* DELETE…; COMMIT;` — whose three statements are re-prepared against the OPEN
|
|
22
|
+
* transaction so they run on the held mutex slot without re-locking (which would
|
|
23
|
+
* deadlock — see `st-nativescript-sqlite-transaction-mutex`).
|
|
24
|
+
*/
|
|
25
|
+
export class SqliteStoreDriver implements RawStoreDriver {
|
|
26
|
+
private readonly stmts: {
|
|
27
|
+
getMetadata: SqliteStatement;
|
|
28
|
+
saveMetadata: SqliteStatement;
|
|
29
|
+
getRevision: SqliteStatement;
|
|
30
|
+
saveRevision: SqliteStatement;
|
|
31
|
+
listRevisionsAsc: SqliteStatement;
|
|
32
|
+
listRevisionsDesc: SqliteStatement;
|
|
33
|
+
getPending: SqliteStatement;
|
|
34
|
+
savePending: SqliteStatement;
|
|
35
|
+
deletePending: SqliteStatement;
|
|
36
|
+
listPending: SqliteStatement;
|
|
37
|
+
listBlockIds: SqliteStatement;
|
|
38
|
+
getTransaction: SqliteStatement;
|
|
39
|
+
saveTransaction: SqliteStatement;
|
|
40
|
+
getProof: SqliteStatement;
|
|
41
|
+
saveProof: SqliteStatement;
|
|
42
|
+
getMaterialized: SqliteStatement;
|
|
43
|
+
saveMaterialized: SqliteStatement;
|
|
44
|
+
deleteMaterialized: SqliteStatement;
|
|
45
|
+
pageCount: SqliteStatement;
|
|
46
|
+
pageSize: SqliteStatement;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// NOTE: identity is the HANDLE object, so two handles opened over the same SQLite FILE read
|
|
50
|
+
// as two identities. Resolving that would mean naming the underlying database file, which
|
|
51
|
+
// `SqliteDb` does not expose. The package opener (`ns-opener.ts`) hands out one handle per
|
|
52
|
+
// file in practice, so this is the reachable case, not the complete one.
|
|
53
|
+
private readonly identity: StoreIdentity;
|
|
54
|
+
|
|
55
|
+
constructor(private readonly db: SqliteDb) {
|
|
56
|
+
this.identity = identityForHandle('sqlite-handle', db);
|
|
57
|
+
this.stmts = {
|
|
58
|
+
getMetadata: db.prepare('SELECT value FROM metadata WHERE block_id = ?'),
|
|
59
|
+
saveMetadata: db.prepare('INSERT OR REPLACE INTO metadata (block_id, value) VALUES (?, ?)'),
|
|
60
|
+
getRevision: db.prepare('SELECT action_id FROM revisions WHERE block_id = ? AND rev = ?'),
|
|
61
|
+
saveRevision: db.prepare('INSERT OR REPLACE INTO revisions (block_id, rev, action_id) VALUES (?, ?, ?)'),
|
|
62
|
+
listRevisionsAsc: db.prepare('SELECT rev, action_id FROM revisions WHERE block_id = ? AND rev BETWEEN ? AND ? ORDER BY rev ASC'),
|
|
63
|
+
listRevisionsDesc: db.prepare('SELECT rev, action_id FROM revisions WHERE block_id = ? AND rev BETWEEN ? AND ? ORDER BY rev DESC'),
|
|
64
|
+
getPending: db.prepare('SELECT value FROM pending WHERE block_id = ? AND action_id = ?'),
|
|
65
|
+
savePending: db.prepare('INSERT OR REPLACE INTO pending (block_id, action_id, value) VALUES (?, ?, ?)'),
|
|
66
|
+
deletePending: db.prepare('DELETE FROM pending WHERE block_id = ? AND action_id = ?'),
|
|
67
|
+
listPending: db.prepare('SELECT action_id FROM pending WHERE block_id = ? ORDER BY action_id ASC'),
|
|
68
|
+
// metadata.block_id is the PRIMARY KEY, so each row is a distinct block id —
|
|
69
|
+
// no dedup needed. NOTE: drains the whole metadata table up front; if a peer
|
|
70
|
+
// ever holds millions of blocks and this SELECT becomes a startup-latency
|
|
71
|
+
// problem, page it (LIMIT/OFFSET or keyset) — fine at current scale.
|
|
72
|
+
listBlockIds: db.prepare('SELECT block_id FROM metadata'),
|
|
73
|
+
getTransaction: db.prepare('SELECT value FROM transactions WHERE block_id = ? AND action_id = ?'),
|
|
74
|
+
saveTransaction: db.prepare('INSERT OR REPLACE INTO transactions (block_id, action_id, value) VALUES (?, ?, ?)'),
|
|
75
|
+
getProof: db.prepare('SELECT value FROM proofs WHERE block_id = ? AND rev = ?'),
|
|
76
|
+
saveProof: db.prepare('INSERT OR REPLACE INTO proofs (block_id, rev, value) VALUES (?, ?, ?)'),
|
|
77
|
+
getMaterialized: db.prepare('SELECT value FROM materialized WHERE block_id = ? AND action_id = ?'),
|
|
78
|
+
saveMaterialized: db.prepare('INSERT OR REPLACE INTO materialized (block_id, action_id, value) VALUES (?, ?, ?)'),
|
|
79
|
+
deleteMaterialized: db.prepare('DELETE FROM materialized WHERE block_id = ? AND action_id = ?'),
|
|
80
|
+
pageCount: db.prepare('PRAGMA page_count'),
|
|
81
|
+
pageSize: db.prepare('PRAGMA page_size'),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
storeIdentity(): StoreIdentity {
|
|
86
|
+
return this.identity;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// --- metadata ---
|
|
90
|
+
|
|
91
|
+
async getMetadata(blockId: BlockId): Promise<Uint8Array | undefined> {
|
|
92
|
+
const row = await this.stmts.getMetadata.get(blockId);
|
|
93
|
+
return row ? (row.value as Uint8Array) : undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async putMetadata(blockId: BlockId, value: Uint8Array): Promise<void> {
|
|
97
|
+
await this.stmts.saveMetadata.run(blockId, value);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// --- revisions ---
|
|
101
|
+
|
|
102
|
+
async getRevision(blockId: BlockId, rev: number): Promise<Uint8Array | undefined> {
|
|
103
|
+
const row = await this.stmts.getRevision.get(blockId, rev);
|
|
104
|
+
return row ? (row.action_id as Uint8Array) : undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async putRevision(blockId: BlockId, rev: number, value: Uint8Array): Promise<void> {
|
|
108
|
+
await this.stmts.saveRevision.run(blockId, rev, value);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async *rangeRevisions(blockId: BlockId, lo: number, hi: number, reverse: boolean): AsyncIterable<[number, Uint8Array]> {
|
|
112
|
+
// `.all(...)` materializes every row before we yield, so no SQLite cursor
|
|
113
|
+
// straddles the consumer's awaits (the kernel's drain-before-yield contract).
|
|
114
|
+
const stmt = reverse ? this.stmts.listRevisionsDesc : this.stmts.listRevisionsAsc;
|
|
115
|
+
const rows = await stmt.all(blockId, lo, hi);
|
|
116
|
+
for (const row of rows) {
|
|
117
|
+
yield [row.rev as number, row.action_id as Uint8Array];
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// --- pending ---
|
|
122
|
+
|
|
123
|
+
async getPending(blockId: BlockId, actionId: ActionId): Promise<Uint8Array | undefined> {
|
|
124
|
+
const row = await this.stmts.getPending.get(blockId, actionId);
|
|
125
|
+
return row ? (row.value as Uint8Array) : undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async putPending(blockId: BlockId, actionId: ActionId, value: Uint8Array): Promise<void> {
|
|
129
|
+
await this.stmts.savePending.run(blockId, actionId, value);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async deletePending(blockId: BlockId, actionId: ActionId): Promise<void> {
|
|
133
|
+
await this.stmts.deletePending.run(blockId, actionId);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async *listPendingActionIds(blockId: BlockId): AsyncIterable<ActionId> {
|
|
137
|
+
// Drained by `.all(...)` before yielding — same rationale as rangeRevisions.
|
|
138
|
+
const rows = await this.stmts.listPending.all(blockId);
|
|
139
|
+
for (const row of rows) {
|
|
140
|
+
yield row.action_id as ActionId;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// --- transactions ---
|
|
145
|
+
|
|
146
|
+
async getTransaction(blockId: BlockId, actionId: ActionId): Promise<Uint8Array | undefined> {
|
|
147
|
+
const row = await this.stmts.getTransaction.get(blockId, actionId);
|
|
148
|
+
return row ? (row.value as Uint8Array) : undefined;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async putTransaction(blockId: BlockId, actionId: ActionId, value: Uint8Array): Promise<void> {
|
|
152
|
+
await this.stmts.saveTransaction.run(blockId, actionId, value);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// --- proofs (keyed (block_id, rev) like revisions; no delete — see RawStoreDriver.getProof) ---
|
|
156
|
+
|
|
157
|
+
async getProof(blockId: BlockId, rev: number): Promise<Uint8Array | undefined> {
|
|
158
|
+
const row = await this.stmts.getProof.get(blockId, rev);
|
|
159
|
+
return row ? (row.value as Uint8Array) : undefined;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async putProof(blockId: BlockId, rev: number, value: Uint8Array): Promise<void> {
|
|
163
|
+
await this.stmts.saveProof.run(blockId, rev, value);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// --- materialized ---
|
|
167
|
+
|
|
168
|
+
async getMaterialized(blockId: BlockId, actionId: ActionId): Promise<Uint8Array | undefined> {
|
|
169
|
+
const row = await this.stmts.getMaterialized.get(blockId, actionId);
|
|
170
|
+
return row ? (row.value as Uint8Array) : undefined;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async putMaterialized(blockId: BlockId, actionId: ActionId, value: Uint8Array): Promise<void> {
|
|
174
|
+
await this.stmts.saveMaterialized.run(blockId, actionId, value);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async deleteMaterialized(blockId: BlockId, actionId: ActionId): Promise<void> {
|
|
178
|
+
await this.stmts.deleteMaterialized.run(blockId, actionId);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// --- promote (the only cross-key atomic op) ---
|
|
182
|
+
|
|
183
|
+
async promote(blockId: BlockId, actionId: ActionId): Promise<void> {
|
|
184
|
+
await this.db.transaction(async (tx) => {
|
|
185
|
+
// Prepare against the open transaction so these three statements run on
|
|
186
|
+
// the held mutex slot without re-locking the connection (which would
|
|
187
|
+
// deadlock). Re-preparing is cheap — the driver caches by SQL text.
|
|
188
|
+
const getPending = tx.prepare('SELECT value FROM pending WHERE block_id = ? AND action_id = ?');
|
|
189
|
+
const saveTransaction = tx.prepare('INSERT OR REPLACE INTO transactions (block_id, action_id, value) VALUES (?, ?, ?)');
|
|
190
|
+
const deletePending = tx.prepare('DELETE FROM pending WHERE block_id = ? AND action_id = ?');
|
|
191
|
+
const row = await getPending.get(blockId, actionId);
|
|
192
|
+
if (!row) {
|
|
193
|
+
throw new Error(`Pending action ${actionId} not found for block ${blockId}`);
|
|
194
|
+
}
|
|
195
|
+
await saveTransaction.run(blockId, actionId, row.value as Uint8Array);
|
|
196
|
+
await deletePending.run(blockId, actionId);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// --- optional passthroughs ---
|
|
201
|
+
|
|
202
|
+
async *listBlockIds(): AsyncIterable<BlockId> {
|
|
203
|
+
const rows = await this.stmts.listBlockIds.all();
|
|
204
|
+
for (const row of rows) {
|
|
205
|
+
yield row.block_id as BlockId;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async approximateBytesUsed(): Promise<number> {
|
|
210
|
+
try {
|
|
211
|
+
const pageCountRow = await this.stmts.pageCount.get();
|
|
212
|
+
const pageSizeRow = await this.stmts.pageSize.get();
|
|
213
|
+
const pages = (pageCountRow?.page_count as number | undefined) ?? 0;
|
|
214
|
+
const size = (pageSizeRow?.page_size as number | undefined) ?? 0;
|
|
215
|
+
return pages * size;
|
|
216
|
+
} catch (err) {
|
|
217
|
+
log('PRAGMA page_count/page_size failed: %o', err);
|
|
218
|
+
return 0;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* SQLite-backed {@link IRawStorage} for NativeScript peers, now a thin shell over
|
|
225
|
+
* the shared {@link KvRawStorage} kernel driven by a {@link SqliteStoreDriver}.
|
|
226
|
+
* The public name/constructor (`new SqliteRawStorage(db)`) is unchanged so
|
|
227
|
+
* existing imports keep resolving; the kernel supplies the `IRawStorage` surface
|
|
228
|
+
* and the driver supplies SQLite behavior.
|
|
229
|
+
*
|
|
230
|
+
* `listBlockIds`/`getApproximateBytesUsed` are re-declared here as always-present
|
|
231
|
+
* (the SQLite driver always implements them, so the kernel constructor always
|
|
232
|
+
* wires them) — the base declares them optional, but every NS consumer relies on
|
|
233
|
+
* them.
|
|
234
|
+
*/
|
|
235
|
+
export class SqliteRawStorage extends KvRawStorage {
|
|
236
|
+
declare listBlockIds: () => AsyncIterable<BlockId>;
|
|
237
|
+
declare getApproximateBytesUsed: () => Promise<number>;
|
|
238
|
+
declare getStoreIdentity: () => StoreIdentity;
|
|
239
|
+
|
|
240
|
+
constructor(db: SqliteDb) {
|
|
241
|
+
super(new SqliteStoreDriver(db));
|
|
242
|
+
}
|
|
243
|
+
}
|