provident-storeroom 0.0.0-stage → 0.1.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.
Files changed (4) hide show
  1. package/README.md +165 -2
  2. package/index.d.ts +257 -0
  3. package/index.mjs +1849 -0
  4. package/package.json +38 -4
package/README.md CHANGED
@@ -1,3 +1,166 @@
1
- # Temporary Holding Version
1
+ # `provident-storeroom` — the published Node ESM binding for the native Rust store
2
+
3
+ **THE CLAIMED REALM IS `{ Node ESM }` AND NOTHING ELSE** (`A70`, `package.md §1.1`): a consumer `import`s
4
+ this package as an ES module from a Node runtime whose ABI carries a Node-API addon. **Every other realm is
5
+ UNCLAIMED and each owes its declared answer** (`package.md §2`: Node CJS, Electron `main`, Electron
6
+ `preload`, Electron `renderer`, the browser, `worker_threads` and any IPC route). **No other realm is
7
+ described here as supported.**
8
+
9
+ **THE LICENCE OF RECORD IS `AGPL-3.0`** (`DD-43`). It is the repository's own `LICENSE` and no clause of
10
+ this unit changes it. **AND THE LICENCE COPY TRAVELS WITH EVERY ARTEFACT, THIS PACKAGE'S OWN INCLUDED**:
11
+ each of the SIX artefacts — this package and the five platform packages — carries a copy of the
12
+ repository's own `LICENSE` as the licence TEXT travelling with it, copied BYTE-FOR-BYTE at the release's
13
+ own assembly step (`docs/specs/storeroom-publish/contract.md §2.3` item 2; `distribution.md §4.2` item 1 and
14
+ `§4.3` item 2; `PUB-DD-11`; `Q3-5`). **WHAT IS REFUSED IS A SECOND, DRIFTING COPY INSIDE THE TREE**: no
15
+ `LICENSE` byte is written under `bindings/js/` (`§2.3` item 4; `distribution.md §4.3` item 1), so the copy
16
+ is an ARTEFACT-LEVEL fact and not a crate-level file, and this package's `files` allowlist names it
17
+ nowhere — the allowlist is the three entries `§2.1` item 1 fixes and NOTHING ELSE (`Q3-2`). **AND THE COPY
18
+ IS NOT A FIFTH DECLARATION SITE** (`distribution.md §4.2` item 3): the four sites are AUTHORED
19
+ DECLARATIONS ABOUT the licence, while a tarball's own copy is the licence's text travelling with an
20
+ artefact — so the count of SITES stays four and the count of artefacts CARRYING A NOTICE is six.
21
+
22
+ ## The one entry
23
+
24
+ ```js
25
+ import { storeCreate, read, readLiteral, write, delete as remove, rollback, listen, unlisten } from 'provident-storeroom';
26
+ ```
27
+
28
+ **The `exports` map publishes EXACTLY ONE arms-bearing entry — the ESM one** (`package.md §1.3`, `DD-24`):
29
+ there is no wildcard export, no deep import to the addon and no CJS arm. **The addon is reached INTERNALLY
30
+ by the package's own `createRequire`-style step and is not an entry point**: a consumer that spells the
31
+ addon's path directly is outside every clause of this contract.
32
+
33
+ ## The surface
34
+
35
+ **The eight verbs of `surface.md §2` and NOTHING ELSE**, plus the one member of the object `storeCreate`
36
+ returned:
37
+
38
+ | The member | Its answer |
39
+ | --- | --- |
40
+ | `storeCreate(cfg)` | the package's own instance handle — `cfg` carries the store's three declared keys and no fourth |
41
+ | `read(instance, address, tier?)` | a leaf's literal, a branch's assembled value, the empty address's whole register |
42
+ | `readLiteral(instance, address, tier?)` | the same, narrowed to a leaf (`ReadTargetIsBranch` on a branch) |
43
+ | `write(instance, address, tier, value)` | `{op, watched, triggered}` |
44
+ | `delete(instance, address, tier?)` | `{address, tiers, triggered}` |
45
+ | `rollback(instance, opId)` | `{opId, undoneOps, restoredTo}` |
46
+ | `listen(instance, address)` | a fresh opaque handle |
47
+ | `unlisten(instance, handle)` | `undefined` — and a no-op success for every value outside the domain |
48
+ | `instance.register(handle, listener)` | `undefined`; a non-function listener or a handle this instance never minted throws a `TypeError` |
49
+
50
+ **The failure form is ONE** (`surface.md §2.5`, `DD-12`): a THROWN plain object carrying exactly
51
+ `{status, message}` — never an `Error` subclass, never a returned tagged union and never a `Promise`.
52
+ **No `findAddress` is exposed** (`A63`), no `exists` verb exists and no release verb is declared (`A74`).
53
+
54
+ ## The two readings a caller will meet, and the reload rule
55
+
56
+ **A handle MUST NOT be carried across a process reload.** Handle identity is this process's own: a prior
57
+ session's token names no registration of this process, and `unlisten` over it is a no-op success while
58
+ `register` over it is a `TypeError`.
59
+
60
+ **Two file-behaviour readings.** A `delete` and a `rollback` perform no file I/O, so a consumer that deletes
61
+ a `file`-tier version and then constructs a fresh instance over an equal `filePath` sees the removed version
62
+ STAND AGAIN — that re-boot is the store's own declared boot and not a defect. And a `file`-tier `write` that
63
+ fails answers `FileCommitFailed` after the store's own automatic journal rollback has run; the package
64
+ compensates for nothing.
65
+
66
+ ## How the addon is resolved — three rungs, and the covered/uncovered answer
67
+
68
+ **THE ENTRY RESOLVES ITS ARTEFACT IN THE DECLARED ORDER** (`docs/specs/storeroom-publish/resolution.md
69
+ §2`; `docs/specs/storeroom-publish/contract.md §1.1`):
70
+
71
+ 1. **RUNG ONE — THE SCOPED PLATFORM PACKAGE FOR THIS RUNTIME'S KEY.** The entry `require`s THE ONE NAME
72
+ the closed key set declares for the `process.platform` × `process.arch` pair, and no other name. The
73
+ five declared names are
74
+
75
+ **`@auspicion/js-linux-x64-gnu`** · **`@auspicion/js-linux-arm64-gnu`** ·
76
+ **`@auspicion/js-darwin-x64`** · **`@auspicion/js-darwin-arm64`** ·
77
+ **`@auspicion/js-win32-x64-msvc`**
78
+
79
+ — five names, three of them carrying a toolchain suffix (`-gnu` twice, `-msvc` once) and two carrying
80
+ none. **The name is SELECTED from this table and is never built by concatenating tokens**, so no sixth
81
+ name is computed. These five are the registry's own per-target optional dependencies, and this
82
+ package's `optionalDependencies` pins each of them at this package's own version, exactly.
83
+
84
+ 2. **RUNG TWO — THE MODULE-RELATIVE ADDON.** Failing rung one, the entry `require`s
85
+ `build/Release/storeroom_js_binding.node` beside the entry module, constructed from the entry module's
86
+ own location and from no other source — no environment variable, no configuration key, no path
87
+ relative to the working directory and no search of a parent directory.
88
+
89
+ 3. **RUNG THREE — THE DECLARED ABSENT-ADDON FORM.** Failing rung two, the load path answers the single
90
+ failure form, and no instance is returned.
91
+
92
+ **IN A PUBLISHED INSTALL, RUNG ONE IS THE RUNG THAT FIRES**, because rung two's path is the checkout's
93
+ own and a `files`-restricted tarball does not carry it — **no binary ships IN THIS PACKAGE'S OWN TARBALL,
94
+ at any key, on any target** (`§2.1` item 1; `Q3-2`). **AND THE FIVE PLATFORM ARTEFACTS EACH CARRY THEIR OWN
95
+ TARGET'S BINARY**: each one's allowlist names the `.node` beside its manifest, which is what gives rung one
96
+ a declared source to load at that key at all (`PAR-PUB-21`; `distribution.md §3.2` item 5). **RUNG TWO IS
97
+ THE CHECKOUT-ONLY RUNG**: it is the in-place developer loop and every battery that exists today, and
98
+ building it is a step of a checkout rather than of an install:
99
+
100
+ ```sh
101
+ cargo build --release --manifest-path bindings/js/Cargo.toml --offline
102
+ mkdir -p bindings/js/build/Release
103
+ cp bindings/js/target/release/libstoreroom_js_binding.so bindings/js/build/Release/storeroom_js_binding.node
104
+ ```
105
+
106
+ **No binary is ever committed** (`package.md §3.2`): `build/` and `target/` are ignored, and the artefacts
107
+ are built and published, never stored in the tree. **The prebuild matrix is five targets** (`linux-x64`,
108
+ `linux-arm64`, `darwin-x64`, `darwin-arm64`, `win32-x64`), built one runner per target by the release's own
109
+ workflow, `/.github/workflows/publish.yml`. The Node-API version this addon is built against is the sibling
110
+ crate's own build target and is not a JS-side floor of this package's own (`package.md §1.4`).
111
+
112
+ **AND THE UNCOVERED-TARGET ANSWER IS A DECLARED LIMITATION, WITH ITS CONSEQUENCE STATED RATHER THAN
113
+ DISCOVERED** (`docs/specs/storeroom-publish/contract.md §2.1` item 3; `docs/specs/storeroom-publish/
114
+ distribution.md §2.2`; `PUB-DD-1`, `PUB-DD-2`):
115
+
116
+ * **A CONSUMER WHOSE `process.platform` × `process.arch` PAIR IS NOT ONE OF THE FIVE COVERED KEYS GETS NO
117
+ BINARY.** Rung one is not attempted at all for that pair — no name exists for it — so the load path
118
+ falls to rung two, which a published install does not carry, and the uncovered consumer therefore meets
119
+ the declared absent-addon form.
120
+ * **THEY GET NO BUILDABLE ROUTE FROM THE TARBALL EITHER: no `build.rs`, no `Cargo.toml`, no `src/**` and
121
+ no `postinstall` build-on-install step is shipped.** The store crate's source is deliberately outside
122
+ this package's allowlist, whose whole content is `index.mjs` · `README.md` · `index.d.ts`.
123
+ * **THEIR ONLY ROUTE IS TO BUILD THE STORE CRATE FROM ITS SOURCE THEMSELVES.** This is a LIMITATION and
124
+ not a promise: no clause of this package claims that an uncovered consumer's route is supported, tested
125
+ or witnessed. **A covered consumer needs NO Rust toolchain; an uncovered consumer needs one.**
126
+ * **AND THE DECLARED ANSWER TO A COVERED KEY WHOSE C LIBRARY DIFFERS FROM ITS ARTEFACT'S IS THE SAME
127
+ ONE**: the `os` and `cpu` fields carry an operating system and an architecture and cannot express a C
128
+ library, so no C library is read, detected or measured anywhere on this load path, and a state that
129
+ follows from that is a state the load path reaches rather than a key of its own.
130
+
131
+ ## Tests
132
+
133
+ ```sh
134
+ cargo test --manifest-path bindings/js/Cargo.toml --offline --no-fail-fast # the sibling crate's Rust tests
135
+ node --test bindings/js/test/*.test.mjs # this package's JS tests
136
+ ```
137
+
138
+ **AND THE ORDER IS A DECLARED STEP, NOT A CONVENIENCE: THE JS LEG RUNS ONLY AFTER THE ADDON IS BUILT**
139
+ (`docs/specs/storeroom-js-proposal.md §17` · `A75`: *"the JS leg of the acceptance layer acquires A BUILD
140
+ STEP (a `.node` must exist for those cells)"*). **The JS cells drive the package through its CLAIMED ESM
141
+ ENTRY and never the `.node` addon directly** (`acceptance.md §4.1` item 1, `DD-18`), so the entry's own
142
+ route — `JS -> facade -> core -> store` — is what they exercise, and that route needs the artefact the
143
+ `Building the addon` section above produces:
144
+
145
+ ```sh
146
+ # 1. THE BUILD STEP, AT THE REPOSITORY ROOT, BEFORE ANY JS CELL RUNS:
147
+ cargo build --release --manifest-path bindings/js/Cargo.toml --offline
148
+ mkdir -p bindings/js/build/Release
149
+ cp bindings/js/target/release/libstoreroom_js_binding.so bindings/js/build/Release/storeroom_js_binding.node
150
+ # 2. THE JS LEG, AFTER IT:
151
+ node --test bindings/js/test/*.test.mjs
152
+ ```
153
+
154
+ **THERE IS NO FALLBACK AND NO JS-SIDE STORE** (`A75`): an addon that is ABSENT or FAILS TO LOAD is a
155
+ **DECLARED FAILURE** — `storeCreate` answers the single failure form
156
+ `{status: 'FilePathUnreachable', message: <the store's own generated string at the addon's path>}` and NO
157
+ instance is returned. **AND THE MESSAGE'S OWN STRING IS NOT A PLACEHOLDER** (`JS-3`, closed): it is the
158
+ store's generator's rendering of THAT subject — `'/abs/path/to/build/Release/storeroom_js_binding.node' is
159
+ not reachable at construction, the path must exist or the application must be able to write it` — reached
160
+ through the addon's `errorMessage` where the artefact loaded far enough to carry the generator, and
161
+ reproduced BYTE-FOR-BYTE from the generator's own clause (`src/error.rs`'s `FilePathUnreachable` arm) where
162
+ the generator is the thing that failed to load. **A consumer that runs the JS cells without step 1 sees that
163
+ failure and not a silently degraded run.** **The Rust leg needs no addon at all**: the conversion core is the
164
+ crate's `rlib` half, so `cargo test --manifest-path bindings/js/Cargo.toml` is drivable with no Node runtime
165
+ present (`package.md §4.1` item 3, `§4.5` item 7).
2
166
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
package/index.d.ts ADDED
@@ -0,0 +1,257 @@
1
+ // `provident-storeroom` — **THE AUTHORED TYPE DECLARATION OF THE PUBLISHED NODE ESM BINDING**
2
+ // (`docs/specs/storeroom-publish/contract.md §2.4`; `docs/specs/storeroom-publish/distribution.md §5`;
3
+ // `PUB-DD-3`; `Q3-4`).
4
+ //
5
+ // **THIS FILE IS HAND-AUTHORED AND NOT GENERATED** (`§2.4` item 1; `PUB-DD-21`): it carries no generation
6
+ // banner, no build-time code generator produces it, and it is the file the package's own `types` field
7
+ // reaches and the package's own `files` allowlist ships.
8
+ //
9
+ // **IT DECLARES THREE THINGS AND NOTHING ELSE** (`distribution.md §5.2`): (1) the EIGHT VERBS of the
10
+ // claimed ESM entry, exactly as the sibling directory enumerates them and with NO ninth name; (2) the
11
+ // instance's own member set, `{ register, on, off }` — three own members and nothing else; and (3) the
12
+ // failure surface, a thrown plain object with exactly `{status, message}`.
13
+ //
14
+ // **AND THE RECORDS THOSE VERBS ANSWER WITH ARE DECLARED BESIDE THEM, WHICH IS STILL PART (1) AND NOT A
15
+ // FOURTH THING**: `Address` · `Tier` · `TierSet` · `StoreConfig` · `BaseState` · `JournalOp` ·
16
+ // `WriteRecord` · `DeleteRecord` · `RollbackRecord` · `Handle` · `Listener` are the SHAPES OF THE
17
+ // ARGUMENTS AND OF THE ANSWERS, in `DD-39`'s own member spellings (the sibling directory's `contract.md
18
+ // §0.2`), and a declaration that did not carry them would declare eight names and no surface. **None of
19
+ // them is a STORE type**: no register, no anchor, no tier tree, no journal and no store verb is declared
20
+ // here (`§5.2` item 4).
21
+ //
22
+ // **AND THE ONE THING THIS DECLARATION MUST NOT CARRY, STATED SO THE FINDING RULE IS CHECKABLE**
23
+ // (`distribution.md §5.2` item 4): **it declares NO store type, NO store verb, NO `findAddress`, NO
24
+ // release verb and NO constraint or repair seam** — each of those is a declaration the sibling directory
25
+ // refuses, and a declaration file carrying one would declare a surface the package does not publish.
26
+
27
+ /**
28
+ * A position in the register: the address a verb is called at, as a sequence of path segments.
29
+ *
30
+ * **A SEGMENT IS A `string` (a key) OR A NON-NEGATIVE INTEGER (an index)** — `PAR-JS-5`'s own domain, and the
31
+ * domain the shipped walk admits and the store's own records return. **`readonly string[]` WAS THE SHIPPED
32
+ * DECLARATION AND IS FALSE OF EVERY ADDRESS CARRYING AN INDEX**, so a consumer compiling the lawful
33
+ * `read(instance, ['key', 0])` met a type error on a correct call.
34
+ */
35
+ export type Address = readonly (string | number)[];
36
+
37
+ /**
38
+ * The tier a verb is called at: the store's own persistence tokens.
39
+ *
40
+ * **THE DOMAIN IS THE STORE'S THREE TOKENS — `'mem'` · `'file'` · `'temp'`** (`PAR-JS-6` · `PAR-JS-7` ·
41
+ * `PAR-JS-11`; the store's own tier row). **`'mem' | 'file'` WAS THE SHIPPED DECLARATION AND DROPPED
42
+ * `'temp'`**, mis-typing a lawful third token as a value outside the domain.
43
+ */
44
+ export type Tier = 'mem' | 'file' | 'temp';
45
+
46
+ /**
47
+ * **THE READER'S ARITY, DECLARED BECAUSE IT IS NOT THE WRITER'S** (`PAR-JS-6`; `crossing.md §1.3`'s
48
+ * `TierArg` row 2): on `read` and `readLiteral` a tier is ABSENT, ONE token, or an ARRAY of tokens read as an
49
+ * ANY-MATCH set. **On `write` and `delete` an array is outside the domain — the array spelling is the
50
+ * reader's arity — so those two verbs take the single token `Tier` alone** (`PAR-JS-7` · `PAR-JS-11`).
51
+ */
52
+ export type TierSet = Tier | readonly Tier[];
53
+
54
+ /** The configuration a store is constructed from — the store's three declared keys and no fourth. */
55
+ export interface StoreConfig {
56
+ /** The journal's declared length: a positive integer (`PAR-JS-3`). */
57
+ readonly journalLength: number;
58
+ /**
59
+ * The listeners a construction adopts (`PAR-JS-4`): an array of `{ address, handle }` records, the EMPTY
60
+ * array included.
61
+ *
62
+ * **AND THE KEY IS REQUIRED, NOT OPTIONAL**: an ABSENT `listeners` is the ONE absence the construction
63
+ * does not admit and answers `AddressMalformed` for, so `listeners?` — the shipped spelling — invited a
64
+ * call that can never construct. **The ELEMENT SHAPE IS THE STORE'S TO REFUSE**: a member that is not an
65
+ * `{ address, handle }` record, or whose `handle` is not a plain non-empty `string`, is admitted here and
66
+ * refused by the store's own construction, because the package mints no second refusal for that position.
67
+ */
68
+ readonly listeners: readonly unknown[];
69
+ /** The file the file tier is backed by, where one is declared (`PAR-JS-2`; ABSENT is in domain). */
70
+ readonly filePath?: string;
71
+ }
72
+
73
+ /**
74
+ * **THE STORE'S OWN CLOSED SET OF FAILURE CODES, AS THE TYPE DECLARES IT — A UNION OVER A
75
+ * DECLARED-BUT-OPEN SET** (`contract.md §2.4` item 2; `distribution.md §5.3`; `PUB-DD-3`).
76
+ *
77
+ * **THE FIFTEEN MEMBERS BELOW ARE THE STORE'S OWN, and their membership is the STORE'S to close and
78
+ * never this package's**: this package MINTS NO MEMBER, WIDENS NO SET AND RENAMES NONE
79
+ * (`distribution.md §5.3` item 3).
80
+ *
81
+ * **AND AN UNKNOWN STATUS IS STILL TYPED — THE ESCAPE IS LOAD-BEARING, NOT A LOOSENESS.** The store's set
82
+ * has already moved from fourteen to fifteen members and the store's own park prices a sixteenth, so an
83
+ * immutably-enumerated union would mis-type a LAWFUL refusal the moment the store's set moves
84
+ * (`PUB-DD-3`'s refused alternative). The `(string & {})` arm is what keeps a member the store has added
85
+ * typeable in an installed `0.1.0`, and its absence would be a finding rather than a strictness.
86
+ */
87
+ export type StoreStatus =
88
+ | 'AddressMalformed'
89
+ | 'AddressNotFound'
90
+ | 'LeafHasNoDownstream'
91
+ | 'TierNotFound'
92
+ | 'OutOfDomainTier'
93
+ | 'ParentAnchorMonotonicityViolation'
94
+ | 'ContainerKindConflict'
95
+ | 'ReadTargetIsBranch'
96
+ | 'WriteParentNotLink'
97
+ | 'JournalOpUnknown'
98
+ | 'RollbackCompacted'
99
+ | 'ConstructionArgumentMissing'
100
+ | 'FilePathUnreachable'
101
+ | 'ValueNotAdmitted'
102
+ | 'FileCommitFailed'
103
+ | (string & {});
104
+
105
+ /**
106
+ * **THE SINGLE FAILURE SURFACE** (`contract.md §1.4`; `distribution.md §5.2` item 3): a THROWN plain
107
+ * object carrying exactly `{status, message}` — never an `Error` subclass, never a returned tagged union,
108
+ * never a `Promise` rejection and never a third member. **The status is carried VERBATIM from the store's
109
+ * own closed set and the message is the store's own generated string**; this package mints neither.
110
+ */
111
+ export interface StoreRefusal {
112
+ readonly status: StoreStatus;
113
+ readonly message: string;
114
+ }
115
+
116
+ /** The opaque handle a listener registration is keyed by: the package's own value for one registration. */
117
+ export type Handle = object;
118
+
119
+ /** The caller's listener: any JS function, invoked with the triggering address as its ONE argument. */
120
+ export type Listener = (address: Address) => void;
121
+
122
+ /**
123
+ * **A BASE STATE — THE PRE- AND POST-STATE A JOURNAL OP CARRIES** (`DD-39`: *"`BaseState` → `{ present,
124
+ * value }`"*). **`present` is whether a version stood at the address, and `value` is that version's value
125
+ * where one did — `undefined` where none did**, because the record is the store's own and the package adds
126
+ * no member to it.
127
+ */
128
+ export interface BaseState {
129
+ readonly present: boolean;
130
+ readonly value: unknown;
131
+ }
132
+
133
+ /**
134
+ * **THE STORE'S OWN JOURNAL OP, CROSSED MEMBER FOR MEMBER AND IN THE STORE'S OWN SPELLINGS** — `DD-39`'s
135
+ * eight declared names (`distribution.md §5.2` item 1; `P-PUB-7`): `{ opId, kind, address, tier, before,
136
+ * after, seq, compacted }`.
137
+ *
138
+ * **`opId` IS A `string`** — the store's own op-id domain is a non-empty string (`PAR-JS-9`), and the id a
139
+ * `write` returns is the id a `rollback` takes. **`kind` is the store's own token** (`'write'` and
140
+ * `'delete'` today) **and its membership is the STORE'S to close, so it is typed as `string` and this
141
+ * package mints no union over it.** **`tier` is one of the store's own three tokens, or `null` where the op
142
+ * carries none**; **`seq` is the journal's own sequence number and `compacted` the store's own flag**, each
143
+ * carried verbatim.
144
+ */
145
+ export interface JournalOp {
146
+ readonly opId: string;
147
+ readonly kind: string;
148
+ readonly address: Address;
149
+ readonly tier: Tier | null;
150
+ readonly before: BaseState;
151
+ readonly after: BaseState;
152
+ readonly seq: number;
153
+ readonly compacted: boolean;
154
+ }
155
+
156
+ /**
157
+ * The record a `write` answers: fresh data on every call, never a view of the store's own state.
158
+ *
159
+ * **`op` IS THE STORE'S OWN JOURNAL RECORD AND NOT A NUMBER** (`DD-39`; `P-PUB-7`'s `S-TYPES`): **the shipped
160
+ * declaration read `op: number`, which is false of EVERY value the line returns**, and a consumer compiling
161
+ * `write(i, a, 'mem', v).op.opId` met a type error on a correct call.
162
+ */
163
+ export interface WriteRecord {
164
+ readonly op: JournalOp;
165
+ readonly watched: readonly Address[];
166
+ readonly triggered: readonly Handle[];
167
+ }
168
+
169
+ /** The record a `delete` answers. */
170
+ export interface DeleteRecord {
171
+ readonly address: Address;
172
+ readonly tiers: readonly Tier[];
173
+ readonly triggered: readonly Handle[];
174
+ }
175
+
176
+ /**
177
+ * The record a `rollback` answers (`DD-39`: *"`RollbackResult` → `{ opId, undoneOps, restoredTo }`"*).
178
+ *
179
+ * **ALL THREE MEMBERS WERE MISTYPED BY THE SHIPPED DECLARATION** (`opId: number`, `undoneOps: number`,
180
+ * `restoredTo: number`): **`opId` echoes the id the caller passed, and that id is a `string`** (`PAR-JS-9`'s
181
+ * own unit: *"the `JournalOp.opId` string"*); **`undoneOps` is the LIST of the ids the reversal undid — an
182
+ * ARRAY of those ids, not a count**; and **`restoredTo` is the base state the addressed subtree now stands
183
+ * at**, `{ present, value }`.
184
+ */
185
+ export interface RollbackRecord {
186
+ readonly opId: string;
187
+ readonly undoneOps: readonly string[];
188
+ readonly restoredTo: BaseState;
189
+ }
190
+
191
+ /**
192
+ * **THE INSTANCE `storeCreate` RETURNS — `{ register, on, off }`, THREE OWN MEMBERS AND NOTHING ELSE**
193
+ * (`distribution.md §5.2` item 2). **The instance's own state is released with the instance and by nothing
194
+ * else: none of the three is a release verb.**
195
+ */
196
+ export interface StoreInstance {
197
+ /** Register `listener` under the opaque `handle`, and answer `undefined`. */
198
+ register(handle: Handle, listener: Listener): void;
199
+ /** Register a listener at `address` and answer the fresh opaque handle it is keyed by. */
200
+ on(address: Address, listener: Listener): Handle;
201
+ /** Withdraw the store-side home entry the `handle` names, and answer `undefined`. */
202
+ off(handle: Handle): void;
203
+ }
204
+
205
+ /**
206
+ * Construct a store at `cfg` and answer its instance.
207
+ *
208
+ * **AN ADDON THAT IS ABSENT, THAT FAILS TO LOAD, OR WHOSE OWN `version` DOES NOT MATCH THIS PACKAGE'S
209
+ * VERSION IS A DECLARED REFUSAL AND NEVER A SILENT FALLBACK** (`docs/specs/storeroom-publish/
210
+ * resolution.md §2`, `§5`): **no instance is returned, no JavaScript store is substituted, and the
211
+ * thrown value is the one `StoreRefusal`.** The load path resolves the scoped platform package for this
212
+ * runtime first, this checkout's own module-relative addon second, and answers the declared absent form
213
+ * when neither yields a loadable artefact.
214
+ */
215
+ export function storeCreate(cfg: StoreConfig): StoreInstance;
216
+
217
+ /**
218
+ * Read a leaf's literal, a branch's assembled value, or the empty address's whole register.
219
+ *
220
+ * **`tier` IS THE READER'S ARITY** (`PAR-JS-6`): absent, ONE token, or an ARRAY of tokens read as an
221
+ * ANY-MATCH set — **so the shipped `tier?: Tier` refused, as a type error, a lawful call spelling a set**.
222
+ */
223
+ export function read(instance: StoreInstance, address: Address, tier?: TierSet): unknown;
224
+
225
+ /** The same read, narrowed to a leaf — a branch answers `ReadTargetIsBranch`; `tier` is `TierSet`. */
226
+ export function readLiteral(instance: StoreInstance, address: Address, tier?: TierSet): unknown;
227
+
228
+ /** Write `value` at `address` on `tier` — EXACTLY ONE token, never an array (`PAR-JS-7`). */
229
+ export function write(instance: StoreInstance, address: Address, tier: Tier, value: unknown): WriteRecord;
230
+
231
+ /**
232
+ * Remove the versions the address names, and answer the operation's record.
233
+ *
234
+ * **AND THE NAME IS `delete`, WHICH THIS DECLARATION CANNOT BIND AS AN IDENTIFIER**: `delete` is a RESERVED
235
+ * WORD, so the function is declared as `deleteOp` and EXPORTED under the name the entry publishes —
236
+ * `export { deleteOp as delete }` — exactly as `bindings/js/index.mjs` does on its own side.
237
+ * **`export function delete(…)`, WHICH THE SHIPPED FILE CARRIED, IS NOT A PARSEABLE DECLARATION AT ALL**, so
238
+ * a consumer's compiler read no surface from this file rather than a mis-typed one (`P-PUB-7`; `Q3-4`).
239
+ */
240
+ declare function deleteOp(instance: StoreInstance, address: Address, tier?: Tier): DeleteRecord;
241
+ export { deleteOp as delete };
242
+
243
+ /**
244
+ * Roll the journal back to `opId`, and answer what the rollback restored.
245
+ *
246
+ * **`opId` IS A NON-EMPTY `string` AND NOT A NUMBER** (`PAR-JS-9`'s own unit: *"the `JournalOp.opId`
247
+ * string"*): the shipped `opId: number` both mis-declared the domain — a number is an OUTSIDE value the
248
+ * store answers `AddressMalformed` for — and made the ordinary call `rollback(i, w.op.opId)`, whose id is
249
+ * the string `write` returned, a type error.
250
+ */
251
+ export function rollback(instance: StoreInstance, opId: string): RollbackRecord;
252
+
253
+ /** Begin watching an address, and answer the fresh opaque handle it is keyed by. */
254
+ export function listen(instance: StoreInstance, address: Address): Handle;
255
+
256
+ /** Withdraw a watching, and answer `undefined` — a no-op success for every value outside the domain. */
257
+ export function unlisten(instance: StoreInstance, handle: Handle): void;