@optimystic/db-p2p-storage-fs 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 CHANGED
@@ -1,118 +1,120 @@
1
- # @optimystic/db-p2p-storage-fs
2
-
3
- Node.js filesystem storage backend for Optimystic peers. Provides:
4
-
5
- - **`FileRawStorage`** — implements `IRawStorage` so a Node peer persists block
6
- metadata, revisions, pending transactions, committed transactions, and
7
- materialized blocks durably across restarts.
8
- - **`FileKVStore`** — implements `IKVStore` for the persistent transaction state
9
- used to recover crashed two-phase commits.
10
-
11
- This package targets plain Node.js. Use the sibling adapter for other
12
- environments:
13
-
14
- - `@optimystic/db-p2p-storage-ns` — NativeScript (iOS/Android, SQLite)
15
- - `@optimystic/db-p2p-storage-rn` — React Native (MMKV)
16
- - `@optimystic/db-p2p-storage-web` — Browser (IndexedDB)
17
-
18
- ## Install
19
-
20
- ```bash
21
- yarn add @optimystic/db-p2p-storage-fs @optimystic/db-p2p @optimystic/db-core
22
- ```
23
-
24
- ## Usage
25
-
26
- ```ts
27
- import { FileRawStorage, FileKVStore } from '@optimystic/db-p2p-storage-fs';
28
- import { createLibp2pNode } from '@optimystic/db-p2p';
29
-
30
- const rawStorage = new FileRawStorage('/var/lib/my-peer/data');
31
- const kvStore = new FileKVStore('/var/lib/my-peer/data');
32
-
33
- const libp2p = await createLibp2pNode({
34
- bootstrapNodes: [/* … */],
35
- networkName: 'my-network',
36
- rawStorage,
37
- kvStore,
38
- });
39
- ```
40
-
41
- Both constructors take a single `basePath` — the directory under which all
42
- data is stored. They can share the same `basePath` in practice because their
43
- top-level names do not collide: block data lives under `<blockId>/`
44
- subdirectories (block ids are content-address hashes), while KV data lives
45
- under directories named by the first segment of each key (a `/`-separated key
46
- becomes nested subdirectories — e.g. `coordinator/key1` → `coordinator/key1.json`).
47
- Sharing is safe only as long as no block id equals a KV key's first segment;
48
- give them separate `basePath`s if you cannot guarantee that.
49
-
50
- ## On-disk layout
51
-
52
- ```
53
- <basePath>/
54
- <blockId>/
55
- meta.json — BlockMetadata (JSON)
56
- revs/<rev>.json — ActionId for that revision number
57
- pend/<id>.json — pending Transform (two-phase commit, before promotion)
58
- actions/<id>.json — committed Transform
59
- blocks/<id>.json — materialized IBlock snapshot
60
- <key-segment>/
61
- <key-segment>.json — FileKVStore value; key "/" separators become subdirectories
62
- ```
63
-
64
- Action ids that contain a colon (e.g. `tx:abcd1234`) are percent-encoded in
65
- filenames (`tx%3Aabcd1234.json`) for Windows compatibility; the storage layer
66
- encodes and decodes transparently so callers always work with the canonical
67
- id form.
68
-
69
- ## Atomic writes
70
-
71
- Every write goes through `atomic-write.ts`: the new content is written to a
72
- `.tmp` sibling, then renamed over the canonical path. A crash mid-write
73
- therefore leaves either the complete old file or the complete new file — never
74
- a partial/torn one.
75
-
76
- ## Identity
77
-
78
- Unlike the `ns`/`rn`/`web` adapters, this package ships **no** identity module
79
- and no `loadOrCreateFSPeerKey` helper. The reference peer that uses this adapter
80
- does not persist its libp2p private key, so an fs-backed node gets a fresh
81
- ephemeral peer id on every restart. Adding durable identity is a separate
82
- feature — see Known limitations below.
83
-
84
- ## Tests
85
-
86
- ```bash
87
- yarn test # mocha, minimal reporter
88
- yarn test:verbose # mocha, spec reporter
89
- ```
90
-
91
- Two layers run here, both over a per-test `fs.mkdtemp` fixture with `afterEach`
92
- cleanup:
93
-
94
- - **Shared conformance suite** — `runRawStorageConformance('FileSystem', …)` from
95
- `@optimystic/db-p2p/testing/conformance`, the one cross-backend parity target. It proves the
96
- fs backend (now `KvRawStorage` over a `FileStoreDriver`) behaves identically to
97
- every other backend: round-trips, `listRevisions` ordering, promote atomicity +
98
- the exact missing-pend error, clone-on-store/read (structural via the byte
99
- boundary), drain-before-yield iteration, and a `BlockStorage` parity slice.
100
- - **fs-only tests** (`node:assert`) — the behaviors the shared suite can't cover:
101
- atomic writes + torn-file corruption tolerance, `readdir` error discrimination,
102
- colon-encoded filenames + the POSIX legacy raw-colon fallback, the directory-based
103
- `listBlockIds` meta-gate, and `FileKVStore.list`/`delete`.
104
-
105
- ## Known limitations
106
-
107
- **No cross-process lock.** Two separate Node processes pointing at the same
108
- `basePath` can interleave writes with no coordination. The constructor carries
109
- a TODO (`file-storage.ts:52`) to integrate
110
- [`proper-lockfile`](https://www.npmjs.com/package/proper-lockfile) along with
111
- an explicit `dispose()` pattern. Until that lands, `FileRawStorage` is
112
- single-process only.
113
-
114
- **Ephemeral peer identity.** There is no `loadOrCreateFSPeerKey` equivalent.
115
- A Node peer backed by `FileRawStorage` gets a new libp2p peer id each restart.
116
- If your use case requires a stable, restart-surviving identity, a future
117
- `feat-fs-peer-identity` feature should add the key-persistence helper — it is
118
- deliberately out of scope here.
1
+ # @optimystic/db-p2p-storage-fs
2
+
3
+ Node.js filesystem storage backend for Optimystic peers. Provides:
4
+
5
+ - **`FileRawStorage`** — implements `IRawStorage` so a Node peer persists block
6
+ metadata, revisions, pending transactions, committed transactions, commit
7
+ proofs, and
8
+ materialized blocks durably across restarts.
9
+ - **`FileKVStore`** — implements `IKVStore` for the persistent transaction state
10
+ used to recover crashed two-phase commits.
11
+
12
+ This package targets plain Node.js. Use the sibling adapter for other
13
+ environments:
14
+
15
+ - `@optimystic/db-p2p-storage-ns` — NativeScript (iOS/Android, SQLite)
16
+ - `@optimystic/db-p2p-storage-rn` — React Native (MMKV)
17
+ - `@optimystic/db-p2p-storage-web` — Browser (IndexedDB)
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ yarn add @optimystic/db-p2p-storage-fs @optimystic/db-p2p @optimystic/db-core
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ```ts
28
+ import { FileRawStorage, FileKVStore } from '@optimystic/db-p2p-storage-fs';
29
+ import { createLibp2pNode } from '@optimystic/db-p2p';
30
+
31
+ const rawStorage = new FileRawStorage('/var/lib/my-peer/data');
32
+ const kvStore = new FileKVStore('/var/lib/my-peer/data');
33
+
34
+ const libp2p = await createLibp2pNode({
35
+ bootstrapNodes: [/* … */],
36
+ networkName: 'my-network',
37
+ rawStorage,
38
+ kvStore,
39
+ });
40
+ ```
41
+
42
+ Both constructors take a single `basePath` — the directory under which all
43
+ data is stored. They can share the same `basePath` in practice because their
44
+ top-level names do not collide: block data lives under `<blockId>/`
45
+ subdirectories (block ids are content-address hashes), while KV data lives
46
+ under directories named by the first segment of each key (a `/`-separated key
47
+ becomes nested subdirectories — e.g. `coordinator/key1` → `coordinator/key1.json`).
48
+ Sharing is safe only as long as no block id equals a KV key's first segment;
49
+ give them separate `basePath`s if you cannot guarantee that.
50
+
51
+ ## On-disk layout
52
+
53
+ ```
54
+ <basePath>/
55
+ <blockId>/
56
+ meta.json — BlockMetadata (JSON)
57
+ revs/<rev>.json — ActionId for that revision number
58
+ pend/<id>.json — pending Transform (two-phase commit, before promotion)
59
+ actions/<id>.json — committed Transform
60
+ proofs/<rev>.json — BlockCommitProof retained for that revision
61
+ blocks/<id>.json — materialized IBlock snapshot
62
+ <key-segment>/
63
+ <key-segment>.json — FileKVStore value; key "/" separators become subdirectories
64
+ ```
65
+
66
+ Action ids that contain a colon (e.g. `tx:abcd1234`) are percent-encoded in
67
+ filenames (`tx%3Aabcd1234.json`) for Windows compatibility; the storage layer
68
+ encodes and decodes transparently so callers always work with the canonical
69
+ id form.
70
+
71
+ ## Atomic writes
72
+
73
+ Every write goes through `atomic-write.ts`: the new content is written to a
74
+ `.tmp` sibling, then renamed over the canonical path. A crash mid-write
75
+ therefore leaves either the complete old file or the complete new file — never
76
+ a partial/torn one.
77
+
78
+ ## Identity
79
+
80
+ Unlike the `ns`/`rn`/`web` adapters, this package ships **no** identity module
81
+ and no `loadOrCreateFSPeerKey` helper. The reference peer that uses this adapter
82
+ does not persist its libp2p private key, so an fs-backed node gets a fresh
83
+ ephemeral peer id on every restart. Adding durable identity is a separate
84
+ feature — see Known limitations below.
85
+
86
+ ## Tests
87
+
88
+ ```bash
89
+ yarn test # mocha, minimal reporter
90
+ yarn test:verbose # mocha, spec reporter
91
+ ```
92
+
93
+ Two layers run here, both over a per-test `fs.mkdtemp` fixture with `afterEach`
94
+ cleanup:
95
+
96
+ - **Shared conformance suite** — `runRawStorageConformance('FileSystem', …)` from
97
+ `@optimystic/db-p2p/testing/conformance`, the one cross-backend parity target. It proves the
98
+ fs backend (now `KvRawStorage` over a `FileStoreDriver`) behaves identically to
99
+ every other backend: round-trips, `listRevisions` ordering, promote atomicity +
100
+ the exact missing-pend error, clone-on-store/read (structural via the byte
101
+ boundary), drain-before-yield iteration, and a `BlockStorage` parity slice.
102
+ - **fs-only tests** (`node:assert`) — the behaviors the shared suite can't cover:
103
+ atomic writes + torn-file corruption tolerance, `readdir` error discrimination,
104
+ colon-encoded filenames + the POSIX legacy raw-colon fallback, the directory-based
105
+ `listBlockIds` meta-gate, and `FileKVStore.list`/`delete`.
106
+
107
+ ## Known limitations
108
+
109
+ **No cross-process lock.** Two separate Node processes pointing at the same
110
+ `basePath` can interleave writes with no coordination. The constructor carries
111
+ a TODO (`file-storage.ts:52`) to integrate
112
+ [`proper-lockfile`](https://www.npmjs.com/package/proper-lockfile) along with
113
+ an explicit `dispose()` pattern. Until that lands, `FileRawStorage` is
114
+ single-process only.
115
+
116
+ **Ephemeral peer identity.** There is no `loadOrCreateFSPeerKey` equivalent.
117
+ A Node peer backed by `FileRawStorage` gets a new libp2p peer id each restart.
118
+ If your use case requires a stable, restart-surviving identity, a future
119
+ `feat-fs-peer-identity` feature should add the key-persistence helper — it is
120
+ deliberately out of scope here.
@@ -6,7 +6,7 @@
6
6
  * concurrent reader only ever sees the complete old file or the complete new
7
7
  * file — never a torn/half-written one. After the rename we best-effort fsync
8
8
  * the containing directory so the rename itself survives power loss on POSIX;
9
- * that directory fsync is unsupported on win32 and its error is swallowed.
9
+ * that directory fsync is unsupported on win32 and is skipped there.
10
10
  *
11
11
  * On any failure the temp file is removed (best-effort) so a crashed write does
12
12
  * not leave the canonical path damaged. A crash *between* the temp write and the
@@ -14,7 +14,7 @@ let tempCounter = 0;
14
14
  * concurrent reader only ever sees the complete old file or the complete new
15
15
  * file — never a torn/half-written one. After the rename we best-effort fsync
16
16
  * the containing directory so the rename itself survives power loss on POSIX;
17
- * that directory fsync is unsupported on win32 and its error is swallowed.
17
+ * that directory fsync is unsupported on win32 and is skipped there.
18
18
  *
19
19
  * On any failure the temp file is removed (best-effort) so a crashed write does
20
20
  * not leave the canonical path damaged. A crash *between* the temp write and the
@@ -62,17 +62,25 @@ export async function atomicWriteFile(filePath, content) {
62
62
  }
63
63
  /**
64
64
  * Best-effort fsync of a directory so a completed rename is durable. POSIX needs
65
- * this; win32 (and platforms that reject opening a directory for fsync) throw,
66
- * and we ignore that rather than failing the write.
65
+ * this; platforms that reject opening a directory for fsync throw, and we ignore
66
+ * that rather than failing the write.
67
+ *
68
+ * Skipped outright on win32: there `fs.open(dir, 'r')` SUCCEEDS and only the
69
+ * following `handle.sync()` fails with EPERM (swallowed), so the open/close pair
70
+ * was guaranteed wasted work — exactly half of all `fs.open` calls a write
71
+ * workload makes. Durability is unchanged on win32 (the sync never succeeded
72
+ * there); the on-disk layout is untouched.
67
73
  */
68
74
  async function fsyncDir(dir) {
75
+ if (process.platform === 'win32')
76
+ return;
69
77
  let handle;
70
78
  try {
71
79
  handle = await fs.open(dir, 'r');
72
80
  await handle.sync();
73
81
  }
74
82
  catch {
75
- // Directory fsync unsupported here (e.g. win32) — nothing to do.
83
+ // Directory fsync unsupported here — nothing to do.
76
84
  }
77
85
  finally {
78
86
  if (handle)
@@ -1 +1 @@
1
- {"version":3,"file":"atomic-write.js","sourceRoot":"","sources":["../../src/atomic-write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,gFAAgF;AAChF,4EAA4E;AAC5E,+EAA+E;AAC/E,+EAA+E;AAC/E,uDAAuD;AACvD,IAAI,WAAW,GAAG,CAAC,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAAgB,EAAE,OAA4B;IACnF,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzC,qFAAqF;IACrF,iEAAiE;IACjE,oFAAoF;IACpF,qFAAqF;IACrF,mEAAmE;IACnE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,GAAG,IAAI,WAAW,EAAE,MAAM,CAAC,CAAC;IAEjG,IAAI,MAAiC,CAAC;IACtC,IAAI,CAAC;QACJ,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACrC,MAAM,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAChC,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,MAAM,GAAG,SAAS,CAAC;QACnB,yEAAyE;QACzE,0EAA0E;QAC1E,2EAA2E;QAC3E,6EAA6E;QAC7E,6EAA6E;QAC7E,6EAA6E;QAC7E,4EAA4E;QAC5E,+EAA+E;QAC/E,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,IAAI,MAAM;YAAE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAqB,CAAC,CAAC,CAAC;QACpE,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAyC,CAAC,CAAC,CAAC;QAChF,MAAM,GAAG,CAAC;IACX,CAAC;IAED,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,QAAQ,CAAC,GAAW;IAClC,IAAI,MAAiC,CAAC;IACtC,IAAI,CAAC;QACJ,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACjC,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACR,iEAAiE;IAClE,CAAC;YAAS,CAAC;QACV,IAAI,MAAM;YAAE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAqB,CAAC,CAAC,CAAC;IACrE,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"atomic-write.js","sourceRoot":"","sources":["../../src/atomic-write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,gFAAgF;AAChF,4EAA4E;AAC5E,+EAA+E;AAC/E,+EAA+E;AAC/E,uDAAuD;AACvD,IAAI,WAAW,GAAG,CAAC,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAAgB,EAAE,OAA4B;IACnF,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzC,qFAAqF;IACrF,iEAAiE;IACjE,oFAAoF;IACpF,qFAAqF;IACrF,mEAAmE;IACnE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,GAAG,IAAI,WAAW,EAAE,MAAM,CAAC,CAAC;IAEjG,IAAI,MAAiC,CAAC;IACtC,IAAI,CAAC;QACJ,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACrC,MAAM,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAChC,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,MAAM,GAAG,SAAS,CAAC;QACnB,yEAAyE;QACzE,0EAA0E;QAC1E,2EAA2E;QAC3E,6EAA6E;QAC7E,6EAA6E;QAC7E,6EAA6E;QAC7E,4EAA4E;QAC5E,+EAA+E;QAC/E,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,IAAI,MAAM;YAAE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAqB,CAAC,CAAC,CAAC;QACpE,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAyC,CAAC,CAAC,CAAC;QAChF,MAAM,GAAG,CAAC;IACX,CAAC;IAED,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC;AAED;;;;;;;;;;GAUG;AACH,KAAK,UAAU,QAAQ,CAAC,GAAW;IAClC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO;IACzC,IAAI,MAAiC,CAAC;IACtC,IAAI,CAAC;QACJ,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACjC,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACR,oDAAoD;IACrD,CAAC;YAAS,CAAC;QACV,IAAI,MAAM;YAAE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAqB,CAAC,CAAC,CAAC;IACrE,CAAC;AACF,CAAC"}
@@ -1,9 +1,9 @@
1
1
  import type { BlockId, ActionId } 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
  /**
4
- * Filesystem {@link RawStoreDriver}: the five logical block-storage stores mapped
5
- * to five subdirectories under `basePath/<blockId>/`
6
- * (`{meta.json,revs/,pend/,actions/,blocks/}`). The directory tree is a
4
+ * Filesystem {@link RawStoreDriver}: the six logical block-storage stores mapped
5
+ * to six paths under `basePath/<blockId>/`
6
+ * (`{meta.json,revs/,pend/,actions/,proofs/,blocks/}`). The directory tree is a
7
7
  * deliberate, human-inspectable/debuggable layout — it is NOT flattened into
8
8
  * encoded-filename KV keys.
9
9
  *
@@ -15,7 +15,9 @@ import { KvRawStorage, type RawStoreDriver } from "@optimystic/db-p2p";
15
15
  */
16
16
  export declare class FileStoreDriver implements RawStoreDriver {
17
17
  private readonly basePath;
18
+ private readonly identity;
18
19
  constructor(basePath: string);
20
+ storeIdentity(): StoreIdentity;
19
21
  getMetadata(blockId: BlockId): Promise<Uint8Array | undefined>;
20
22
  putMetadata(blockId: BlockId, value: Uint8Array): Promise<void>;
21
23
  getRevision(blockId: BlockId, rev: number): Promise<Uint8Array | undefined>;
@@ -27,6 +29,8 @@ export declare class FileStoreDriver implements RawStoreDriver {
27
29
  listPendingActionIds(blockId: BlockId): AsyncIterable<ActionId>;
28
30
  getTransaction(blockId: BlockId, actionId: ActionId): Promise<Uint8Array | undefined>;
29
31
  putTransaction(blockId: BlockId, actionId: ActionId, value: Uint8Array): Promise<void>;
32
+ getProof(blockId: BlockId, rev: number): Promise<Uint8Array | undefined>;
33
+ putProof(blockId: BlockId, rev: number, value: Uint8Array): Promise<void>;
30
34
  getMaterialized(blockId: BlockId, actionId: ActionId): Promise<Uint8Array | undefined>;
31
35
  putMaterialized(blockId: BlockId, actionId: ActionId, value: Uint8Array): Promise<void>;
32
36
  deleteMaterialized(blockId: BlockId, actionId: ActionId): Promise<void>;
@@ -37,6 +41,7 @@ export declare class FileStoreDriver implements RawStoreDriver {
37
41
  private getBlockPath;
38
42
  private getMetadataPath;
39
43
  private getRevisionPath;
44
+ private getProofPath;
40
45
  private getPendingActionPath;
41
46
  private getActionPath;
42
47
  private getMaterializedPath;
@@ -51,13 +56,14 @@ export declare class FileStoreDriver implements RawStoreDriver {
51
56
  * imports keep resolving; the kernel supplies the `IRawStorage` surface and the
52
57
  * driver supplies fs behavior.
53
58
  *
54
- * `listBlockIds`/`getApproximateBytesUsed` are re-declared here as always-present
55
- * (the fs driver always implements them, so the kernel constructor always wires
56
- * them) — the base declares them optional, but every fs consumer relies on them.
59
+ * `listBlockIds`/`getApproximateBytesUsed`/`getStoreIdentity` are re-declared here as
60
+ * always-present (the fs driver always implements them, so the kernel constructor always
61
+ * wires them) — the base declares them optional, but every fs consumer relies on them.
57
62
  */
58
63
  export declare class FileRawStorage extends KvRawStorage {
59
64
  listBlockIds: () => AsyncIterable<BlockId>;
60
65
  getApproximateBytesUsed: () => Promise<number>;
66
+ getStoreIdentity: () => StoreIdentity;
61
67
  constructor(basePath: string);
62
68
  }
63
69
  //# sourceMappingURL=file-storage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-storage.d.ts","sourceRoot":"","sources":["../../src/file-storage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAsCvE;;;;;;;;;;;;GAYG;AACH,qBAAa,eAAgB,YAAW,cAAc;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,MAAM;IAMvC,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAI9D,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAe/D,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAI3E,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3E,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,aAAa,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAuBhH,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAOjF,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlF,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IASjE,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC;IA8ChE,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAOrF,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAMtF,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAOtF,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAMvF,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAWvE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB3D,YAAY,IAAI,aAAa,CAAC,OAAO,CAAC;IAgDvC,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC;YAI/B,iBAAiB;IA6B/B,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,oBAAoB;IAK5B,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,mBAAmB;YASb,cAAc;YAsBd,qBAAqB;YAcrB,iBAAiB;CAc/B;AAED;;;;;;;;;;GAUG;AACH,qBAAa,cAAe,SAAQ,YAAY;IACvC,YAAY,EAAE,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;IAC3C,uBAAuB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;gBAE3C,QAAQ,EAAE,MAAM;CAG5B"}
1
+ {"version":3,"file":"file-storage.d.ts","sourceRoot":"","sources":["../../src/file-storage.ts"],"names":[],"mappings":"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"}
@@ -35,9 +35,9 @@ function isParseableJson(bytes) {
35
35
  }
36
36
  }
37
37
  /**
38
- * Filesystem {@link RawStoreDriver}: the five logical block-storage stores mapped
39
- * to five subdirectories under `basePath/<blockId>/`
40
- * (`{meta.json,revs/,pend/,actions/,blocks/}`). The directory tree is a
38
+ * Filesystem {@link RawStoreDriver}: the six logical block-storage stores mapped
39
+ * to six paths under `basePath/<blockId>/`
40
+ * (`{meta.json,revs/,pend/,actions/,proofs/,blocks/}`). The directory tree is a
41
41
  * deliberate, human-inspectable/debuggable layout — it is NOT flattened into
42
42
  * encoded-filename KV keys.
43
43
  *
@@ -49,9 +49,43 @@ function isParseableJson(bytes) {
49
49
  */
50
50
  export class FileStoreDriver {
51
51
  basePath;
52
+ identity;
52
53
  constructor(basePath) {
53
54
  this.basePath = basePath;
54
55
  // TODO: use https://www.npmjs.com/package/proper-lockfile to take a lock on the basePath, also introduce explicit dispose pattern
56
+ // The directory this driver is backed by, resolved once here: `path.resolve` is
57
+ // cwd-dependent, and capturing it at construction is the correct reading — two drivers
58
+ // built from the same RELATIVE path under different cwds genuinely address different
59
+ // directories and must not compare equal. An empty basePath resolves to the cwd;
60
+ // nothing special-cases it. (A whitespace-only basePath is NOT the cwd — `path.resolve`
61
+ // is pure string work, so `' '` names a child directory called `' '`.)
62
+ // Lowercased on win32 because Windows paths are case-insensitive: `C:\Foo` and `C:\foo`
63
+ // are one directory and must produce one identity.
64
+ // NOTE: aliases of one directory that this does NOT collapse, and so read as two
65
+ // identities: symlinks, junctions, UNC-versus-mapped-drive spellings, and case-differing
66
+ // spellings on a case-INSENSITIVE non-Windows volume (the default on macOS) — platform is
67
+ // the only signal available synchronously, and case-folding every darwin path would be
68
+ // wrong on a case-sensitive volume. `fs.realpath` resolves all of these, but it is async
69
+ // (this constructor is not) and requires the directory to already exist. Revisit if an
70
+ // alias ever bites. All of these fail in the SAFE direction: a missed alias reports two
71
+ // identities for one directory, so an identity-keyed consumer declines to merge and gets
72
+ // today's behavior.
73
+ // NOTE: the win32 fold is the one branch that can err in the UNSAFE direction — Windows
74
+ // 10+ supports per-directory case sensitivity (`fsutil file setCaseSensitiveInfo`), and
75
+ // on such a directory `X:\p\Foo` and `X:\p\foo` are two directories folded onto ONE
76
+ // identity. That merging consumer now exists — `withReadCache` (db-p2p) shares ONE read
77
+ // cache per identity — so on such a directory the two stores would read through one cache
78
+ // and see each other's blocks, and if the second cache is built directly rather than
79
+ // through that helper, `SharedCachePool.registerStore` refuses it outright (one cache per
80
+ // backing store) and construction throws. Not addressable synchronously either (the flag is a
81
+ // per-directory filesystem query). Revisit if Optimystic ever targets a
82
+ // case-sensitive-enabled Windows directory; until then the fold is right for every
83
+ // ordinary Windows volume.
84
+ const resolved = path.resolve(basePath);
85
+ this.identity = `file:${process.platform === 'win32' ? resolved.toLowerCase() : resolved}`;
86
+ }
87
+ storeIdentity() {
88
+ return this.identity;
55
89
  }
56
90
  // --- metadata ---
57
91
  async getMetadata(blockId) {
@@ -163,6 +197,17 @@ export class FileStoreDriver {
163
197
  async putTransaction(blockId, actionId, value) {
164
198
  await atomicWriteFile(this.getActionPath(blockId, actionId), value);
165
199
  }
200
+ // --- proofs ---
201
+ // Keyed by (blockId, rev) like the revisions store, but JSON-valued like the action
202
+ // stores — so it takes the corrupt-content-as-missing guard the revisions store does
203
+ // not, and the filename carries no colon to encode. Deliberately no delete: a proof
204
+ // lives and dies with its revision record (see RawStoreDriver.getProof).
205
+ async getProof(blockId, rev) {
206
+ return this.readBytesIfExists(this.getProofPath(blockId, rev), true);
207
+ }
208
+ async putProof(blockId, rev, value) {
209
+ await atomicWriteFile(this.getProofPath(blockId, rev), value);
210
+ }
166
211
  // --- materialized ---
167
212
  async getMaterialized(blockId, actionId) {
168
213
  return this.readActionScopedBytes(this.getMaterializedPath(blockId, actionId), this.getMaterializedPath(blockId, actionId, false));
@@ -200,7 +245,7 @@ export class FileStoreDriver {
200
245
  }
201
246
  // --- optional passthroughs ---
202
247
  async *listBlockIds() {
203
- // The block layout is `basePath/<blockId>/{meta.json,revs/,pend/,actions/,blocks/}`
248
+ // The block layout is `basePath/<blockId>/{meta.json,revs/,pend/,actions/,proofs/,blocks/}`
204
249
  // (see getBlockPath), so the direct children of basePath are the per-block directories
205
250
  // and each directory NAME is the blockId (used raw, no encoding). Filter to directories
206
251
  // so a stray file can't be mistaken for a block; `*.tmp` atomic-write orphans live inside
@@ -291,6 +336,9 @@ export class FileStoreDriver {
291
336
  getRevisionPath(blockId, rev) {
292
337
  return path.join(this.getBlockPath(blockId), 'revs', `${rev}.json`);
293
338
  }
339
+ getProofPath(blockId, rev) {
340
+ return path.join(this.getBlockPath(blockId), 'proofs', `${rev}.json`);
341
+ }
294
342
  // `encoded` controls colon handling: writes and canonical reads use the
295
343
  // percent-encoded filename (encoded = true); the legacy raw-colon fallback
296
344
  // (see readActionScopedBytes) passes encoded = false to reach pre-encode
@@ -373,9 +421,9 @@ export class FileStoreDriver {
373
421
  * imports keep resolving; the kernel supplies the `IRawStorage` surface and the
374
422
  * driver supplies fs behavior.
375
423
  *
376
- * `listBlockIds`/`getApproximateBytesUsed` are re-declared here as always-present
377
- * (the fs driver always implements them, so the kernel constructor always wires
378
- * them) — the base declares them optional, but every fs consumer relies on them.
424
+ * `listBlockIds`/`getApproximateBytesUsed`/`getStoreIdentity` are re-declared here as
425
+ * always-present (the fs driver always implements them, so the kernel constructor always
426
+ * wires them) — the base declares them optional, but every fs consumer relies on them.
379
427
  */
380
428
  export class FileRawStorage extends KvRawStorage {
381
429
  constructor(basePath) {
@@ -1 +1 @@
1
- {"version":3,"file":"file-storage.js","sourceRoot":"","sources":["../../src/file-storage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"file-storage.js","sourceRoot":"","sources":["../../src/file-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-fs",
3
- "version": "0.24.2",
3
+ "version": "0.25.0",
4
4
  "type": "module",
5
5
  "description": "Node.js filesystem storage backend for @optimystic/db-p2p",
6
6
  "main": "dist/src/index.js",
@@ -48,8 +48,8 @@
48
48
  "typescript": "^5.9.3"
49
49
  },
50
50
  "dependencies": {
51
- "@optimystic/db-core": "^0.24.2",
52
- "@optimystic/db-p2p": "^0.24.2",
51
+ "@optimystic/db-core": "^0.25.0",
52
+ "@optimystic/db-p2p": "^0.25.0",
53
53
  "debug": "^4.4.3"
54
54
  }
55
55
  }
@@ -1,82 +1,89 @@
1
- import { promises as fs } from 'fs';
2
- import * as path from 'path';
3
-
4
- // Per-process monotonic counter for unique temp names. Combined with the pid it
5
- // makes each temp path unique across concurrent writers to the same logical
6
- // target — even two FileRawStorage/FileKVStore instances in one process, which
7
- // do not lock (see the proper-lockfile TODO in file-storage.ts). Deterministic
8
- // and collision-safe, unlike Math.random()/Date.now().
9
- let tempCounter = 0;
10
-
11
- /**
12
- * Atomically write `content` to `filePath`.
13
- *
14
- * Writes to a unique `*.tmp` sibling, fsyncs the data, then renames it into
15
- * place. `rename` over an existing file is atomic on POSIX and NTFS, so a
16
- * concurrent reader only ever sees the complete old file or the complete new
17
- * file — never a torn/half-written one. After the rename we best-effort fsync
18
- * the containing directory so the rename itself survives power loss on POSIX;
19
- * that directory fsync is unsupported on win32 and its error is swallowed.
20
- *
21
- * On any failure the temp file is removed (best-effort) so a crashed write does
22
- * not leave the canonical path damaged. A crash *between* the temp write and the
23
- * rename leaves only an inert `*.tmp` sibling — never read (reads target
24
- * canonical paths) and skipped by `.json` directory scans.
25
- *
26
- * `content` is `string | Uint8Array`: `FileKVStore` writes strings, while the
27
- * `KvRawStorage`-backed `FileStoreDriver` writes the kernel's raw value bytes.
28
- * `FileHandle.writeFile` writes either losslessly — a `Uint8Array` is written
29
- * byte-for-byte, so non-ASCII JSON round-trips exactly.
30
- */
31
- export async function atomicWriteFile(filePath: string, content: string | Uint8Array): Promise<void> {
32
- const dir = path.dirname(filePath);
33
- await fs.mkdir(dir, { recursive: true });
34
-
35
- // Suffix ends in `.tmp` (not `.json`) so listPendingTransactions / FileKVStore.list,
36
- // which filter on `.json`, never surface an in-flight temp file.
37
- // NOTE: a crash between open and rename leaves an inert `*.tmp` orphan (never read,
38
- // skipped by `.json` scans). No cleanup sweep exists; if a crash-looping writer ever
39
- // accumulates many, add a startup sweep of stale `*.tmp` siblings.
40
- const tmpPath = path.join(dir, `${path.basename(filePath)}.${process.pid}.${tempCounter++}.tmp`);
41
-
42
- let handle: fs.FileHandle | undefined;
43
- try {
44
- handle = await fs.open(tmpPath, 'w');
45
- await handle.writeFile(content);
46
- await handle.sync();
47
- await handle.close();
48
- handle = undefined;
49
- // NOTE: on win32, rename-over-existing can throw EPERM/EACCES/EBUSY if a
50
- // concurrent reader holds the target open without FILE_SHARE_DELETE (Node
51
- // readIfExists/get open→read→close in a tiny window, so it's rare). Modern
52
- // libuv retries some cases; if this ever surfaces as spurious write failures
53
- // under concurrent read+write on Windows, add a bounded retry loop here (the
54
- // write-file-atomic package does exactly this). Conditional — the adapter is
55
- // already last-writer-wins with no cross-process lock (proper-lockfile TODO
56
- // in file-storage.ts), so it is not reachable under current single-writer use.
57
- await fs.rename(tmpPath, filePath);
58
- } catch (err) {
59
- if (handle) await handle.close().catch(() => { /* best-effort */ });
60
- await fs.unlink(tmpPath).catch(() => { /* best-effort: temp may not exist */ });
61
- throw err;
62
- }
63
-
64
- await fsyncDir(dir);
65
- }
66
-
67
- /**
68
- * Best-effort fsync of a directory so a completed rename is durable. POSIX needs
69
- * this; win32 (and platforms that reject opening a directory for fsync) throw,
70
- * and we ignore that rather than failing the write.
71
- */
72
- async function fsyncDir(dir: string): Promise<void> {
73
- let handle: fs.FileHandle | undefined;
74
- try {
75
- handle = await fs.open(dir, 'r');
76
- await handle.sync();
77
- } catch {
78
- // Directory fsync unsupported here (e.g. win32) — nothing to do.
79
- } finally {
80
- if (handle) await handle.close().catch(() => { /* best-effort */ });
81
- }
82
- }
1
+ import { promises as fs } from 'fs';
2
+ import * as path from 'path';
3
+
4
+ // Per-process monotonic counter for unique temp names. Combined with the pid it
5
+ // makes each temp path unique across concurrent writers to the same logical
6
+ // target — even two FileRawStorage/FileKVStore instances in one process, which
7
+ // do not lock (see the proper-lockfile TODO in file-storage.ts). Deterministic
8
+ // and collision-safe, unlike Math.random()/Date.now().
9
+ let tempCounter = 0;
10
+
11
+ /**
12
+ * Atomically write `content` to `filePath`.
13
+ *
14
+ * Writes to a unique `*.tmp` sibling, fsyncs the data, then renames it into
15
+ * place. `rename` over an existing file is atomic on POSIX and NTFS, so a
16
+ * concurrent reader only ever sees the complete old file or the complete new
17
+ * file — never a torn/half-written one. After the rename we best-effort fsync
18
+ * the containing directory so the rename itself survives power loss on POSIX;
19
+ * that directory fsync is unsupported on win32 and is skipped there.
20
+ *
21
+ * On any failure the temp file is removed (best-effort) so a crashed write does
22
+ * not leave the canonical path damaged. A crash *between* the temp write and the
23
+ * rename leaves only an inert `*.tmp` sibling — never read (reads target
24
+ * canonical paths) and skipped by `.json` directory scans.
25
+ *
26
+ * `content` is `string | Uint8Array`: `FileKVStore` writes strings, while the
27
+ * `KvRawStorage`-backed `FileStoreDriver` writes the kernel's raw value bytes.
28
+ * `FileHandle.writeFile` writes either losslessly — a `Uint8Array` is written
29
+ * byte-for-byte, so non-ASCII JSON round-trips exactly.
30
+ */
31
+ export async function atomicWriteFile(filePath: string, content: string | Uint8Array): Promise<void> {
32
+ const dir = path.dirname(filePath);
33
+ await fs.mkdir(dir, { recursive: true });
34
+
35
+ // Suffix ends in `.tmp` (not `.json`) so listPendingTransactions / FileKVStore.list,
36
+ // which filter on `.json`, never surface an in-flight temp file.
37
+ // NOTE: a crash between open and rename leaves an inert `*.tmp` orphan (never read,
38
+ // skipped by `.json` scans). No cleanup sweep exists; if a crash-looping writer ever
39
+ // accumulates many, add a startup sweep of stale `*.tmp` siblings.
40
+ const tmpPath = path.join(dir, `${path.basename(filePath)}.${process.pid}.${tempCounter++}.tmp`);
41
+
42
+ let handle: fs.FileHandle | undefined;
43
+ try {
44
+ handle = await fs.open(tmpPath, 'w');
45
+ await handle.writeFile(content);
46
+ await handle.sync();
47
+ await handle.close();
48
+ handle = undefined;
49
+ // NOTE: on win32, rename-over-existing can throw EPERM/EACCES/EBUSY if a
50
+ // concurrent reader holds the target open without FILE_SHARE_DELETE (Node
51
+ // readIfExists/get open→read→close in a tiny window, so it's rare). Modern
52
+ // libuv retries some cases; if this ever surfaces as spurious write failures
53
+ // under concurrent read+write on Windows, add a bounded retry loop here (the
54
+ // write-file-atomic package does exactly this). Conditional — the adapter is
55
+ // already last-writer-wins with no cross-process lock (proper-lockfile TODO
56
+ // in file-storage.ts), so it is not reachable under current single-writer use.
57
+ await fs.rename(tmpPath, filePath);
58
+ } catch (err) {
59
+ if (handle) await handle.close().catch(() => { /* best-effort */ });
60
+ await fs.unlink(tmpPath).catch(() => { /* best-effort: temp may not exist */ });
61
+ throw err;
62
+ }
63
+
64
+ await fsyncDir(dir);
65
+ }
66
+
67
+ /**
68
+ * Best-effort fsync of a directory so a completed rename is durable. POSIX needs
69
+ * this; platforms that reject opening a directory for fsync throw, and we ignore
70
+ * that rather than failing the write.
71
+ *
72
+ * Skipped outright on win32: there `fs.open(dir, 'r')` SUCCEEDS and only the
73
+ * following `handle.sync()` fails with EPERM (swallowed), so the open/close pair
74
+ * was guaranteed wasted work — exactly half of all `fs.open` calls a write
75
+ * workload makes. Durability is unchanged on win32 (the sync never succeeded
76
+ * there); the on-disk layout is untouched.
77
+ */
78
+ async function fsyncDir(dir: string): Promise<void> {
79
+ if (process.platform === 'win32') return;
80
+ let handle: fs.FileHandle | undefined;
81
+ try {
82
+ handle = await fs.open(dir, 'r');
83
+ await handle.sync();
84
+ } catch {
85
+ // Directory fsync unsupported here — nothing to do.
86
+ } finally {
87
+ if (handle) await handle.close().catch(() => { /* best-effort */ });
88
+ }
89
+ }
@@ -1,7 +1,7 @@
1
1
  import { promises as fs } from 'fs';
2
2
  import * as path from 'path';
3
3
  import type { BlockId, ActionId } from "@optimystic/db-core";
4
- import { KvRawStorage, type RawStoreDriver } from "@optimystic/db-p2p";
4
+ import { KvRawStorage, type RawStoreDriver, type StoreIdentity } from "@optimystic/db-p2p";
5
5
  import { createLogger } from './logger.js';
6
6
  import { atomicWriteFile } from './atomic-write.js';
7
7
 
@@ -40,9 +40,9 @@ function isParseableJson(bytes: Uint8Array): boolean {
40
40
  }
41
41
 
42
42
  /**
43
- * Filesystem {@link RawStoreDriver}: the five logical block-storage stores mapped
44
- * to five subdirectories under `basePath/<blockId>/`
45
- * (`{meta.json,revs/,pend/,actions/,blocks/}`). The directory tree is a
43
+ * Filesystem {@link RawStoreDriver}: the six logical block-storage stores mapped
44
+ * to six paths under `basePath/<blockId>/`
45
+ * (`{meta.json,revs/,pend/,actions/,proofs/,blocks/}`). The directory tree is a
46
46
  * deliberate, human-inspectable/debuggable layout — it is NOT flattened into
47
47
  * encoded-filename KV keys.
48
48
  *
@@ -53,8 +53,44 @@ function isParseableJson(bytes: Uint8Array): boolean {
53
53
  * the legacy raw-colon read fallback + win32 guards, and rename-based promote.
54
54
  */
55
55
  export class FileStoreDriver implements RawStoreDriver {
56
+ private readonly identity: StoreIdentity;
57
+
56
58
  constructor(private readonly basePath: string) {
57
59
  // TODO: use https://www.npmjs.com/package/proper-lockfile to take a lock on the basePath, also introduce explicit dispose pattern
60
+ // The directory this driver is backed by, resolved once here: `path.resolve` is
61
+ // cwd-dependent, and capturing it at construction is the correct reading — two drivers
62
+ // built from the same RELATIVE path under different cwds genuinely address different
63
+ // directories and must not compare equal. An empty basePath resolves to the cwd;
64
+ // nothing special-cases it. (A whitespace-only basePath is NOT the cwd — `path.resolve`
65
+ // is pure string work, so `' '` names a child directory called `' '`.)
66
+ // Lowercased on win32 because Windows paths are case-insensitive: `C:\Foo` and `C:\foo`
67
+ // are one directory and must produce one identity.
68
+ // NOTE: aliases of one directory that this does NOT collapse, and so read as two
69
+ // identities: symlinks, junctions, UNC-versus-mapped-drive spellings, and case-differing
70
+ // spellings on a case-INSENSITIVE non-Windows volume (the default on macOS) — platform is
71
+ // the only signal available synchronously, and case-folding every darwin path would be
72
+ // wrong on a case-sensitive volume. `fs.realpath` resolves all of these, but it is async
73
+ // (this constructor is not) and requires the directory to already exist. Revisit if an
74
+ // alias ever bites. All of these fail in the SAFE direction: a missed alias reports two
75
+ // identities for one directory, so an identity-keyed consumer declines to merge and gets
76
+ // today's behavior.
77
+ // NOTE: the win32 fold is the one branch that can err in the UNSAFE direction — Windows
78
+ // 10+ supports per-directory case sensitivity (`fsutil file setCaseSensitiveInfo`), and
79
+ // on such a directory `X:\p\Foo` and `X:\p\foo` are two directories folded onto ONE
80
+ // identity. That merging consumer now exists — `withReadCache` (db-p2p) shares ONE read
81
+ // cache per identity — so on such a directory the two stores would read through one cache
82
+ // and see each other's blocks, and if the second cache is built directly rather than
83
+ // through that helper, `SharedCachePool.registerStore` refuses it outright (one cache per
84
+ // backing store) and construction throws. Not addressable synchronously either (the flag is a
85
+ // per-directory filesystem query). Revisit if Optimystic ever targets a
86
+ // case-sensitive-enabled Windows directory; until then the fold is right for every
87
+ // ordinary Windows volume.
88
+ const resolved = path.resolve(basePath);
89
+ this.identity = `file:${process.platform === 'win32' ? resolved.toLowerCase() : resolved}`;
90
+ }
91
+
92
+ storeIdentity(): StoreIdentity {
93
+ return this.identity;
58
94
  }
59
95
 
60
96
  // --- metadata ---
@@ -186,6 +222,21 @@ export class FileStoreDriver implements RawStoreDriver {
186
222
  await atomicWriteFile(this.getActionPath(blockId, actionId), value);
187
223
  }
188
224
 
225
+ // --- proofs ---
226
+
227
+ // Keyed by (blockId, rev) like the revisions store, but JSON-valued like the action
228
+ // stores — so it takes the corrupt-content-as-missing guard the revisions store does
229
+ // not, and the filename carries no colon to encode. Deliberately no delete: a proof
230
+ // lives and dies with its revision record (see RawStoreDriver.getProof).
231
+
232
+ async getProof(blockId: BlockId, rev: number): Promise<Uint8Array | undefined> {
233
+ return this.readBytesIfExists(this.getProofPath(blockId, rev), true);
234
+ }
235
+
236
+ async putProof(blockId: BlockId, rev: number, value: Uint8Array): Promise<void> {
237
+ await atomicWriteFile(this.getProofPath(blockId, rev), value);
238
+ }
239
+
189
240
  // --- materialized ---
190
241
 
191
242
  async getMaterialized(blockId: BlockId, actionId: ActionId): Promise<Uint8Array | undefined> {
@@ -234,7 +285,7 @@ export class FileStoreDriver implements RawStoreDriver {
234
285
  // --- optional passthroughs ---
235
286
 
236
287
  async *listBlockIds(): AsyncIterable<BlockId> {
237
- // The block layout is `basePath/<blockId>/{meta.json,revs/,pend/,actions/,blocks/}`
288
+ // The block layout is `basePath/<blockId>/{meta.json,revs/,pend/,actions/,proofs/,blocks/}`
238
289
  // (see getBlockPath), so the direct children of basePath are the per-block directories
239
290
  // and each directory NAME is the blockId (used raw, no encoding). Filter to directories
240
291
  // so a stray file can't be mistaken for a block; `*.tmp` atomic-write orphans live inside
@@ -326,6 +377,10 @@ export class FileStoreDriver implements RawStoreDriver {
326
377
  return path.join(this.getBlockPath(blockId), 'revs', `${rev}.json`);
327
378
  }
328
379
 
380
+ private getProofPath(blockId: BlockId, rev: number): string {
381
+ return path.join(this.getBlockPath(blockId), 'proofs', `${rev}.json`);
382
+ }
383
+
329
384
  // `encoded` controls colon handling: writes and canonical reads use the
330
385
  // percent-encoded filename (encoded = true); the legacy raw-colon fallback
331
386
  // (see readActionScopedBytes) passes encoded = false to reach pre-encode
@@ -408,13 +463,14 @@ export class FileStoreDriver implements RawStoreDriver {
408
463
  * imports keep resolving; the kernel supplies the `IRawStorage` surface and the
409
464
  * driver supplies fs behavior.
410
465
  *
411
- * `listBlockIds`/`getApproximateBytesUsed` are re-declared here as always-present
412
- * (the fs driver always implements them, so the kernel constructor always wires
413
- * them) — the base declares them optional, but every fs consumer relies on them.
466
+ * `listBlockIds`/`getApproximateBytesUsed`/`getStoreIdentity` are re-declared here as
467
+ * always-present (the fs driver always implements them, so the kernel constructor always
468
+ * wires them) — the base declares them optional, but every fs consumer relies on them.
414
469
  */
415
470
  export class FileRawStorage extends KvRawStorage {
416
471
  declare listBlockIds: () => AsyncIterable<BlockId>;
417
472
  declare getApproximateBytesUsed: () => Promise<number>;
473
+ declare getStoreIdentity: () => StoreIdentity;
418
474
 
419
475
  constructor(basePath: string) {
420
476
  super(new FileStoreDriver(basePath));