@engramx/client 0.15.0-rc.3 → 0.16.0-rc.2
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 +255 -26
- package/dist/EngramClient.d.ts +235 -229
- package/dist/EngramClient.js +446 -1247
- package/dist/EngramClient.js.map +1 -1
- package/dist/MarketClient.d.ts +137 -0
- package/dist/MarketClient.js +228 -0
- package/dist/MarketClient.js.map +1 -0
- package/dist/ProfileManager.d.ts +4 -4
- package/dist/SessionManager.d.ts +3 -3
- package/dist/SessionManager.js +1 -1
- package/dist/SessionManager.js.map +1 -1
- package/dist/actionReceipt.d.ts +59 -0
- package/dist/actionReceipt.js +68 -2
- package/dist/actionReceipt.js.map +1 -1
- package/dist/auth.d.ts +16 -0
- package/dist/auth.js +38 -5
- package/dist/auth.js.map +1 -1
- package/dist/certifiedAudit.d.ts +32 -6
- package/dist/certifiedAudit.js +75 -14
- package/dist/certifiedAudit.js.map +1 -1
- package/dist/cli.js +95 -26
- package/dist/cli.js.map +1 -1
- package/dist/encryption.d.ts +26 -12
- package/dist/encryption.js +13 -15
- package/dist/encryption.js.map +1 -1
- package/dist/generated/engram.idl.d.ts +6 -0
- package/dist/generated/engram.idl.js +1366 -0
- package/dist/generated/engram.idl.js.map +1 -0
- package/dist/generated/market.idl.d.ts +6 -0
- package/dist/generated/market.idl.js +557 -0
- package/dist/generated/market.idl.js.map +1 -0
- package/dist/generated/registry.idl.d.ts +6 -0
- package/dist/generated/registry.idl.js +510 -0
- package/dist/generated/registry.idl.js.map +1 -0
- package/dist/idl.d.ts +66 -0
- package/dist/idl.js +227 -0
- package/dist/idl.js.map +1 -0
- package/dist/index.d.ts +12 -18
- package/dist/index.js +54 -9
- package/dist/index.js.map +1 -1
- package/dist/ledgerfsHash.js +1 -1
- package/dist/ledgerfsHash.js.map +1 -1
- package/dist/lineage.js +8 -5
- package/dist/lineage.js.map +1 -1
- package/dist/memoryArchive.d.ts +384 -0
- package/dist/memoryArchive.js +477 -0
- package/dist/memoryArchive.js.map +1 -0
- package/dist/migrate.js +31 -4
- package/dist/migrate.js.map +1 -1
- package/dist/openEngram.d.ts +48 -0
- package/dist/openEngram.js +161 -0
- package/dist/openEngram.js.map +1 -0
- package/dist/pair.d.ts +33 -2
- package/dist/pair.js +56 -9
- package/dist/pair.js.map +1 -1
- package/dist/types.d.ts +244 -307
- package/dist/version.d.ts +8 -0
- package/dist/version.js +45 -0
- package/dist/version.js.map +1 -0
- package/dist/wire.d.ts +76 -0
- package/dist/wire.js +79 -0
- package/dist/wire.js.map +1 -0
- package/package.json +3 -13
- package/dist/bootstrap.d.ts +0 -21
- package/dist/bootstrap.js +0 -71
- package/dist/bootstrap.js.map +0 -1
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { Principal } from '@icp-sdk/core/principal';
|
|
2
|
+
import { type Event as LedgerFsEvent, type Hash } from './ledgerfsHash.js';
|
|
3
|
+
export interface MemoryLogChunkRef {
|
|
4
|
+
hash: Uint8Array;
|
|
5
|
+
size: bigint;
|
|
6
|
+
birthSeq: bigint;
|
|
7
|
+
}
|
|
8
|
+
export interface MemoryLogManifest {
|
|
9
|
+
chunks: MemoryLogChunkRef[];
|
|
10
|
+
totalSize: bigint;
|
|
11
|
+
contentRoot: Uint8Array;
|
|
12
|
+
}
|
|
13
|
+
/** Why an imported entry exists — the pre-ledgerfs migration seam. All five classes. */
|
|
14
|
+
export type MemoryLogImportNote = {
|
|
15
|
+
genesis: {
|
|
16
|
+
boundTo: [] | [Uint8Array];
|
|
17
|
+
};
|
|
18
|
+
} | {
|
|
19
|
+
legacyGap: {
|
|
20
|
+
firstSurviving: bigint;
|
|
21
|
+
};
|
|
22
|
+
} | {
|
|
23
|
+
legacyTruncated: {
|
|
24
|
+
storedBytes: bigint;
|
|
25
|
+
prefixHash: Uint8Array;
|
|
26
|
+
};
|
|
27
|
+
} | {
|
|
28
|
+
legacyDelete: null;
|
|
29
|
+
} | {
|
|
30
|
+
legacyUnreconstructable: {
|
|
31
|
+
contentHash: Uint8Array;
|
|
32
|
+
reason: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/** The operation one log entry records. `condense` and `exported` are store-global. */
|
|
36
|
+
export type MemoryLogOp = {
|
|
37
|
+
append: {
|
|
38
|
+
deltaHash: Uint8Array;
|
|
39
|
+
deltaSize: bigint;
|
|
40
|
+
newSize: bigint;
|
|
41
|
+
};
|
|
42
|
+
} | {
|
|
43
|
+
set: {
|
|
44
|
+
manifest: MemoryLogManifest;
|
|
45
|
+
};
|
|
46
|
+
} | {
|
|
47
|
+
restore: {
|
|
48
|
+
toVersion: bigint;
|
|
49
|
+
manifest: MemoryLogManifest;
|
|
50
|
+
};
|
|
51
|
+
} | {
|
|
52
|
+
tombstone: null;
|
|
53
|
+
} | {
|
|
54
|
+
evict: {
|
|
55
|
+
fromVersion: bigint;
|
|
56
|
+
toVersion: bigint;
|
|
57
|
+
chunkCount: bigint;
|
|
58
|
+
byteCount: bigint;
|
|
59
|
+
evictedRoot: Uint8Array;
|
|
60
|
+
};
|
|
61
|
+
} | {
|
|
62
|
+
condense: {
|
|
63
|
+
fromSeq: bigint;
|
|
64
|
+
toSeq: bigint;
|
|
65
|
+
opCount: bigint;
|
|
66
|
+
opsRoot: Uint8Array;
|
|
67
|
+
headAtBoundary: Uint8Array;
|
|
68
|
+
};
|
|
69
|
+
} | {
|
|
70
|
+
exported: {
|
|
71
|
+
fromSeq: bigint;
|
|
72
|
+
toSeq: bigint;
|
|
73
|
+
opsRoot: Uint8Array;
|
|
74
|
+
authorFilter: [] | [Principal];
|
|
75
|
+
};
|
|
76
|
+
} | {
|
|
77
|
+
imported: MemoryLogImportNote;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* One entry in the engram's single memory log.
|
|
81
|
+
*
|
|
82
|
+
* `path` is carried verbatim, which is why the whole surface is owner-only: a path is inside the
|
|
83
|
+
* entry's hash preimage, so it cannot be redacted for a lesser caller without breaking the very
|
|
84
|
+
* hash the archive exists to prove.
|
|
85
|
+
*/
|
|
86
|
+
export interface MemoryLogEvent {
|
|
87
|
+
seq: bigint;
|
|
88
|
+
path: string;
|
|
89
|
+
version: bigint;
|
|
90
|
+
op: MemoryLogOp;
|
|
91
|
+
/** Attribution — who wrote it. Never authorization. */
|
|
92
|
+
by: Principal;
|
|
93
|
+
/**
|
|
94
|
+
* When the entry was chained, in nanoseconds. ⟨RENAMED 2026-10-05⟩ This said `at`. The engram
|
|
95
|
+
* renamed every wire instant to carry its unit on 2026-10-02 (`at` → `atNs` on this record,
|
|
96
|
+
* `MemoryRangeExport`, `ExportReceiptRow` and `CondenseCheckpointRow`), and the four mirrors in
|
|
97
|
+
* this file kept the old name. `toLedgerFsEvent` then read `e.at`, which a served entry no
|
|
98
|
+
* longer carries, and `sle64(undefined)` throws "TypeError: Cannot convert undefined to a BigInt".
|
|
99
|
+
* So `memoryLogEventHash` and `verifyMemoryArchive` threw on the first real entry. They never
|
|
100
|
+
* returned a wrong verdict, but they could not check a single entry (measured 2026-10-05 with
|
|
101
|
+
* node). The hash contract's own field (`Event.at` in ledgerfsHash.ts) keeps its name, because
|
|
102
|
+
* the hashed body carries the value and never the name.
|
|
103
|
+
*/
|
|
104
|
+
atNs: bigint;
|
|
105
|
+
size: bigint;
|
|
106
|
+
contentRoot: Uint8Array;
|
|
107
|
+
/** Hash of the previous entry under the canonical (non-Candid) encoding. */
|
|
108
|
+
prev: Uint8Array;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* One page of the memory log.
|
|
112
|
+
*
|
|
113
|
+
* `pageCap` is the width of the window the engram actually covered — its clamp on `max`, which
|
|
114
|
+
* sits at 256 rather than the library's 1024. It is DISCLOSED for exactly one reason: a caller
|
|
115
|
+
* that cannot see the cap cannot know whether it has the whole window. Read it, never `max`.
|
|
116
|
+
*
|
|
117
|
+
* ⚠ ⟨STALE 2026-10-05 — measured, not fixed⟩ This envelope no longer mirrors the wire, and the
|
|
118
|
+
* difference goes beyond a field name. 0.16.0 renamed `getMemoryLogPage` to `listMemoryLog`, and it
|
|
119
|
+
* answers `LogPage = { firstAvailableSeq; head; page : { items; total; withheld } }`, so `events`,
|
|
120
|
+
* `totalEvents` and `pageCap` are not served. `assembleMemoryArchive` walks by `pageCap`, and the
|
|
121
|
+
* served page has no field with that meaning. A caller therefore has to adapt `listMemoryLog` into
|
|
122
|
+
* this shape, and the adaptation decides how wide each window really was. That is a design call
|
|
123
|
+
* for the walk, not a rename. It is left open and named in test/wire-mirror.test.ts, which fails
|
|
124
|
+
* once this envelope matches, so the exception cannot outlive the drift. The entries themselves
|
|
125
|
+
* (`MemoryLogEvent`) do mirror the wire.
|
|
126
|
+
*/
|
|
127
|
+
export interface MemoryLogPage {
|
|
128
|
+
events: MemoryLogEvent[];
|
|
129
|
+
/** Entries EVER chained, not the retained count — a condensed prefix never shortens this. */
|
|
130
|
+
totalEvents: bigint;
|
|
131
|
+
/** The floor below which entries are no longer served: a condensed prefix, made visible. */
|
|
132
|
+
firstAvailableSeq: bigint;
|
|
133
|
+
head: Uint8Array;
|
|
134
|
+
pageCap: bigint;
|
|
135
|
+
}
|
|
136
|
+
/** What `exportMemoryRange` writes into the chain and hands back. */
|
|
137
|
+
export interface MemoryExportReceipt {
|
|
138
|
+
/** Chain position of the receipt entry itself — always above every entry it covers. */
|
|
139
|
+
seq: bigint;
|
|
140
|
+
head: Uint8Array;
|
|
141
|
+
fromSeq: bigint;
|
|
142
|
+
toSeq: bigint;
|
|
143
|
+
opsRoot: Uint8Array;
|
|
144
|
+
authorFilter: [] | [Principal];
|
|
145
|
+
/** ⟨RENAMED 2026-10-05⟩ was `at` — see `MemoryLogEvent.atNs`. */
|
|
146
|
+
atNs: bigint;
|
|
147
|
+
}
|
|
148
|
+
/** What `condenseMemoryLog` returns: the checkpoint that replaced the dropped prefix. */
|
|
149
|
+
export interface MemoryCondenseResult {
|
|
150
|
+
seq: bigint;
|
|
151
|
+
head: Uint8Array;
|
|
152
|
+
fromSeq: bigint;
|
|
153
|
+
toSeq: bigint;
|
|
154
|
+
opCount: bigint;
|
|
155
|
+
opsRoot: Uint8Array;
|
|
156
|
+
/** The head attested at the boundary — what a verifier seeds from once the prefix is gone. */
|
|
157
|
+
headAtBoundary: Uint8Array;
|
|
158
|
+
newFirstAvailableSeq: bigint;
|
|
159
|
+
/**
|
|
160
|
+
* SIGNED, and that is the point: a condense drops entries but adds a checkpoint back, so a
|
|
161
|
+
* short condense can cost more history bytes than it frees. A positive delta is a real,
|
|
162
|
+
* representable outcome, not an error.
|
|
163
|
+
*/
|
|
164
|
+
historyBytesDelta: bigint;
|
|
165
|
+
}
|
|
166
|
+
/** A receipt or checkpoint named by a preview, enough to go fetch or explain it. */
|
|
167
|
+
export interface MemoryReceiptRef {
|
|
168
|
+
seq: bigint;
|
|
169
|
+
fromSeq: bigint;
|
|
170
|
+
toSeq: bigint;
|
|
171
|
+
}
|
|
172
|
+
/** What a condense WOULD do, and whether the export gate is open. Reads nothing destructive. */
|
|
173
|
+
export interface MemoryCondensePreview {
|
|
174
|
+
firstAvailableSeq: bigint;
|
|
175
|
+
totalEvents: bigint;
|
|
176
|
+
proposedToSeq: bigint;
|
|
177
|
+
opCountInRange: bigint;
|
|
178
|
+
/** True when an unfiltered receipt already covers the whole proposed prefix. */
|
|
179
|
+
unlocked: boolean;
|
|
180
|
+
coveringReceipt: [] | [MemoryReceiptRef];
|
|
181
|
+
/** The nearest miss, so a refusal says what is still needed rather than only "no". */
|
|
182
|
+
bestUnfilteredReceipt: [] | [MemoryReceiptRef];
|
|
183
|
+
/**
|
|
184
|
+
* Author-filtered receipts seen while scanning. They are counted, never credited: a filtered
|
|
185
|
+
* ops root cannot witness that every entry in the range was served.
|
|
186
|
+
*/
|
|
187
|
+
filteredReceiptsSeen: bigint;
|
|
188
|
+
maxUnlockableToSeq: bigint;
|
|
189
|
+
scannedFromSeq: bigint;
|
|
190
|
+
/** True ⇒ the scan hit its bound; the answer describes what was scanned, not the whole chain. */
|
|
191
|
+
scanTruncated: boolean;
|
|
192
|
+
}
|
|
193
|
+
export interface MemoryExportReceiptRow {
|
|
194
|
+
seq: bigint;
|
|
195
|
+
/** ⟨RENAMED 2026-10-05⟩ was `at` — see `MemoryLogEvent.atNs`. */
|
|
196
|
+
atNs: bigint;
|
|
197
|
+
by: Principal;
|
|
198
|
+
fromSeq: bigint;
|
|
199
|
+
toSeq: bigint;
|
|
200
|
+
opsRoot: Uint8Array;
|
|
201
|
+
authorFilter: [] | [Principal];
|
|
202
|
+
}
|
|
203
|
+
export interface MemoryCheckpointRow {
|
|
204
|
+
seq: bigint;
|
|
205
|
+
/** ⟨RENAMED 2026-10-05⟩ was `at` — see `MemoryLogEvent.atNs`. */
|
|
206
|
+
atNs: bigint;
|
|
207
|
+
by: Principal;
|
|
208
|
+
fromSeq: bigint;
|
|
209
|
+
toSeq: bigint;
|
|
210
|
+
opCount: bigint;
|
|
211
|
+
opsRoot: Uint8Array;
|
|
212
|
+
headAtBoundary: Uint8Array;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* How many log entries one assembled archive may span.
|
|
216
|
+
*
|
|
217
|
+
* A `#set` entry carries a full manifest, and maxFileBytes / chunkSize = 10 MiB / 256 KiB caps a
|
|
218
|
+
* manifest at 40 chunk references (src/engram/LedgerFsInit.mo) — several kilobytes of decoded JS
|
|
219
|
+
* objects for a single entry. Ten thousand of those is already past what a browser tab should
|
|
220
|
+
* hold, and an owner who runs out of memory mid-walk gets no archive AND no receipt.
|
|
221
|
+
*
|
|
222
|
+
* The ceiling is on the RANGE WIDTH, not on the entries kept, so an author-filtered archive is
|
|
223
|
+
* bounded by the same number: the range is what drives the round trips, and the range is what a
|
|
224
|
+
* receipt attests. Splitting costs nothing — each part gets its own receipt, and condense needs
|
|
225
|
+
* only one receipt covering the prefix it drops.
|
|
226
|
+
*/
|
|
227
|
+
export declare const ARCHIVE_MAX_RANGE = 10000n;
|
|
228
|
+
/**
|
|
229
|
+
* Entries requested per page before any clamp.
|
|
230
|
+
*
|
|
231
|
+
* Set to the engram's own cap (`MemoryRouter.LOG_PAGE_MAX`, 256) so a full page is never left
|
|
232
|
+
* half-used — the engram clamps the ask to that number anyway and reports the result as
|
|
233
|
+
* `pageCap`. Asking for the cap is safe rather than optimistic because the fallback below it is
|
|
234
|
+
* real: a page that will not fit is retried at half the size, and a walk that had to shrink says
|
|
235
|
+
* so through `smallestPageUsed`.
|
|
236
|
+
*/
|
|
237
|
+
export declare const ARCHIVE_PAGE_EVENTS = 256n;
|
|
238
|
+
/**
|
|
239
|
+
* A decoded log entry in the form the frozen hash contract operates on.
|
|
240
|
+
*
|
|
241
|
+
* The store-global sentinel substitution (`#condense`/`#exported` hash with an empty path, zero
|
|
242
|
+
* version, zero size and a zero content root) is NOT applied here — ledgerfsHash owns it, in the
|
|
243
|
+
* one place the Motoko encoder is mirrored. Doing it twice is how the two drift.
|
|
244
|
+
*/
|
|
245
|
+
export declare function toLedgerFsEvent(e: MemoryLogEvent): LedgerFsEvent;
|
|
246
|
+
/** The canonical hash of one log entry, recomputed from its decoded fields. */
|
|
247
|
+
export declare const memoryLogEventHash: (e: MemoryLogEvent) => Hash;
|
|
248
|
+
/**
|
|
249
|
+
* Fetches one page.
|
|
250
|
+
*
|
|
251
|
+
* The caller supplies it, and after 2026-08-17 that is the only way it arrives: `EngramClient`
|
|
252
|
+
* used to carry a `getMemoryLogPage` wrapper that satisfied this shape, and the charter diet
|
|
253
|
+
* removed it — `getMemoryLogPage` is owner-only on the canister and the class is the agent SDK.
|
|
254
|
+
* Nothing about the WALK changed. An owner tool passes its own authenticated actor's
|
|
255
|
+
* `getMemoryLogPage` here and gets the same paging, the same halving on an over-large response,
|
|
256
|
+
* and the same refusal to return a short archive; the tests pass their own fetcher and always did.
|
|
257
|
+
*
|
|
258
|
+
* ⟨CORRECTED 2026-10-05⟩ An owner tool can no longer pass the actor's method straight in. 0.16.0
|
|
259
|
+
* serves `listMemoryLog`, not `getMemoryLogPage`, and its reply is not a `MemoryLogPage` (see the
|
|
260
|
+
* note there). Until the walk is adapted, a fetcher has to translate the served page into this
|
|
261
|
+
* shape. That translation is open, not done.
|
|
262
|
+
*/
|
|
263
|
+
export type MemoryLogPageFetcher = (startSeq: bigint, max: bigint, authorFilter?: Principal) => Promise<MemoryLogPage>;
|
|
264
|
+
export interface AssembleArchiveOptions {
|
|
265
|
+
/** Default: the engram's retained floor, learned from the first page. */
|
|
266
|
+
fromSeq?: bigint | number;
|
|
267
|
+
/** Default: the last entry ever chained, learned from the first page. */
|
|
268
|
+
toSeq?: bigint | number;
|
|
269
|
+
/** Restrict to one author. A filtered archive can only be checked against a filtered receipt. */
|
|
270
|
+
authorFilter?: Principal;
|
|
271
|
+
/** Starting page size. Only ever shrinks from here — never grows toward `pageCap`. */
|
|
272
|
+
pageEvents?: bigint | number;
|
|
273
|
+
/** Lower the range ceiling for this call. Values above {@link ARCHIVE_MAX_RANGE} are clamped. */
|
|
274
|
+
maxRange?: bigint | number;
|
|
275
|
+
}
|
|
276
|
+
export interface MemoryArchive {
|
|
277
|
+
/** Entries in ascending seq order, deduplicated. */
|
|
278
|
+
events: MemoryLogEvent[];
|
|
279
|
+
fromSeq: bigint;
|
|
280
|
+
toSeq: bigint;
|
|
281
|
+
authorFilter: Principal | null;
|
|
282
|
+
totalEvents: bigint;
|
|
283
|
+
firstAvailableSeq: bigint;
|
|
284
|
+
/** The engram's chain head as of the last page fetched. */
|
|
285
|
+
head: Uint8Array;
|
|
286
|
+
/** The cap the engram disclosed on the last page. */
|
|
287
|
+
pageCap: bigint;
|
|
288
|
+
pagesFetched: number;
|
|
289
|
+
/**
|
|
290
|
+
* The smallest page size the walk had to fall back to. Below the requested size ⇒ at least one
|
|
291
|
+
* page did not fit in a response and was retried smaller. Surfaced because "it worked, slowly"
|
|
292
|
+
* and "it worked" are different facts about the engram's log.
|
|
293
|
+
*/
|
|
294
|
+
smallestPageUsed: bigint;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Whether a failed page looks like the engram could not fit the response, as opposed to refusing
|
|
298
|
+
* the call.
|
|
299
|
+
*
|
|
300
|
+
* Deliberately STRICT. Halving on every error would spend six round trips turning an
|
|
301
|
+
* authorization refusal into the same refusal, and would report it under a misleading heading;
|
|
302
|
+
* an unmatched error is rethrown with the cursor attached instead. If a new replica wording slips
|
|
303
|
+
* past this, the archive fails LOUDLY — the walk stops and throws — which is the safe direction:
|
|
304
|
+
* the alternative is an archive that is quietly short.
|
|
305
|
+
*/
|
|
306
|
+
export declare function isResponseTooLarge(err: unknown): boolean;
|
|
307
|
+
/**
|
|
308
|
+
* Walk a range of the memory log into one archive, or throw.
|
|
309
|
+
*
|
|
310
|
+
* WHAT IT REFUSES TO DO, in order of how badly each would hurt:
|
|
311
|
+
* - report a short archive as whole (every seq in an unfiltered range is asserted present);
|
|
312
|
+
* - assume it received `max` entries (it advances by the window the engram confirmed via
|
|
313
|
+
* `pageCap`, and by the highest seq actually returned when that is further);
|
|
314
|
+
* - give up on a page the engram could not fit (halves and retries, down to one entry);
|
|
315
|
+
* - start below the retained floor (a condensed prefix is unattestable, so an explicit request
|
|
316
|
+
* for it is refused rather than silently raised);
|
|
317
|
+
* - assemble more than {@link ARCHIVE_MAX_RANGE} entries in one pass.
|
|
318
|
+
*
|
|
319
|
+
* Termination is structural: the cursor advances by at least one seq per successful page, and the
|
|
320
|
+
* page size strictly halves per size failure until it reaches one.
|
|
321
|
+
*/
|
|
322
|
+
export declare function assembleMemoryArchive(fetchPage: MemoryLogPageFetcher, options?: AssembleArchiveOptions): Promise<MemoryArchive>;
|
|
323
|
+
/**
|
|
324
|
+
* The part of a receipt or checkpoint verification needs. Both an `exportMemoryRange` receipt and
|
|
325
|
+
* a `condenseMemoryLog` checkpoint satisfy it — they commit to an ops root over the same
|
|
326
|
+
* construction, which is why one verifier covers both.
|
|
327
|
+
*/
|
|
328
|
+
export interface OpsRootAttestation {
|
|
329
|
+
fromSeq: bigint;
|
|
330
|
+
toSeq: bigint;
|
|
331
|
+
opsRoot: Uint8Array;
|
|
332
|
+
/** Absent or `[]` ⇒ the attestation covers every author in the range. */
|
|
333
|
+
authorFilter?: [] | [Principal];
|
|
334
|
+
}
|
|
335
|
+
export interface MemoryArchiveVerification {
|
|
336
|
+
/** The single question: does this archive reproduce the root the engram committed to? */
|
|
337
|
+
matches: boolean;
|
|
338
|
+
computedOpsRoot: string;
|
|
339
|
+
attestedOpsRoot: string;
|
|
340
|
+
/** Entries the ops root is built over, after applying the attestation's author filter. */
|
|
341
|
+
eventsCovered: number;
|
|
342
|
+
/** Entries the attestation's range implies, when it can be known (unfiltered only). */
|
|
343
|
+
eventsExpected: number | null;
|
|
344
|
+
/** Every seq in the range present exactly once. Only meaningful for an unfiltered attestation. */
|
|
345
|
+
rangeContiguous: boolean;
|
|
346
|
+
/** Each held entry's `prev` equals the recomputed hash of the entry before it. */
|
|
347
|
+
chainLinked: boolean;
|
|
348
|
+
/** Facts found while checking, in the order found. Empty when everything lined up. */
|
|
349
|
+
notes: string[];
|
|
350
|
+
/**
|
|
351
|
+
* Present only on a mismatch. Written to describe the situation without assigning blame — the
|
|
352
|
+
* likeliest causes are on the reader's side, and an owner told "your engram is corrupt" acts on
|
|
353
|
+
* it.
|
|
354
|
+
*/
|
|
355
|
+
explanation: string | null;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Rebuild the ops root over a set of log entries exactly as the engram does: the entries in
|
|
359
|
+
* `[fromSeq, toSeq]` that pass the author filter, in ascending seq order, each hashed with
|
|
360
|
+
* ledgerfsHash and wrapped as an ops leaf.
|
|
361
|
+
*
|
|
362
|
+
* An empty covered set has a DEFINED root — the honest attestation that this author wrote nothing
|
|
363
|
+
* in the range — so it is computed, never special-cased into a failure.
|
|
364
|
+
*/
|
|
365
|
+
export declare function recomputeOpsRoot(events: readonly MemoryLogEvent[], range: {
|
|
366
|
+
fromSeq: bigint;
|
|
367
|
+
toSeq: bigint;
|
|
368
|
+
authorFilter?: [] | [Principal];
|
|
369
|
+
}): {
|
|
370
|
+
root: Hash;
|
|
371
|
+
covered: MemoryLogEvent[];
|
|
372
|
+
};
|
|
373
|
+
/**
|
|
374
|
+
* Check an archive against the receipt (or checkpoint) that attests it.
|
|
375
|
+
*
|
|
376
|
+
* The hashing is ./ledgerfsHash.ts throughout — the file the `ledgerfs-goldens` cross-lock pins
|
|
377
|
+
* against the Motoko encoder. Nothing is reimplemented here, because a second implementation of
|
|
378
|
+
* the hash contract is exactly how an owner ends up being told their evidence is bad when the two
|
|
379
|
+
* copies merely drifted.
|
|
380
|
+
*
|
|
381
|
+
* Never throws on a mismatch: a mismatch is a RESULT to read, and the wording of
|
|
382
|
+
* {@link MemoryArchiveVerification.explanation} deliberately does not accuse the engram.
|
|
383
|
+
*/
|
|
384
|
+
export declare function verifyMemoryArchive(archive: Pick<MemoryArchive, 'events'>, attestation: OpsRootAttestation): MemoryArchiveVerification;
|