tersign 0.3.0 → 0.4.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 CHANGED
@@ -20,14 +20,14 @@
20
20
  No account. No API key. This is the genesis receipt, `seq 1` on the production chain:
21
21
 
22
22
  ```sh
23
- npx tersign verify 0xe5874f1ffe87f0a6dd9eb157730f67b86ee4538b125fe30fcc4e165213dd3fc4 --ledger https://tersign.ai
23
+ npx tersign verify 0xe5874f1ffe87f0a6dd9eb157730f67b86ee4538b125fe30fcc4e165213dd3fc4
24
24
  ```
25
25
 
26
26
  ```text
27
27
  ledger: counter-signed OK (seller tersign-first, seq 1 …) VALID
28
28
  ```
29
29
 
30
- `npx tersign verify <receipt.json | 0xdigest> [--ledger url]` recovers the EIP-712 signature **locally**, then checks the entry against the public chain yours or anyone's. Prefer raw HTTP? The same proof, no CLI:
30
+ `npx tersign verify <receipt.json | 0xdigest> [--ledger url]` recovers the EIP-712 signature **locally**. A bare digest is then checked against the Tersign ledger unless `--ledger` names another; a receipt file verifies offline and touches no chain at all. The ledger consulted is always printed. Prefer raw HTTP? The same proof, no CLI:
31
31
 
32
32
  ```sh
33
33
  curl https://tersign.ai/v1/receipts/0xe5874f1ffe87f0a6dd9eb157730f67b86ee4538b125fe30fcc4e165213dd3fc4/verify
@@ -155,7 +155,7 @@ Full URLs, readable without auth. If you are an agent, start here.
155
155
  | llms.txt | https://raw.githubusercontent.com/tersignhq/tersign-js/main/llms.txt |
156
156
  | Conformance vectors (RFC 8785 + keccak256) | https://github.com/tersignhq/tersign-js/blob/main/test/fixtures/canonical-vectors.json |
157
157
  | Sample compliance record + digests | https://github.com/tersignhq/tersign-js/blob/main/test/fixtures/compliance-record.json |
158
- | Genesis verify | `npx tersign verify 0xe5874f1ffe87f0a6dd9eb157730f67b86ee4538b125fe30fcc4e165213dd3fc4 --ledger https://tersign.ai` |
158
+ | Genesis verify | `npx tersign verify 0xe5874f1ffe87f0a6dd9eb157730f67b86ee4538b125fe30fcc4e165213dd3fc4` |
159
159
 
160
160
  ---
161
161
 
@@ -8,6 +8,6 @@ export declare function envDeps(env?: Record<string, string | undefined>): McpDe
8
8
  * every client; mcp.test.ts pins it against package.json so a release bump can't drift it. */
9
9
  export declare const MCP_SERVER_IDENTITY: {
10
10
  readonly name: "tersign";
11
- readonly version: "0.3.0";
11
+ readonly version: "0.4.2";
12
12
  };
13
13
  export declare function buildServer(deps: McpDeps): McpServer;
@@ -45,7 +45,7 @@ function json(value) {
45
45
  }
46
46
  /** MUST match package.json name/version — the MCP handshake self-reports this identity to
47
47
  * every client; mcp.test.ts pins it against package.json so a release bump can't drift it. */
48
- export const MCP_SERVER_IDENTITY = { name: 'tersign', version: '0.3.0' };
48
+ export const MCP_SERVER_IDENTITY = { name: 'tersign', version: '0.4.2' };
49
49
  export function buildServer(deps) {
50
50
  const server = new McpServer(MCP_SERVER_IDENTITY);
51
51
  server.registerTool('issue_receipt', {
@@ -1,2 +1,3 @@
1
1
  #!/usr/bin/env node
2
- export {};
2
+ /** Where a bare digest is checked when the caller names no ledger. */
3
+ export declare const DEFAULT_LEDGER = "https://tersign.ai";
@@ -4,7 +4,14 @@
4
4
  * the counter-signed hash-chain holds.
5
5
  *
6
6
  * tersign-verify <receipt.json> [--signer 0xseller] [--ledger https://…]
7
- * tersign-verify <0xdigest> --ledger https://…
7
+ * tersign-verify <0xdigest> [--ledger https://…]
8
+ *
9
+ * A bare digest needs a ledger to check against, and with none named it uses the public
10
+ * Tersign ledger — the one the published digests live on — rather than refusing. The
11
+ * ledger actually used is always printed, so a reader can see which chain answered and
12
+ * that the choice was theirs to change. `--ledger` still wins whenever it is given; a
13
+ * receipt FILE with no `--ledger` verifies its signature locally and checks no chain,
14
+ * which is unchanged.
8
15
  */
9
16
  import { readFileSync } from 'node:fs';
10
17
  import { digestOf } from './canonical.js';
@@ -18,28 +25,32 @@ function fail(msg) {
18
25
  console.error(`INVALID: ${msg}`);
19
26
  process.exit(1);
20
27
  }
28
+ /** Where a bare digest is checked when the caller names no ledger. */
29
+ export const DEFAULT_LEDGER = 'https://tersign.ai';
21
30
  const target = process.argv[2];
22
31
  if (!target || target.startsWith('--')) {
23
32
  console.error('usage: tersign-verify <receipt.json | 0xdigest> [--signer 0xaddr] [--ledger url]');
33
+ console.error(` a bare digest checks against ${DEFAULT_LEDGER} unless --ledger names another`);
24
34
  process.exit(2);
25
35
  }
26
36
  const ledger = arg('--ledger');
27
37
  const expectedSigner = arg('--signer');
28
- async function checkLedger(digest) {
29
- if (!ledger)
30
- return;
31
- const res = await fetch(`${ledger.replace(/\/$/, '')}/v1/receipts/${digest}/verify`);
38
+ async function checkLedger(digest, url) {
39
+ const res = await fetch(`${url.replace(/\/$/, '')}/v1/receipts/${digest}/verify`);
32
40
  const body = (await res.json());
41
+ // Name the ledger that answered, always — a verifier that hides which chain it consulted is
42
+ // making the reader take its word for the one fact the check exists to establish. Nothing
43
+ // beyond that: `--ledger` is documented in usage and the README, and the failure path is not
44
+ // the place to advertise the alternative to the thing that just failed.
33
45
  if (!body.found)
34
- fail(`ledger has no record of ${digest}`);
46
+ fail(`no record of ${digest} on the Tersign ledger (${url})`);
35
47
  if (!body.chainOk)
36
48
  fail('ledger record found but the counter-signed hash-chain does NOT verify');
37
- console.log(`ledger: counter-signed OK (seller ${body.sellerId}, seq ${body.seq}, ledger key ${body.ledgerSigner})`);
49
+ console.log(`ledger: ${url}`);
50
+ console.log(` counter-signed OK (seller ${body.sellerId}, seq ${body.seq}, ledger key ${body.ledgerSigner})`);
38
51
  }
39
52
  if (/^0x[0-9a-f]{64}$/i.test(target)) {
40
- if (!ledger)
41
- fail('a bare digest can only be checked against a ledger — pass --ledger');
42
- await checkLedger(target);
53
+ await checkLedger(target, ledger ?? DEFAULT_LEDGER);
43
54
  console.log('VALID');
44
55
  process.exit(0);
45
56
  }
@@ -73,5 +84,9 @@ if (record) {
73
84
  fail('compliance record is bound to a DIFFERENT receipt');
74
85
  console.log(`record: OK (bound to receipt, signer ${rec.signer})`);
75
86
  }
76
- await checkLedger(digest);
87
+ // A receipt FILE carries its own signature, so it verifies with no network at all. Only
88
+ // check a chain when the caller asked for one — defaulting here would turn an offline
89
+ // verification into a silent network call, which is the opposite of the point.
90
+ if (ledger)
91
+ await checkLedger(digest, ledger);
77
92
  console.log('VALID');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tersign",
3
- "version": "0.3.0",
3
+ "version": "0.4.2",
4
4
  "description": "Tersign \u2014 the evidence layer for the agent economy. Counter-signed receipts, agent action records, idempotency enforcement, refunds, disputes, and jury-ready evidence envelopes for x402/agent-commerce sellers.",
5
5
  "license": "MIT",
6
6
  "type": "module",