@axorum/mcp 0.0.0-stage → 1.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.
package/dist/server.js ADDED
@@ -0,0 +1,439 @@
1
+ /**
2
+ * The MCP server: nine tools over the Axorum agent plane. `submit_intent` moves money,
3
+ * seven reads inform it, and `verify_receipt` checks a signed receipt offline.
4
+ *
5
+ * # What this is for
6
+ *
7
+ * An MCP-capable agent that connects to this server becomes an Axorum-governed spender,
8
+ * with no integration code. It gets a tool that moves money — and it gets it *safely*,
9
+ * because Axorum sits underneath refusing what the policy in force forbids, and recording
10
+ * the refusal. The guardrail is not a prompt asking the model to behave. It is a ledger
11
+ * that will not post what it is not allowed to post.
12
+ *
13
+ * # The tool descriptions are prompts
14
+ *
15
+ * The `description` on each tool is not documentation for a human skimming a table; it is
16
+ * the text a language model reads when deciding whether to call the tool and what to pass
17
+ * it. So each one says when to use the tool, what a refusal means, and what *not* to do —
18
+ * do not retry a refusal, do not follow a `not_primary` redirect. Those sentences are load
19
+ * bearing. They are the difference between a model that adapts to a policy and one that
20
+ * hammers it.
21
+ *
22
+ * @packageDocumentation
23
+ */
24
+ import { createRequire } from "node:module";
25
+ import { AxorumClient, DEFAULT_RETRY_POLICY } from "@axorum/client";
26
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
27
+ import { toDraft } from "./convert.js";
28
+ import { currencyWarningSentence, describeRecord, describeUsage, renderError, renderOutcome, renderResult, renderText, } from "./render.js";
29
+ import { getBalanceShape, getObligationsShape, getReceiptShape, getTransactionShape, getUsageShape, submitIntentShape, verifyReceiptShape, } from "./schemas.js";
30
+ import { VerifyRefusal, verifyReceipt } from "./verify.js";
31
+ /**
32
+ * The server's name and version, as announced to an MCP host.
33
+ *
34
+ * The version is read from this package's own manifest rather than restated here. The
35
+ * literal that used to sit on this line said `0.4.0` while the package was published at
36
+ * a different version — and this is the number every MCP host is told during the
37
+ * handshake, so the drift was visible to every client and to nobody maintaining it.
38
+ * `package.json` sits one level above both `src/` and `dist/`, so the same path resolves
39
+ * whether this module is running from source under vitest or from the published build.
40
+ */
41
+ const manifest = createRequire(import.meta.url)("../package.json");
42
+ export const SERVER_INFO = { name: "axorum", version: manifest.version };
43
+ /**
44
+ * The sentence every tool description repeats, in one place.
45
+ *
46
+ * Deliberate, effective redundancy. A model may see only *one* of these descriptions in
47
+ * the context where it decides to act, so the rule that makes this whole thing safe cannot
48
+ * live in only one of them.
49
+ */
50
+ const REFUSAL_CONTRACT = "A refusal is a NORMAL, successful result, not an error: Axorum judged your intent and " +
51
+ "the policy forbade it, and that refusal is now recorded on the ledger. Read it, adapt, " +
52
+ "and do not retry the same thing hoping for a different answer — you will get the same " +
53
+ "answer. Only a genuine malfunction (bad config, unreachable service) comes back as an error.";
54
+ /**
55
+ * Builds the server, wired to `client`.
56
+ *
57
+ * The client is injectable so the integration suite can point a real one at a real booted
58
+ * service; production passes none and gets one built from `config`.
59
+ */
60
+ export function createServer(config, client) {
61
+ const axorum = client ?? buildClient(config);
62
+ const server = new McpServer(SERVER_INFO, {
63
+ instructions: "Axorum is a deontic financial-control ledger. Submit an intent and it is permitted or " +
64
+ "refused under the policy in force, and either way the outcome is recorded. " +
65
+ REFUSAL_CONTRACT +
66
+ " Money is denominated in integer MINOR units (cents), written as decimal strings for " +
67
+ "exactness. You act as a single agent identity, fixed by this server's configuration; " +
68
+ "there is no way to act as anybody else.",
69
+ });
70
+ registerSubmitIntent(server, axorum, config);
71
+ registerGetActivePolicy(server, axorum);
72
+ registerGetCurrencies(server, axorum);
73
+ registerGetTransaction(server, axorum);
74
+ registerGetObligations(server, axorum);
75
+ registerGetBalance(server, axorum);
76
+ registerGetUsage(server, axorum);
77
+ registerGetReceipt(server, axorum);
78
+ registerVerifyReceipt(server, config);
79
+ return server;
80
+ }
81
+ /** Builds the SDK client from the validated configuration. */
82
+ function buildClient(config) {
83
+ return new AxorumClient(clientOptions(config));
84
+ }
85
+ /**
86
+ * The SDK client's options for the validated configuration. Pure.
87
+ *
88
+ * With failover URLs, `@axorum/client` holds every replica, and a read moves to the next
89
+ * one on a refused connection, a timeout or a `421`, but only under a retry policy. So reads
90
+ * get {@link DEFAULT_RETRY_POLICY}, with at least one send per replica. A submission is sent
91
+ * once, to the replica that last answered, which the policy read `submit_intent` makes
92
+ * first has just found. Without failover URLs no retry policy is set, as before.
93
+ */
94
+ export function clientOptions(config) {
95
+ const replicas = config.failoverUrls.length + 1;
96
+ // Spread rather than assign: `exactOptionalPropertyTypes` will not let a
97
+ // present-but-`undefined` key stand in for an absent one.
98
+ return {
99
+ baseUrl: config.baseUrl,
100
+ // The attestation authenticates the party-scoped reads (get_balance, get_transaction,
101
+ // get_obligations, get_usage); submits carry it inside the envelope. The server acts as
102
+ // exactly one agent, so one attestation credentials the whole client.
103
+ attestation: config.attestation,
104
+ ...(config.timeoutMs === undefined ? {} : { timeoutMs: config.timeoutMs }),
105
+ ...(replicas === 1
106
+ ? {}
107
+ : {
108
+ failoverUrls: config.failoverUrls,
109
+ retry: { ...DEFAULT_RETRY_POLICY, maxAttempts: Math.max(DEFAULT_RETRY_POLICY.maxAttempts, replicas) },
110
+ }),
111
+ };
112
+ }
113
+ /** `submit_intent` — the tool. Everything else here exists to inform a call to this one. */
114
+ function registerSubmitIntent(server, axorum, config) {
115
+ server.registerTool("submit_intent", {
116
+ title: "Submit an intent to the Axorum ledger",
117
+ description: "Propose a financial action to the Axorum ledger. Use this whenever you want to move " +
118
+ "money or perform an action the policy governs. The ledger judges your intent against " +
119
+ "the policy in force and either POSTS it or REFUSES it — and records what it did either " +
120
+ "way.\n\n" +
121
+ REFUSAL_CONTRACT +
122
+ "\n\n" +
123
+ "The result leads with a plain-language verdict line. Read that line first; it tells you " +
124
+ "whether money moved. `posted: true` means the entries are on the ledger. `posted: false` " +
125
+ "means they are not, and the refusal is.\n\n" +
126
+ "Idempotency: the transaction id is the ledger's idempotency key. If a call fails in a way " +
127
+ "that leaves you unsure whether it landed (an unconfirmed commit, a dropped connection), " +
128
+ "re-submitting the SAME intent under the SAME transaction id is safe for at least 24 " +
129
+ "hours: it replays the stored outcome, marked as a REPLAY, rather than posting twice. It " +
130
+ "cannot double-spend. A DIFFERENT intent under an id already used is refused " +
131
+ "(transaction_reused); for a new intent, leave the transaction id out.\n\n" +
132
+ "Amounts are in integer MINOR units (cents, not dollars) written as decimal strings: " +
133
+ '{"minor": "50000", "currency": "USD"} is $500.00. Debits and credits must balance.\n\n' +
134
+ "METERED SPEND IS ONE INTENT, NOT TWO. If this action uses a metered resource — an API " +
135
+ "call, compute-seconds, tokens — put the usage moves on THIS intent, alongside the " +
136
+ "entries: `consume_usage` (you used it), `meter_usage` (it has been measured), " +
137
+ "`bill_usage` (it has been billed for). They commit atomically with the money.\n\n" +
138
+ "The ledger holds them to one rule: 0 <= billed <= metered <= consumed. You may never " +
139
+ "meter more than was consumed (that is phantom usage — claiming to have measured more " +
140
+ "than was used), and you may never bill more than was metered (billing with nothing to " +
141
+ "back it). Breaking either refuses the ENTIRE intent — the journal entries do not post " +
142
+ "either. Under-recognition is fine and normal: consuming now and metering later is a " +
143
+ "lawful state, not something to correct. Use get_usage to see what headroom you have.\n\n" +
144
+ "The rule is checked against the state the intent would LEAVE BEHIND, not the state it " +
145
+ "found. So a NEGATIVE move is lawful whenever the chain still holds afterwards and no " +
146
+ "counter would go below zero — that is how you issue a credit memo or fix an " +
147
+ "over-metering. And because the moves of one intent are judged together, metering more " +
148
+ "in the SAME intent raises what you may bill in it.\n\n" +
149
+ "You do not choose your identity: which agent this server acts as, and what authority it " +
150
+ "holds, come from the operator's configuration, not from you.",
151
+ inputSchema: submitIntentShape,
152
+ }, async (input) => {
153
+ try {
154
+ // `submitPinned` reads the policy in force, pins to it, and re-pins if the policy
155
+ // moved mid-flight — minting the transaction id exactly once, before the first
156
+ // attempt, so every retry inside it is a replay and never a second posting. Every
157
+ // attempt carries the id's mint time as `minted_at_ms`, the same one each time.
158
+ const outcome = await axorum.submitPinned(toDraft(input, config));
159
+ return renderOutcome(outcome);
160
+ }
161
+ catch (error) {
162
+ // A supplied id may already have been sent by an earlier call, so a refusal that
163
+ // recorded nothing speaks for this attempt only: see `Operation`.
164
+ return renderError(error, input.transaction === undefined ? "submit" : "resubmit");
165
+ }
166
+ });
167
+ }
168
+ /** `get_active_policy` — what is in force right now. */
169
+ function registerGetActivePolicy(server, axorum) {
170
+ server.registerTool("get_active_policy", {
171
+ title: "Read the policy in force",
172
+ description: "Return the id of the Axorum policy currently in force, or state that none is. Use it to " +
173
+ "check that the ledger is governed before you propose anything, or to quote the policy id " +
174
+ "to a human when explaining a refusal.\n\n" +
175
+ "No policy in force is a true fact about the ledger, not a failure — but note that an " +
176
+ "intent cannot be submitted while it holds, because there is nothing to judge the intent " +
177
+ "against. An operator has to activate a policy first.\n\n" +
178
+ "This tool does not tell you what the policy SAYS, only which one it is. The way to find " +
179
+ "out whether an action is allowed is to submit it and read the verdict.",
180
+ inputSchema: {},
181
+ }, async () => {
182
+ try {
183
+ const policy = await axorum.activePolicy();
184
+ return policy === null
185
+ ? renderText("No policy is in force on this Axorum ledger. That is a real state, not an error — " +
186
+ "but nothing can be submitted while it holds, because an intent is pinned to the " +
187
+ "policy that judges it. A human operator has to activate a policy.")
188
+ : renderResult(`The policy in force is '${policy}'.`, { policy });
189
+ }
190
+ catch (error) {
191
+ return renderError(error, "read");
192
+ }
193
+ });
194
+ }
195
+ /** `get_currencies` — the currencies an amount may be denominated in. */
196
+ function registerGetCurrencies(server, axorum) {
197
+ server.registerTool("get_currencies", {
198
+ title: "Read the declared currencies",
199
+ description: "Return every currency the ledger's operator has declared, each with its minor-unit " +
200
+ "exponent (2 for USD means an amount of 1050 is $10.50; 6 for USDC means 1050 is " +
201
+ "0.00105 USDC). Use it before you submit an amount in a currency you have not used here " +
202
+ "before, and to convert a human's major-unit figure into the minor units an intent " +
203
+ "carries.\n\n" +
204
+ "An amount in a currency missing from this list is refused before any policy judges it, " +
205
+ "with cause 'undeclared_currency'. Only a human operator can declare a currency.\n\n" +
206
+ "A currency with a `warning` is declared, but the policy in force refuses the listed " +
207
+ "actions in it whatever you submit: every such intent is refused at commit with cause " +
208
+ "'currency_mismatch'. You cannot change that. Pay in a currency with no warning, or hand " +
209
+ "the warning's remedy to a human operator.",
210
+ inputSchema: {},
211
+ }, async () => {
212
+ try {
213
+ const registry = await axorum.currencies();
214
+ const listed = registry.currencies
215
+ .map(({ currency, exponent }) => `${currency} (${exponent} minor-unit digits)`)
216
+ .join(", ");
217
+ const warned = registry.currencies.flatMap(({ currency, warning }) => warning === undefined ? [] : [currencyWarningSentence(currency, warning)]);
218
+ return registry.currencies.length === 0
219
+ ? renderText("No currency is declared on this Axorum ledger, so every amount would be refused. " +
220
+ "A human operator has to declare one first.")
221
+ : renderResult([`The declared currencies are ${listed}.`, ...warned].join(" "), registry);
222
+ }
223
+ catch (error) {
224
+ return renderError(error, "read");
225
+ }
226
+ });
227
+ }
228
+ /** `get_transaction` — the stored record, refusals included. */
229
+ function registerGetTransaction(server, axorum) {
230
+ server.registerTool("get_transaction", {
231
+ title: "Read a transaction back from the ledger",
232
+ description: "Read the stored record for a transaction id. Use it to confirm what a submission actually " +
233
+ "did — above all after a failure that left you unsure whether the intent landed. If the " +
234
+ "record is there, it landed; if the ledger does not know the id, it did not.\n\n" +
235
+ "A recorded refusal is a record like any other and appears here with `posted: false`. " +
236
+ "Finding a refusal is not a failure of this lookup — it is the lookup working, and telling " +
237
+ "you the ledger refused that intent and remembered doing so.\n\n" +
238
+ "This is a read. It never posts anything and is always safe to call.",
239
+ inputSchema: getTransactionShape,
240
+ }, async ({ transaction }) => {
241
+ try {
242
+ const record = await axorum.transaction(transaction);
243
+ return renderResult(describeRecord(transaction, record), record);
244
+ }
245
+ catch (error) {
246
+ return renderError(error, "read");
247
+ }
248
+ });
249
+ }
250
+ /** `get_obligations` — duties a party owes or may perform. */
251
+ function registerGetObligations(server, axorum) {
252
+ server.registerTool("get_obligations", {
253
+ title: "Read your agent's open duties",
254
+ description: "List the open obligations your agent owes or is authorized to perform. Your attestation " +
255
+ "identifies the party. In Axorum a permitted action can CREATE a duty — a verdict of ObligatedPending " +
256
+ "means the entries posted and something is now owed. Use this to see what is outstanding, " +
257
+ "and select its obligation ID in fulfills when proposing the required action.\n\n" +
258
+ "No open duties comes back as an empty list. That is an answer, not an error.\n\n" +
259
+ "The attestation scopes the answer to duties your party owes or may perform. You cannot " +
260
+ "read unrelated duties. The optional `actor` is only an assertion of who you are — pass it " +
261
+ "to be told when you are wrong. This is a read and is always safe to call.",
262
+ inputSchema: getObligationsShape,
263
+ }, async ({ actor }) => {
264
+ try {
265
+ const obligations = await axorum.obligations(actor);
266
+ const who = actor ?? "Your agent";
267
+ const count = obligations.pending.length;
268
+ return renderResult(count === 0
269
+ ? `${who} has no open obligations to owe or perform.`
270
+ : `${who} has ${count === 1 ? "1 open obligation" : `${count} open obligations`}.`, obligations);
271
+ }
272
+ catch (error) {
273
+ return renderError(error, "read");
274
+ }
275
+ });
276
+ }
277
+ /** `get_balance` — an account's net position. */
278
+ function registerGetBalance(server, axorum) {
279
+ server.registerTool("get_balance", {
280
+ title: "Read an account's balance",
281
+ description: "Return an account's net balance in integer MINOR units. Use it to check a position before " +
282
+ "proposing an intent, or to confirm the effect of one that posted.\n\n" +
283
+ "The balance is reported as a decimal STRING, not a number: the ledger's minor units are " +
284
+ "128-bit integers, and a JSON number would silently round a large one. Treat it as exact " +
285
+ 'text. A balance of "50000" in USD is $500.00.\n\n' +
286
+ "A balance is not a permission. A policy may forbid a spend an account could easily cover, " +
287
+ "and permit one it cannot. The only way to find out whether an action is allowed is to " +
288
+ "submit it. This is a read and is always safe to call.\n\n" +
289
+ "Balance reads are OWNER-SCOPED: the service answers only when the attested party owns " +
290
+ "the account. Any other account — owned by someone else, opened with no owner, or not " +
291
+ "existing at all — answers the same 404 unknown_account (fail-closed, and deliberately " +
292
+ "indistinguishable so an account id is never an existence probe).",
293
+ inputSchema: getBalanceShape,
294
+ }, async ({ account }) => {
295
+ try {
296
+ const balance = await axorum.balance(account);
297
+ return renderResult(`Account '${account}' has a net balance of ${balance.balance.toString()} minor units.`, balance);
298
+ }
299
+ catch (error) {
300
+ return renderError(error, "read");
301
+ }
302
+ });
303
+ }
304
+ /** `get_usage` — a metered resource's consumed/metered/billed running totals. */
305
+ function registerGetUsage(server, axorum) {
306
+ server.registerTool("get_usage", {
307
+ title: "Read a usage balance's running totals",
308
+ description: "Return the running totals for one usage balance — how much of a metered resource has " +
309
+ "been CONSUMED, how much of that has been METERED (measured), and how much of that has " +
310
+ "been BILLED. Use it before submitting usage moves, to see how much room you have.\n\n" +
311
+ "The ledger holds these three to one rule: 0 <= billed <= metered <= consumed. The " +
312
+ "result tells you the two headrooms that follow from it — how much consumption you may " +
313
+ "still meter, and how much metering you may still bill. Those are hard limits: a move " +
314
+ "past either is refused, and it takes the whole intent down with it, money entries " +
315
+ "included.\n\n" +
316
+ "A balance that has not reconciled is NOT a problem to fix. Consuming now and metering " +
317
+ "later is the normal shape of metered billing; the totals converge as reconciliation " +
318
+ "catches up. Read the first line of the result — it is the ledger's own plain-English " +
319
+ "narration of the balance, with exact figures.\n\n" +
320
+ "The totals are reported as decimal STRINGS, not numbers: consumption has no ceiling, so " +
321
+ "a busy meter's total can grow past what a JSON number holds exactly. Treat them as " +
322
+ "exact text.\n\n" +
323
+ "Usage reads are OWNER-SCOPED. You can only read a balance your own party owns. A " +
324
+ "balance owned by someone else, one with no owner, and one that does not exist all " +
325
+ "answer with the same 404 unknown_usage — deliberately identical, so that a usage id can " +
326
+ "never be used to probe what exists. If you get that error, do not conclude the balance " +
327
+ "is absent; conclude only that you cannot read it. This is a read and is always safe to " +
328
+ "call.",
329
+ inputSchema: getUsageShape,
330
+ }, async ({ usage }) => {
331
+ try {
332
+ const report = await axorum.usage(usage);
333
+ return renderResult(describeUsage(report), report);
334
+ }
335
+ catch (error) {
336
+ return renderError(error, "read");
337
+ }
338
+ });
339
+ }
340
+ /** `get_receipt` — the signed receipt, fetched for offline verification. */
341
+ function registerGetReceipt(server, axorum) {
342
+ server.registerTool("get_receipt", {
343
+ title: "Fetch a transaction's signed receipt",
344
+ description: "Fetch the SIGNED receipt for a transaction your agent proposed: an " +
345
+ "axorum.evidence.v0 envelope whose base64 payload is the axorum.receipt.v0 facts of " +
346
+ "the applied record — transaction, tick, verdict, posted, policy (with its hash), the " +
347
+ "evidence hashes, and the provenance hash. It is signed by the deployment's key, so a " +
348
+ "third party can verify it OFFLINE with nothing but the deployment's published key " +
349
+ "list; use verify_receipt to run that check here.\n\n" +
350
+ "A refusal's receipt is a first-class receipt (verdict ForbiddenRejected, posted " +
351
+ "false) — signed proof the refusal was recorded.\n\n" +
352
+ "The receipt is re-minted deterministically from the stored record: fetching twice " +
353
+ "yields byte-identical envelopes, and both equal the inline `receipt` the original " +
354
+ "submission's outcome carried. A 503 signing_not_configured / signing_unavailable " +
355
+ "means the deployment does not sign or its signer is down — the transaction itself " +
356
+ "is committed and unaffected. This is a read and is always safe to call.",
357
+ inputSchema: getReceiptShape,
358
+ }, async ({ transaction }) => {
359
+ try {
360
+ const receipt = await axorum.receipt(transaction);
361
+ return renderResult(`Signed receipt for '${transaction}' from deployment '${receipt.deployment}', ` +
362
+ `signed by key ${receipt.key_id}. Verify it offline with verify_receipt.`, receipt);
363
+ }
364
+ catch (error) {
365
+ return renderError(error, "read");
366
+ }
367
+ });
368
+ }
369
+ /** `verify_receipt` — the offline check, in nothing but node:crypto. */
370
+ function registerVerifyReceipt(server, config) {
371
+ server.registerTool("verify_receipt", {
372
+ title: "Verify a signed receipt offline",
373
+ description: "Verify an axorum.evidence.v0 receipt envelope OFFLINE — pure local cryptography, no " +
374
+ "call to the ledger. The check is the full spec/evidence-signing.md flow: the key " +
375
+ "list's own self-signature (so a compromised retired key cannot hide its revocation), " +
376
+ "the receipt's Ed25519 signature with the kind and deployment bound inside the signed " +
377
+ "message, key status (a revoked key fails the whole artifact; a retired one verifies " +
378
+ "with a note), and the receipt's internal contract (justification_hash is the final " +
379
+ "evidence element).\n\n" +
380
+ "Pass verification_keys — the envelope from GET /api/verification-keys.json — that " +
381
+ "you obtained and pinned OUT-OF-BAND for the strongest check; omit it and this server " +
382
+ "fetches the configured deployment's published list for you (trust-on-first-use). " +
383
+ "Pass pinned_generation to refuse a rolled-back key list.\n\n" +
384
+ "A verification FAILURE is an answer, not a malfunction: it means these bytes are " +
385
+ "not what the deployment signed, or the key is not (or no longer) trustworthy. The " +
386
+ "refusal message states which, in the spec's own compliance language.",
387
+ inputSchema: verifyReceiptShape,
388
+ }, async ({ receipt_envelope, verification_keys, pinned_generation }) => {
389
+ try {
390
+ const keys = verification_keys ?? (await fetchPublishedKeys(config.baseUrl));
391
+ const verified = verifyReceipt(receipt_envelope, keys, pinned_generation);
392
+ // The §4 retired-key note names the key id, verbatim.
393
+ const note = verified.keyStatus === "retired"
394
+ ? ` Note: signed by retired key ${verified.keyId}. The signature verifies; the key has since been rotated out.`
395
+ : "";
396
+ return renderResult(`VERIFIED: the receipt is authentic and unaltered under deployment ` +
397
+ `'${verified.deployment}' — verdict ${String(verified.receipt.verdict)}, ` +
398
+ `posted ${String(verified.receipt.posted)}, tick ${verified.tickExact}.` +
399
+ note, verified.receipt);
400
+ }
401
+ catch (error) {
402
+ if (error instanceof KeyListUnavailable) {
403
+ // Could not obtain the key list — not a verification verdict.
404
+ return renderError(error, "read");
405
+ }
406
+ if (error instanceof VerifyRefusal) {
407
+ return renderResult(`VERIFICATION FAILED: ${error.message}`, {
408
+ verified: false,
409
+ reason: error.message,
410
+ });
411
+ }
412
+ return renderError(error, "read");
413
+ }
414
+ });
415
+ }
416
+ /** Could not obtain the key list to verify against — an inability to CHECK,
417
+ * not a verification failure (the receipt might be perfectly valid). Distinct
418
+ * from `VerifyRefusal` so it is never rendered as "VERIFICATION FAILED". */
419
+ class KeyListUnavailable extends Error {
420
+ }
421
+ /** Fetches the deployment's published key-list envelope (the §3.8 surface). */
422
+ async function fetchPublishedKeys(baseUrl) {
423
+ const base = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
424
+ let response;
425
+ try {
426
+ response = await fetch(`${base}/api/verification-keys.json`);
427
+ }
428
+ catch (error) {
429
+ throw new KeyListUnavailable(`the deployment's published key list could not be fetched ` +
430
+ `(${error instanceof Error ? error.message : String(error)}) — supply ` +
431
+ `verification_keys obtained out-of-band`);
432
+ }
433
+ if (!response.ok) {
434
+ throw new KeyListUnavailable(`the deployment's published key list could not be fetched ` +
435
+ `(HTTP ${response.status}) — supply verification_keys obtained out-of-band`);
436
+ }
437
+ return (await response.json());
438
+ }
439
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Offline verification of `axorum.evidence.v0` envelopes — the `verify_receipt`
3
+ * tool's engine, in nothing but `node:crypto`.
4
+ *
5
+ * This is a deliberate second implementation of the verifier the Rust
6
+ * `axorum-evidence` crate ships, built from the committed JSON Schemas
7
+ * (`spec/schemas/`) and `spec/evidence-signing.md` §3.1/§4 alone. It shares no
8
+ * code with the service: an envelope that verifies here has been checked the
9
+ * way a stranger's stack would check it. The refusal sentences are the spec's
10
+ * §4 catalogue, verbatim.
11
+ *
12
+ * The signed message is:
13
+ *
14
+ * ```text
15
+ * "axorum.evidence.v0" || 0x0A || kind || 0x0A || deployment || 0x0A || SHA-256(payload)
16
+ * ```
17
+ *
18
+ * with the deployment and kind *inside* the signed bytes — no artifact
19
+ * transplants across deployments, no signature replays across kinds.
20
+ *
21
+ * @packageDocumentation
22
+ */
23
+ /** The envelope format version this verifier understands. */
24
+ export declare const ENVELOPE_VERSION = "axorum.evidence.v0";
25
+ /** The key-list format version this verifier understands. */
26
+ export declare const KEYS_VERSION = "axorum.keys.v0";
27
+ /** The receipt payload version this verifier understands. */
28
+ export declare const RECEIPT_VERSION = "axorum.receipt.v0";
29
+ /** The closed six-kind artifact vocabulary (`spec/evidence-signing.md` §3.1). */
30
+ export declare const ARTIFACT_KINDS: readonly ["receipt", "evidence-package", "lake-manifest", "lake-head", "oplog-head", "key-list"];
31
+ /** A wire envelope, structurally validated before any cryptography runs. */
32
+ export interface WireEnvelope {
33
+ version: string;
34
+ kind: string;
35
+ deployment: string;
36
+ key_id: string;
37
+ payload: string;
38
+ signature: string;
39
+ }
40
+ /** One key-list entry. */
41
+ interface WireKeyEntry {
42
+ key_id: string;
43
+ public_key: string;
44
+ public_key_pem: string;
45
+ status: "active" | "retired" | "revoked";
46
+ }
47
+ /** The `axorum.keys.v0` list. */
48
+ interface WireKeyList {
49
+ version: string;
50
+ deployment: string;
51
+ generation: number;
52
+ keys: WireKeyEntry[];
53
+ }
54
+ /** A verification refusal, carrying the §4 sentence as its message. */
55
+ export declare class VerifyRefusal extends Error {
56
+ }
57
+ /** Reads and structurally checks a wire envelope from parsed JSON. */
58
+ export declare function readEnvelope(value: unknown): WireEnvelope;
59
+ /** The §3.1 signed message for `(kind, deployment, payload)`. */
60
+ export declare function signedMessage(kind: string, deployment: string, payload: Buffer): Buffer;
61
+ /**
62
+ * Verifies a signed key-list envelope (`kind: key-list`, self-signed by its
63
+ * own active key) and returns the verified list. `pinnedGeneration` refuses a
64
+ * rolled-back list, exactly as the spec's §4 row words it.
65
+ */
66
+ export declare function verifyKeyList(value: unknown, pinnedGeneration?: number): WireKeyList;
67
+ /** What a green check yields: the artifact's identity plus the payload bytes. */
68
+ export interface VerifiedEnvelope {
69
+ kind: string;
70
+ deployment: string;
71
+ keyId: string;
72
+ /** `active` or `retired` — a `retired` pass carries the informational note. */
73
+ keyStatus: "active" | "retired";
74
+ payload: Buffer;
75
+ }
76
+ /**
77
+ * Verifies one envelope against a **verified** key list, with the spec's §4
78
+ * refusal sentences: unknown key, revoked key, deployment mismatch, and the
79
+ * signature itself.
80
+ */
81
+ export declare function verifyEnvelope(value: unknown, list: WireKeyList): VerifiedEnvelope;
82
+ /** The verified receipt facts, plus how the check concluded. */
83
+ export interface VerifiedReceipt {
84
+ /** The deployment whose ledger judged — and signed — the transaction. */
85
+ deployment: string;
86
+ /** `active`, or `retired` (verifies, with the §4 informational note). */
87
+ keyStatus: "active" | "retired";
88
+ /** The signing key's id (for the §4 retired-key note, which names it). */
89
+ keyId: string;
90
+ /** The parsed `axorum.receipt.v0` payload, exactly as signed. */
91
+ receipt: Record<string, unknown>;
92
+ /**
93
+ * The `tick` as its exact decimal string — `tick` is an unsigned 64-bit
94
+ * integer (`spec/schemas/axorum.receipt.v0.schema.json`), so a busy ledger's
95
+ * value can exceed what `JSON.parse` holds without rounding. Read from the
96
+ * raw signed bytes, so it is always exact; the `receipt.tick` field may be a
97
+ * rounded `number` above 2^53.
98
+ */
99
+ tickExact: string;
100
+ }
101
+ /**
102
+ * The whole `axorum verify` flow for one receipt, offline: verify the key
103
+ * list (self-signed, generation-pinned), verify the receipt envelope against
104
+ * it, parse and cross-check the payload. Throws {@link VerifyRefusal} with
105
+ * the spec's §4 sentence on any failure.
106
+ */
107
+ export declare function verifyReceipt(receiptEnvelope: unknown, keyListEnvelope: unknown, pinnedGeneration?: number): VerifiedReceipt;
108
+ export {};
109
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAOH,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,uBAAuB,CAAC;AAErD,6DAA6D;AAC7D,eAAO,MAAM,YAAY,mBAAmB,CAAC;AAE7C,6DAA6D;AAC7D,eAAO,MAAM,eAAe,sBAAsB,CAAC;AAEnD,iFAAiF;AACjF,eAAO,MAAM,cAAc,kGAOjB,CAAC;AAKX,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,0BAA0B;AAC1B,UAAU,YAAY;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;CAC1C;AAED,iCAAiC;AACjC,UAAU,WAAW;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,YAAY,EAAE,CAAC;CACtB;AAED,uEAAuE;AACvE,qBAAa,aAAc,SAAQ,KAAK;CAAG;AAuB3C,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CA0BzD;AAWD,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAQvF;AAkFD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,WAAW,CAuCpF;AAED,iFAAiF;AACjF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,SAAS,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,gBAAgB,CAqClF;AAED,gEAAgE;AAChE,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,SAAS,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC;;;;;;OAMG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAQD;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,eAAe,EAAE,OAAO,EACxB,eAAe,EAAE,OAAO,EACxB,gBAAgB,CAAC,EAAE,MAAM,GACxB,eAAe,CAkCjB"}