@orangecheck/stamp-cli 0.1.0 → 0.2.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
@@ -30,7 +30,8 @@ $ stamp canonical blogpost.md --addr bc1qalice...
30
30
  # Verify a stamp:
31
31
  $ stamp verify blogpost.md.stamp blogpost.md --require-anchor
32
32
 
33
- # Retry anchoring on an existing stamp:
33
+ # Anchor an existing stamp, or upgrade its pending proof once the
34
+ # calendars have reached a block (rewrites the .stamp only on change):
34
35
  $ stamp anchor blogpost.md.stamp
35
36
  ```
36
37
 
@@ -62,12 +63,20 @@ $ stamp verify blogpost.md.stamp blogpost.md --json
62
63
  "content_mime": "text/markdown",
63
64
  "content_length": 12843,
64
65
  "content_checked": true,
65
- "anchor": "confirmed at block 890123",
66
+ "anchor": "confirmed at block 890123 (checked against the block header)",
67
+ "anchor_state": "anchored",
66
68
  "signature_checked": true,
67
69
  "stake": null
68
70
  }
69
71
  ```
70
72
 
73
+ A confirmed anchor is checked per SPEC §6.3: the proof must commit to the
74
+ stamp id, and the block header at the claimed height (from
75
+ `--headers-url`, default `https://mempool.space/api`) must hash to the claimed
76
+ block hash and carry the proof's Merkle root. A proof that does not chain
77
+ exits 2 with `E_BAD_ANCHOR`. If no header can be fetched the claim is reported
78
+ as unverified, and `--require-anchor` fails.
79
+
71
80
  On failure, exits `2` with an error code:
72
81
 
73
82
  ```
package/dist/cli.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
+ import { submitToCalendars, toStampOts, mempoolHeaderSource, makeAnchorVerifier, upgradeProof, fromStampOts } from '@orangecheck/stamp-ots';
2
3
  import { createHash } from 'crypto';
3
4
  import { mkdir, writeFile, stat, readFile } from 'fs/promises';
4
5
  import { basename } from 'path';
5
6
  import { canonicalMessage, stamp, verify } from '@orangecheck/stamp-core';
6
7
  import { Command } from 'commander';
7
- import { submitToCalendars, toStampOts } from '@orangecheck/stamp-ots';
8
8
  import { execFile } from 'child_process';
9
9
  import { promisify } from 'util';
10
10
  import { createInterface } from 'readline/promises';
@@ -18,6 +18,42 @@ var __export = (target, all) => {
18
18
  for (var name in all)
19
19
  __defProp(target, name, { get: all[name], enumerable: true });
20
20
  };
21
+ async function checkAnchorClaim(env, headers) {
22
+ const ots = env.ots;
23
+ if (!ots) return { state: "none" };
24
+ if (ots.status !== "confirmed" || ots.block_height === null || !ots.block_hash) {
25
+ return { state: "pending" };
26
+ }
27
+ const blockHeight = ots.block_height;
28
+ let header = null;
29
+ try {
30
+ header = await headers.getHeaderAt(blockHeight);
31
+ } catch {
32
+ header = null;
33
+ }
34
+ if (!header) {
35
+ return { state: "unverified", blockHeight, message: "block header source unreachable" };
36
+ }
37
+ const verify2 = makeAnchorVerifier({ headerSource: { getHeaderAt: async () => header } });
38
+ const ok = await verify2(ots.proof, blockHeight, ots.block_hash, env.id);
39
+ return ok ? { state: "anchored", blockHeight } : { state: "fail", blockHeight, message: `OTS proof does not chain to block ${blockHeight}` };
40
+ }
41
+ async function advanceOts(env, opts) {
42
+ if (!env.ots) {
43
+ const proof = await submitToCalendars(env.id, { fetch: opts.fetch });
44
+ return { ...env, ots: toStampOts(proof) };
45
+ }
46
+ if (env.ots.status === "confirmed") return env;
47
+ const next = await upgradeProof(fromStampOts(env.ots), env.id, {
48
+ headerSource: opts.headers,
49
+ fetch: opts.fetch
50
+ });
51
+ return { ...env, ots: toStampOts(next) };
52
+ }
53
+ var init_anchor_check = __esm({
54
+ "src/anchor-check.ts"() {
55
+ }
56
+ });
21
57
  async function readBytes(path) {
22
58
  const buf = await readFile(path);
23
59
  return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
@@ -154,12 +190,20 @@ async function runVerify(opts) {
154
190
  });
155
191
  process.exit(2);
156
192
  }
157
- const anchorLabel = r.anchor.status === "none" ? "none" : r.anchor.status === "pending" ? "pending" : `confirmed at block ${r.anchor.blockHeight}`;
158
- if (opts.requireAnchor && r.anchor.status !== "confirmed") {
193
+ const anchor = await checkAnchorClaim(
194
+ envelope,
195
+ mempoolHeaderSource({ baseUrl: opts.headersUrl })
196
+ );
197
+ if (anchor.state === "fail") {
198
+ emit(opts.json, { ok: false, code: "E_BAD_ANCHOR", message: anchor.message });
199
+ process.exit(2);
200
+ }
201
+ const anchorLabel = anchor.state === "anchored" ? `confirmed at block ${anchor.blockHeight} (checked against the block header)` : anchor.state === "unverified" ? `claims block ${anchor.blockHeight}, unverified: ${anchor.message}` : anchor.state;
202
+ if (opts.requireAnchor && anchor.state !== "anchored") {
159
203
  emit(opts.json, {
160
204
  ok: false,
161
205
  code: "E_NO_ANCHOR",
162
- message: `required confirmed OTS anchor, got ${r.anchor.status}`
206
+ message: `required a verified OTS anchor, got ${anchor.state}`
163
207
  });
164
208
  process.exit(2);
165
209
  }
@@ -173,17 +217,20 @@ async function runVerify(opts) {
173
217
  content_length: envelope.content.length,
174
218
  content_checked: Boolean(contentBytes),
175
219
  anchor: anchorLabel,
220
+ anchor_state: anchor.state,
176
221
  signature_checked: !opts.skipSignature,
177
222
  stake: envelope.stake
178
223
  });
179
224
  }
180
225
  var init_verify = __esm({
181
226
  "src/commands/verify.ts"() {
227
+ init_anchor_check();
182
228
  init_util();
183
229
  }
184
230
  });
185
231
 
186
232
  // src/commands/anchor.ts
233
+ init_anchor_check();
187
234
  init_util();
188
235
  async function runAnchor(opts) {
189
236
  if (!await pathExists(opts.stampPath)) die(`no such file: ${opts.stampPath}`);
@@ -196,20 +243,26 @@ async function runAnchor(opts) {
196
243
  });
197
244
  return;
198
245
  }
246
+ let next;
199
247
  try {
200
- const proof = await submitToCalendars(envelope.id);
201
- const next = { ...envelope, ots: toStampOts(proof) };
202
- await writeFile(opts.stampPath, JSON.stringify(next, null, 2) + "\n", "utf8");
203
- emit(opts.json, {
204
- ok: true,
205
- id: next.id,
206
- status: next.ots?.status,
207
- calendars: next.ots?.calendars ?? [],
208
- written: opts.stampPath
248
+ next = await advanceOts(envelope, {
249
+ headers: mempoolHeaderSource({ baseUrl: opts.headersUrl })
209
250
  });
210
251
  } catch (e) {
211
- die(`OTS submission failed: ${e instanceof Error ? e.message : String(e)}`);
252
+ die(`OTS ${envelope.ots ? "upgrade" : "submission"} failed: ${e instanceof Error ? e.message : String(e)}`);
212
253
  }
254
+ const changed = JSON.stringify(next.ots) !== JSON.stringify(envelope.ots);
255
+ if (changed) {
256
+ await writeFile(opts.stampPath, JSON.stringify(next, null, 2) + "\n", "utf8");
257
+ }
258
+ emit(opts.json, {
259
+ ok: true,
260
+ id: next.id,
261
+ status: next.ots?.status,
262
+ block_height: next.ots?.block_height ?? null,
263
+ calendars: next.ots?.calendars ?? [],
264
+ written: changed ? opts.stampPath : null
265
+ });
213
266
  }
214
267
 
215
268
  // src/commands/git-tag.ts
@@ -389,7 +442,7 @@ init_util();
389
442
  var invoked = basename(process.argv[1] ?? "stamp");
390
443
  var program = new Command();
391
444
  if (invoked.startsWith("git-stamp")) {
392
- program.name("git-stamp").description("Stamp git tags with your Bitcoin address, anchored to Bitcoin.").version("0.1.0");
445
+ program.name("git-stamp").description("Stamp git tags with your Bitcoin address, anchored to Bitcoin.").version("0.2.0");
393
446
  program.command("tag <tagname>").description("Sign and (optionally) anchor a stamp over <tagname>^{tree}").requiredOption("--addr <address>", "Bitcoin address").option("--sig <signature>", "BIP-322 signature (non-interactive mode)").option("--no-anchor", "Skip OTS calendar submission").option("--json", "Emit JSON").action(async (tag, opts) => {
394
447
  await runGitTag({
395
448
  tag,
@@ -399,7 +452,7 @@ if (invoked.startsWith("git-stamp")) {
399
452
  json: Boolean(opts.json)
400
453
  });
401
454
  });
402
- program.command("verify <tagname>").description("Verify the stamp stored under .git/stamps/<tagname>.stamp").option("--require-anchor", "Fail unless the OTS proof is confirmed").option("--json", "Emit JSON").action(async (tag, opts) => {
455
+ program.command("verify <tagname>").description("Verify the stamp stored under .git/stamps/<tagname>.stamp").option("--require-anchor", "Fail unless the OTS anchor is confirmed and checked against the block header").option("--json", "Emit JSON").action(async (tag, opts) => {
403
456
  await runGitVerify({
404
457
  tag,
405
458
  requireAnchor: Boolean(opts.requireAnchor),
@@ -407,7 +460,7 @@ if (invoked.startsWith("git-stamp")) {
407
460
  });
408
461
  });
409
462
  } else {
410
- program.name("stamp").description("OC Stamp \u2014 sign anything with your Bitcoin address, anchor to Bitcoin.").version("0.1.0");
463
+ program.name("stamp").description("OC Stamp \u2014 sign anything with your Bitcoin address, anchor to Bitcoin.").version("0.2.0");
411
464
  program.command("file <path>").description("Sign a file and write <path>.stamp alongside").requiredOption("--addr <address>", "Bitcoin address").option("--mime <type>", "Override the MIME type (default: inferred from extension)").option("--signed-at <iso>", "Override signed_at (default: now)").option("--sig <signature>", "BIP-322 signature (non-interactive mode)").option("--no-anchor", "Skip OTS calendar submission").option("--out <path>", "Output path (default: <path>.stamp)").option("--json", "Emit JSON").action(async (path, opts) => {
412
465
  await runStampFile({
413
466
  path,
@@ -420,17 +473,18 @@ if (invoked.startsWith("git-stamp")) {
420
473
  json: Boolean(opts.json)
421
474
  });
422
475
  });
423
- program.command("verify <stamp> [content]").description("Run the full SPEC \xA78 verification").option("--require-anchor", "Fail unless the OTS proof is confirmed").option("--skip-signature", "Skip BIP-322 verification (for CI smoke tests only)").option("--json", "Emit JSON").action(async (stampPath, contentPath, opts) => {
476
+ program.command("verify <stamp> [content]").description("Run the full SPEC \xA78 verification").option("--require-anchor", "Fail unless the OTS anchor is confirmed and checked against the block header").option("--skip-signature", "Skip BIP-322 verification (for CI smoke tests only)").option("--headers-url <url>", "Esplora API for block headers (default: https://mempool.space/api)").option("--json", "Emit JSON").action(async (stampPath, contentPath, opts) => {
424
477
  await runVerify({
425
478
  stampPath,
426
479
  contentPath,
427
480
  requireAnchor: Boolean(opts.requireAnchor),
428
481
  skipSignature: Boolean(opts.skipSignature),
482
+ headersUrl: opts.headersUrl,
429
483
  json: Boolean(opts.json)
430
484
  });
431
485
  });
432
- program.command("anchor <stamp>").description("Submit an existing stamp envelope to OTS calendars").option("--json", "Emit JSON").action(async (stampPath, opts) => {
433
- await runAnchor({ stampPath, json: Boolean(opts.json) });
486
+ program.command("anchor <stamp>").description("Submit a stamp to OTS calendars, or upgrade its pending proof").option("--headers-url <url>", "Esplora API for block headers (default: https://mempool.space/api)").option("--json", "Emit JSON").action(async (stampPath, opts) => {
487
+ await runAnchor({ stampPath, headersUrl: opts.headersUrl, json: Boolean(opts.json) });
434
488
  });
435
489
  program.command("canonical <path>").description("Print the canonical message a stamp over <path> would sign (dry run)").requiredOption("--addr <address>", "Bitcoin address").option("--mime <type>", "Override the MIME type").option("--signed-at <iso>", "Override signed_at (default: now)").action(async (path, opts) => {
436
490
  const { hash, length } = await hashFile(path);
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/util.ts","../src/commands/verify.ts","../src/commands/anchor.ts","../src/commands/git-tag.ts","../src/commands/stamp-file.ts","../src/cli.ts"],"names":["createHash","submitToCalendars","toStampOts","writeFile","runVerify","canonicalMessage","createInterface","stamp","basename"],"mappings":";;;;;;;;;;;;;;;;;;;;AAOA,eAAsB,UAAU,IAAA,EAAmC;AAC/D,EAAA,MAAM,GAAA,GAAM,MAAM,QAAA,CAAS,IAAI,CAAA;AAC/B,EAAA,OAAO,IAAI,UAAA,CAAW,GAAA,CAAI,QAAQ,GAAA,CAAI,UAAA,EAAY,IAAI,UAAU,CAAA;AACpE;AAMA,eAAsB,SAAS,IAAA,EAAyD;AACpF,EAAA,MAAM,KAAA,GAAQ,MAAM,SAAA,CAAU,IAAI,CAAA;AAClC,EAAA,MAAM,CAAA,GAAI,WAAW,QAAQ,CAAA,CAAE,OAAO,KAAK,CAAA,CAAE,OAAO,KAAK,CAAA;AACzD,EAAA,OAAO,EAAE,IAAA,EAAM,SAAA,GAAY,CAAA,EAAG,MAAA,EAAQ,MAAM,UAAA,EAAW;AAC3D;AAGO,SAAS,aAAa,IAAA,EAAsB;AAC/C,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,IAAI,CAAA,CAAE,WAAA,EAAY;AACxC,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,GAAG,EAAE,GAAA,EAAI;AAChC,EAAA,QAAQ,GAAA;AAAK,IACT,KAAK,IAAA;AAAA,IACL,KAAK,UAAA;AACD,MAAA,OAAO,eAAA;AAAA,IACX,KAAK,KAAA;AACD,MAAA,OAAO,YAAA;AAAA,IACX,KAAK,MAAA;AAAA,IACL,KAAK,KAAA;AACD,MAAA,OAAO,WAAA;AAAA,IACX,KAAK,MAAA;AACD,MAAA,OAAO,kBAAA;AAAA,IACX,KAAK,KAAA;AACD,MAAA,OAAO,iBAAA;AAAA,IACX,KAAK,KAAA;AACD,MAAA,OAAO,WAAA;AAAA,IACX,KAAK,KAAA;AAAA,IACL,KAAK,MAAA;AACD,MAAA,OAAO,YAAA;AAAA,IACX,KAAK,KAAA;AACD,MAAA,OAAO,WAAA;AAAA,IACX,KAAK,MAAA;AACD,MAAA,OAAO,YAAA;AAAA,IACX,KAAK,KAAA;AACD,MAAA,OAAO,YAAA;AAAA,IACX,KAAK,KAAA;AACD,MAAA,OAAO,WAAA;AAAA,IACX,KAAK,KAAA;AACD,MAAA,OAAO,WAAA;AAAA,IACX,KAAK,KAAA;AACD,MAAA,OAAO,iBAAA;AAAA,IACX,KAAK,KAAA;AACD,MAAA,OAAO,mBAAA;AAAA,IACX,KAAK,IAAA;AACD,MAAA,OAAO,kBAAA;AAAA,IACX;AACI,MAAA,OAAO,0BAAA;AAAA;AAEnB;AAEA,eAAsB,WAAW,IAAA,EAAgC;AAC7D,EAAA,IAAI;AACA,IAAA,MAAM,KAAK,IAAI,CAAA;AACf,IAAA,OAAO,IAAA;AAAA,EACX,CAAA,CAAA,MAAQ;AACJ,IAAA,OAAO,KAAA;AAAA,EACX;AACJ;AAKA,eAAsB,SAAsB,UAAA,EAAgC;AACxE,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI,UAAA,KAAe,GAAA,IAAO,UAAA,KAAe,YAAA,EAAc;AACnD,IAAA,IAAA,GAAO,MAAM,SAAA,EAAU;AAAA,EAC3B,CAAA,MAAO;AACH,IAAA,IAAA,GAAQ,MAAM,QAAA,CAAS,UAAA,EAAY,MAAM,CAAA;AAAA,EAC7C;AACA,EAAA,OAAO,IAAA,CAAK,MAAM,IAAI,CAAA;AAC1B;AAEA,SAAS,SAAA,GAA6B;AAClC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACpC,IAAA,IAAI,IAAA,GAAO,EAAA;AACX,IAAA,OAAA,CAAQ,KAAA,CAAM,YAAY,MAAM,CAAA;AAChC,IAAA,OAAA,CAAQ,KAAA,CAAM,EAAA,CAAG,MAAA,EAAQ,CAAC,KAAA,KAAU;AAChC,MAAA,IAAA,IAAQ,KAAA;AAAA,IACZ,CAAC,CAAA;AACD,IAAA,OAAA,CAAQ,MAAM,EAAA,CAAG,KAAA,EAAO,MAAM,OAAA,CAAQ,IAAI,CAAC,CAAA;AAC3C,IAAA,OAAA,CAAQ,KAAA,CAAM,EAAA,CAAG,OAAA,EAAS,MAAM,CAAA;AAAA,EACpC,CAAC,CAAA;AACL;AAGO,SAAS,IAAA,CAAK,MAAe,MAAA,EAAuC;AACvE,EAAA,IAAI,IAAA,EAAM;AACN,IAAA,OAAA,CAAQ,IAAI,IAAA,CAAK,SAAA,CAAU,MAAA,EAAQ,IAAA,EAAM,CAAC,CAAC,CAAA;AAAA,EAC/C,CAAA,MAAO;AACH,IAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA,EAAG;AACzC,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,EAAG,CAAC,CAAA,EAAA,EAAK,OAAO,CAAA,KAAM,QAAA,GAAW,IAAA,CAAK,SAAA,CAAU,CAAC,CAAA,GAAI,CAAC,CAAA,CAAE,CAAA;AAAA,IACxE;AAAA,EACJ;AACJ;AAEO,SAAS,GAAA,CAAI,GAAA,EAAa,IAAA,GAAO,CAAA,EAAU;AAC9C,EAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,OAAA,EAAU,GAAG,CAAA,CAAE,CAAA;AAC7B,EAAA,OAAA,CAAQ,KAAK,IAAI,CAAA;AACrB;AAjHA,IAAA,SAAA,GAAA,KAAA,CAAA;AAAA,EAAA,aAAA,GAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACAA,IAAA,cAAA,GAAA,EAAA;AAAA,QAAA,CAAA,cAAA,EAAA;AAAA,EAAA,SAAA,EAAA,MAAA;AAAA,CAAA,CAAA;AAoBA,eAAsB,UAAU,IAAA,EAAoC;AAChE,EAAA,IAAI,CAAE,MAAM,UAAA,CAAW,IAAA,CAAK,SAAS,GAAI,GAAA,CAAI,CAAA,cAAA,EAAiB,IAAA,CAAK,SAAS,CAAA,CAAE,CAAA;AAE9E,EAAA,MAAM,QAAA,GAAW,MAAM,QAAA,CAAwB,IAAA,CAAK,SAAS,CAAA;AAE7D,EAAA,IAAI,YAAA;AACJ,EAAA,IAAI,KAAK,WAAA,EAAa;AAClB,IAAA,IAAI,CAAE,MAAM,UAAA,CAAW,IAAA,CAAK,WAAW,GAAI,GAAA,CAAI,CAAA,cAAA,EAAiB,IAAA,CAAK,WAAW,CAAA,CAAE,CAAA;AAClF,IAAA,YAAA,GAAe,MAAM,SAAA,CAAU,IAAA,CAAK,WAAW,CAAA;AAAA,EACnD;AAGA,EAAA,IAAI,YAAA;AACJ,EAAA,IAAI,CAAC,KAAK,aAAA,EAAe;AACrB,IAAA,MAAM,GAAA,GAAO,MAAM,OAAO,WAAW,CAAA;AAIrC,IAAA,MAAM,QAAA,GAAW,GAAA,CAAI,QAAA,IAAY,GAAA,CAAI,OAAA,EAAS,QAAA;AAC9C,IAAA,IAAI,CAAC,QAAA,EAAU,GAAA,CAAI,qCAAqC,CAAA;AACxD,IAAA,YAAA,GAAe,OAAO,CAAA,EAAG,CAAA,EAAG,CAAA,KAAM;AAC9B,MAAA,IAAI;AACA,QAAA,OAAO,QAAA,CAAS,eAAA,CAAgB,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AAAA,MAC3C,CAAA,CAAA,MAAQ;AACJ,QAAA,OAAO,KAAA;AAAA,MACX;AAAA,IACJ,CAAA;AAAA,EACJ;AAEA,EAAA,MAAM,CAAA,GAAI,MAAM,MAAA,CAAO;AAAA,IACnB,QAAA;AAAA,IACA,OAAA,EAAS,YAAA;AAAA,IACT,YAAA;AAAA,IACA,2BAA2B,IAAA,CAAK;AAAA,GACnC,CAAA;AAED,EAAA,IAAI,CAAC,EAAE,EAAA,EAAI;AACP,IAAA,IAAA,CAAK,KAAK,IAAA,EAAM;AAAA,MACZ,EAAA,EAAI,KAAA;AAAA,MACJ,MAAM,CAAA,CAAE,IAAA;AAAA,MACR,SAAS,CAAA,CAAE;AAAA,KACd,CAAA;AACD,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAClB;AAEA,EAAA,MAAM,WAAA,GACF,CAAA,CAAE,MAAA,CAAO,MAAA,KAAW,SACd,MAAA,GACA,CAAA,CAAE,MAAA,CAAO,MAAA,KAAW,SAAA,GAClB,SAAA,GACA,CAAA,mBAAA,EAAsB,CAAA,CAAE,OAAO,WAAW,CAAA,CAAA;AAEtD,EAAA,IAAI,IAAA,CAAK,aAAA,IAAiB,CAAA,CAAE,MAAA,CAAO,WAAW,WAAA,EAAa;AACvD,IAAA,IAAA,CAAK,KAAK,IAAA,EAAM;AAAA,MACZ,EAAA,EAAI,KAAA;AAAA,MACJ,IAAA,EAAM,aAAA;AAAA,MACN,OAAA,EAAS,CAAA,mCAAA,EAAsC,CAAA,CAAE,MAAA,CAAO,MAAM,CAAA;AAAA,KACjE,CAAA;AACD,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAClB;AAEA,EAAA,IAAA,CAAK,KAAK,IAAA,EAAM;AAAA,IACZ,EAAA,EAAI,IAAA;AAAA,IACJ,IAAI,CAAA,CAAE,EAAA;AAAA,IACN,MAAA,EAAQ,SAAS,MAAA,CAAO,OAAA;AAAA,IACxB,WAAW,QAAA,CAAS,SAAA;AAAA,IACpB,YAAA,EAAc,SAAS,OAAA,CAAQ,IAAA;AAAA,IAC/B,YAAA,EAAc,SAAS,OAAA,CAAQ,IAAA;AAAA,IAC/B,cAAA,EAAgB,SAAS,OAAA,CAAQ,MAAA;AAAA,IACjC,eAAA,EAAiB,QAAQ,YAAY,CAAA;AAAA,IACrC,MAAA,EAAQ,WAAA;AAAA,IACR,iBAAA,EAAmB,CAAC,IAAA,CAAK,aAAA;AAAA,IACzB,OAAO,QAAA,CAAS;AAAA,GACnB,CAAA;AAEL;AA/FA,IAAA,WAAA,GAAA,KAAA,CAAA;AAAA,EAAA,wBAAA,GAAA;AAKA,IAAA,SAAA,EAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACIA,SAAA,EAAA;AAOA,eAAsB,UAAU,IAAA,EAAoC;AAChE,EAAA,IAAI,CAAE,MAAM,UAAA,CAAW,IAAA,CAAK,SAAS,GAAI,GAAA,CAAI,CAAA,cAAA,EAAiB,IAAA,CAAK,SAAS,CAAA,CAAE,CAAA;AAC9E,EAAA,MAAM,QAAA,GAAW,MAAM,QAAA,CAAwB,IAAA,CAAK,SAAS,CAAA;AAE7D,EAAA,IAAI,QAAA,CAAS,GAAA,EAAK,MAAA,KAAW,WAAA,EAAa;AACtC,IAAA,IAAA,CAAK,KAAK,IAAA,EAAM;AAAA,MACZ,EAAA,EAAI,IAAA;AAAA,MACJ,OAAA,EAAS,WAAA;AAAA,MACT,YAAA,EAAc,SAAS,GAAA,CAAI;AAAA,KAC9B,CAAA;AACD,IAAA;AAAA,EACJ;AAEA,EAAA,IAAI;AACA,IAAA,MAAM,KAAA,GAAQ,MAAM,iBAAA,CAAkB,QAAA,CAAS,EAAE,CAAA;AACjD,IAAA,MAAM,OAAsB,EAAE,GAAG,UAAU,GAAA,EAAK,UAAA,CAAW,KAAK,CAAA,EAAE;AAClE,IAAA,MAAM,SAAA,CAAU,IAAA,CAAK,SAAA,EAAW,IAAA,CAAK,SAAA,CAAU,MAAM,IAAA,EAAM,CAAC,CAAA,GAAI,IAAA,EAAM,MAAM,CAAA;AAC5E,IAAA,IAAA,CAAK,KAAK,IAAA,EAAM;AAAA,MACZ,EAAA,EAAI,IAAA;AAAA,MACJ,IAAI,IAAA,CAAK,EAAA;AAAA,MACT,MAAA,EAAQ,KAAK,GAAA,EAAK,MAAA;AAAA,MAClB,SAAA,EAAW,IAAA,CAAK,GAAA,EAAK,SAAA,IAAa,EAAC;AAAA,MACnC,SAAS,IAAA,CAAK;AAAA,KACjB,CAAA;AAAA,EACL,SAAS,CAAA,EAAG;AACR,IAAA,GAAA,CAAI,CAAA,uBAAA,EAA0B,aAAa,KAAA,GAAQ,CAAA,CAAE,UAAU,MAAA,CAAO,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,EAC9E;AACJ;;;AC3BA,SAAA,EAAA;AAGA,IAAM,IAAA,GAAO,UAAU,QAAQ,CAAA;AAU/B,eAAe,WAAW,IAAA,EAAiC;AACvD,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,MAAM,IAAA,CAAK,OAAO,IAAI,CAAA;AACzC,EAAA,OAAO,OAAO,IAAA,EAAK;AACvB;AAEA,eAAsB,UAAU,IAAA,EAAoC;AAEhE,EAAA,IAAI;AACA,IAAA,MAAM,UAAA,CAAW,CAAC,WAAA,EAAa,uBAAuB,CAAC,CAAA;AAAA,EAC3D,CAAA,CAAA,MAAQ;AACJ,IAAA,GAAA,CAAI,4BAA4B,CAAA;AAAA,EACpC;AAGA,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI,WAAA;AACJ,EAAA,IAAI;AACA,IAAA,MAAA,GAAS,MAAM,WAAW,CAAC,WAAA,EAAa,GAAG,IAAA,CAAK,GAAG,SAAS,CAAC,CAAA;AAC7D,IAAA,WAAA,GAAc,MAAM,UAAA,CAAW,CAAC,WAAA,EAAa,IAAA,CAAK,GAAG,CAAC,CAAA;AAAA,EAC1D,SAAS,CAAA,EAAG;AACR,IAAA,GAAA,CAAI,CAAA,uBAAA,EAA0B,IAAA,CAAK,GAAG,CAAA,EAAA,EAAK,CAAA,YAAa,KAAA,GAAQ,CAAA,CAAE,OAAA,GAAU,MAAA,CAAO,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,EAC3F;AAIA,EAAA,MAAM,YAAA,GAAe,IAAI,WAAA,EAAY,CAAE,MAAA;AAAA,IACnC,CAAA;AAAA,KAAA,EAA6B,KAAK,GAAG;AAAA,QAAA,EAAa,WAAW;AAAA,MAAA,EAAW,MAAM;AAAA;AAAA,GAClF;AACA,EAAA,MAAM,WAAA,GAAc,YAAYA,UAAAA,CAAW,QAAQ,EAAE,MAAA,CAAO,YAAY,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA;AACtF,EAAA,MAAM,gBAAgB,YAAA,CAAa,UAAA;AACnC,EAAA,MAAM,IAAA,GAAO,uBAAA;AACb,EAAA,MAAM,QAAA,GAAA,qBAAe,IAAA,EAAK,EAAE,aAAY,CAAE,OAAA,CAAQ,WAAW,GAAG,CAAA;AAEhE,EAAA,MAAM,MAAM,gBAAA,CAAiB;AAAA,IACzB,SAAS,IAAA,CAAK,OAAA;AAAA,IACd,YAAA,EAAc,WAAA;AAAA,IACd,cAAA,EAAgB,aAAA;AAAA,IAChB,YAAA,EAAc,IAAA;AAAA,IACd,SAAA,EAAW;AAAA,GACd,CAAA;AAED,EAAA,IAAI,SAAA;AACJ,EAAA,IAAI,KAAK,GAAA,EAAK;AACV,IAAA,SAAA,GAAY,IAAA,CAAK,GAAA;AAAA,EACrB,CAAA,MAAO;AACH,IAAA,OAAA,CAAQ,MAAM,2DAA2D,CAAA;AACzE,IAAA,OAAA,CAAQ,KAAA,CAAM,QAAA,CAAI,MAAA,CAAO,EAAE,CAAC,CAAA;AAC5B,IAAA,OAAA,CAAQ,MAAM,GAAG,CAAA;AACjB,IAAA,OAAA,CAAQ,KAAA,CAAM,QAAA,CAAI,MAAA,CAAO,EAAE,CAAC,CAAA;AAC5B,IAAA,OAAA,CAAQ,KAAA,EAAM;AACd,IAAA,MAAM,EAAA,GAAK,gBAAgB,EAAE,KAAA,EAAO,QAAQ,KAAA,EAAO,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAQ,CAAA;AAC3E,IAAA,IAAI;AACA,MAAA,SAAA,GAAA,CAAa,MAAM,EAAA,CAAG,QAAA,CAAS,4BAA4B,GAAG,IAAA,EAAK;AAAA,IACvE,CAAA,SAAE;AACE,MAAA,EAAA,CAAG,KAAA,EAAM;AAAA,IACb;AACA,IAAA,IAAI,CAAC,SAAA,EAAW,GAAA,CAAI,uBAAuB,CAAA;AAAA,EAC/C;AAEA,EAAA,MAAM,QAAA,GAA0B,MAAM,KAAA,CAAM;AAAA,IACxC,OAAA,EAAS,EAAE,IAAA,EAAM,WAAA,EAAa,QAAQ,aAAA,EAAc;AAAA,IACpD,IAAA;AAAA,IACA,MAAA,EAAQ;AAAA,MACJ,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,aAAa,YAAY;AAAA,KAC7B;AAAA,IACA,QAAA,EAAU,IAAI,IAAA,CAAK,QAAQ;AAAA,GAC9B,CAAA;AAED,EAAA,IAAI,KAAA,GAAQ,QAAA;AACZ,EAAA,IAAI,KAAK,MAAA,EAAQ;AACb,IAAA,IAAI;AACA,MAAA,MAAM,KAAA,GAAQ,MAAMC,iBAAAA,CAAkB,QAAA,CAAS,EAAE,CAAA;AACjD,MAAA,KAAA,GAAQ,EAAE,GAAG,QAAA,EAAU,GAAA,EAAKC,UAAAA,CAAW,KAAK,CAAA,EAAE;AAAA,IAClD,SAAS,CAAA,EAAG;AACR,MAAA,OAAA,CAAQ,KAAA;AAAA,QACJ,mCAAmC,CAAA,YAAa,KAAA,GAAQ,EAAE,OAAA,GAAU,MAAA,CAAO,CAAC,CAAC,CAAA,iFAAA;AAAA,OAEjF;AAAA,IACJ;AAAA,EACJ;AAKA,EAAA,MAAM,SAAS,MAAM,UAAA,CAAW,CAAC,WAAA,EAAa,WAAW,CAAC,CAAA;AAC1D,EAAA,MAAM,SAAA,GAAY,GAAG,MAAM,CAAA,OAAA,CAAA;AAC3B,EAAA,MAAM,KAAA,CAAM,SAAA,EAAW,EAAE,SAAA,EAAW,MAAM,CAAA;AAC1C,EAAA,MAAM,OAAA,GAAU,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,KAAK,GAAG,CAAA,MAAA,CAAA;AACxC,EAAA,MAAMC,SAAAA,CAAU,SAAS,IAAA,CAAK,SAAA,CAAU,OAAO,IAAA,EAAM,CAAC,CAAA,GAAI,IAAA,EAAM,MAAM,CAAA;AAEtE,EAAA,IAAA,CAAK,KAAK,IAAA,EAAM;AAAA,IACZ,EAAA,EAAI,IAAA;AAAA,IACJ,KAAK,IAAA,CAAK,GAAA;AAAA,IACV,IAAA,EAAM,MAAA;AAAA,IACN,MAAA,EAAQ,WAAA;AAAA,IACR,IAAI,KAAA,CAAM,EAAA;AAAA,IACV,MAAA,EAAQ,MAAM,MAAA,CAAO,OAAA;AAAA,IACrB,GAAA,EAAK,KAAA,CAAM,GAAA,EAAK,MAAA,IAAU,cAAA;AAAA,IAC1B,OAAA,EAAS;AAAA,GACZ,CAAA;AACL;AAQA,eAAsB,aAAa,IAAA,EAAuC;AACtE,EAAA,MAAM,SAAS,MAAM,UAAA,CAAW,CAAC,WAAA,EAAa,WAAW,CAAC,CAAA;AAC1D,EAAA,MAAM,SAAA,GAAY,CAAA,EAAG,MAAM,CAAA,QAAA,EAAW,KAAK,GAAG,CAAA,MAAA,CAAA;AAC9C,EAAA,MAAM,EAAE,SAAA,EAAAC,UAAAA,EAAU,GAAI,MAAM,OAAA,CAAA,OAAA,EAAA,CAAA,IAAA,CAAA,OAAA,WAAA,EAAA,EAAA,cAAA,CAAA,CAAA;AAC5B,EAAA,MAAMA,UAAAA,CAAU;AAAA,IACZ,SAAA;AAAA,IACA,eAAe,IAAA,CAAK,aAAA;AAAA,IACpB,aAAA,EAAe,KAAA;AAAA,IACf,MAAM,IAAA,CAAK;AAAA,GACd,CAAA;AACL;;;ACvIA,SAAA,EAAA;AAeA,eAAsB,aAAa,IAAA,EAAuC;AACtE,EAAA,IAAI,CAAE,MAAM,UAAA,CAAW,IAAA,CAAK,IAAI,GAAI,GAAA,CAAI,CAAA,cAAA,EAAiB,IAAA,CAAK,IAAI,CAAA,CAAE,CAAA;AAEpE,EAAA,MAAM,EAAE,IAAA,EAAM,MAAA,KAAW,MAAM,QAAA,CAAS,KAAK,IAAI,CAAA;AACjD,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,IAAQ,YAAA,CAAa,KAAK,IAAI,CAAA;AAChD,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAA,iBAAY,IAAI,IAAA,IAAO,WAAA,EAAY,CAAE,OAAA,CAAQ,SAAA,EAAW,GAAG,CAAA;AAEjF,EAAA,MAAM,MAAMC,gBAAAA,CAAiB;AAAA,IACzB,SAAS,IAAA,CAAK,OAAA;AAAA,IACd,YAAA,EAAc,IAAA;AAAA,IACd,cAAA,EAAgB,MAAA;AAAA,IAChB,YAAA,EAAc,IAAA;AAAA,IACd,SAAA,EAAW;AAAA,GACd,CAAA;AAED,EAAA,IAAI,SAAA;AACJ,EAAA,IAAI,KAAK,GAAA,EAAK;AACV,IAAA,SAAA,GAAY,IAAA,CAAK,GAAA;AAAA,EACrB,CAAA,MAAO;AAEH,IAAA,OAAA,CAAQ,MAAM,2DAA2D,CAAA;AACzE,IAAA,OAAA,CAAQ,KAAA,CAAM,QAAA,CAAI,MAAA,CAAO,EAAE,CAAC,CAAA;AAC5B,IAAA,OAAA,CAAQ,MAAM,GAAG,CAAA;AACjB,IAAA,OAAA,CAAQ,KAAA,CAAM,QAAA,CAAI,MAAA,CAAO,EAAE,CAAC,CAAA;AAC5B,IAAA,OAAA,CAAQ,KAAA,EAAM;AACd,IAAA,MAAM,EAAA,GAAKC,gBAAgB,EAAE,KAAA,EAAO,QAAQ,KAAA,EAAO,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAQ,CAAA;AAC3E,IAAA,IAAI;AACA,MAAA,SAAA,GAAA,CAAa,MAAM,EAAA,CAAG,QAAA,CAAS,4BAA4B,GAAG,IAAA,EAAK;AAAA,IACvE,CAAA,SAAE;AACE,MAAA,EAAA,CAAG,KAAA,EAAM;AAAA,IACb;AACA,IAAA,IAAI,CAAC,SAAA,EAAW,GAAA,CAAI,uBAAuB,CAAA;AAAA,EAC/C;AAEA,EAAA,MAAM,QAAA,GAA0B,MAAMC,KAAAA,CAAM;AAAA,IACxC,OAAA,EAAS,EAAE,IAAA,EAAM,MAAA,EAAO;AAAA,IACxB,IAAA;AAAA,IACA,MAAA,EAAQ;AAAA,MACJ,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,aAAa,YAAY;AAAA,KAC7B;AAAA,IACA,QAAA,EAAU,IAAI,IAAA,CAAK,QAAQ,CAAA;AAAA,IAC3B,OAAO,IAAA,CAAK;AAAA,GACf,CAAA;AAED,EAAA,IAAI,KAAA,GAAQ,QAAA;AACZ,EAAA,IAAI,KAAK,MAAA,EAAQ;AACb,IAAA,IAAI;AACA,MAAA,MAAM,KAAA,GAAQ,MAAMN,iBAAAA,CAAkB,QAAA,CAAS,EAAE,CAAA;AACjD,MAAA,KAAA,GAAQ,EAAE,GAAG,QAAA,EAAU,GAAA,EAAKC,UAAAA,CAAW,KAAK,CAAA,EAAE;AAAA,IAClD,SAAS,CAAA,EAAG;AACR,MAAA,OAAA,CAAQ,KAAA;AAAA,QACJ,mCAAmC,CAAA,YAAa,KAAA,GAAQ,EAAE,OAAA,GAAU,MAAA,CAAO,CAAC,CAAC,CAAA,iFAAA;AAAA,OAEjF;AAAA,IACJ;AAAA,EACJ;AAEA,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,IAAO,CAAA,EAAG,KAAK,IAAI,CAAA,MAAA,CAAA;AACxC,EAAA,MAAMC,SAAAA,CAAU,SAAS,IAAA,CAAK,SAAA,CAAU,OAAO,IAAA,EAAM,CAAC,CAAA,GAAI,IAAA,EAAM,MAAM,CAAA;AAEtE,EAAA,IAAA,CAAK,KAAK,IAAA,EAAM;AAAA,IACZ,EAAA,EAAI,IAAA;AAAA,IACJ,IAAI,KAAA,CAAM,EAAA;AAAA,IACV,MAAA,EAAQ,MAAM,MAAA,CAAO,OAAA;AAAA,IACrB,WAAW,KAAA,CAAM,SAAA;AAAA,IACjB,YAAA,EAAc,MAAM,OAAA,CAAQ,IAAA;AAAA,IAC5B,cAAA,EAAgB,MAAM,OAAA,CAAQ,MAAA;AAAA,IAC9B,YAAA,EAAc,MAAM,OAAA,CAAQ,IAAA;AAAA,IAC5B,GAAA,EAAK,MAAM,GAAA,GACL,CAAA,EAAG,MAAM,GAAA,CAAI,MAAM,KAAK,KAAA,CAAM,GAAA,CAAI,UAAU,MAAM,CAAA,SAAA,EAAY,MAAM,GAAA,CAAI,SAAA,CAAU,WAAW,CAAA,GAAI,EAAA,GAAK,GAAG,CAAA,CAAA,CAAA,GACzG,cAAA;AAAA,IACN,OAAA,EAAS;AAAA,GACZ,CAAA;AAEL;;;AC9EA,WAAA,EAAA;AAGA,SAAA,EAAA;AAEA,IAAM,UAAUK,QAAAA,CAAS,OAAA,CAAQ,IAAA,CAAK,CAAC,KAAK,OAAO,CAAA;AAEnD,IAAM,OAAA,GAAU,IAAI,OAAA,EAAQ;AAE5B,IAAI,OAAA,CAAQ,UAAA,CAAW,WAAW,CAAA,EAAG;AAEjC,EAAA,OAAA,CACK,KAAK,WAAW,CAAA,CAChB,YAAY,gEAAgE,CAAA,CAC5E,QAAQ,OAAO,CAAA;AAEpB,EAAA,OAAA,CACK,OAAA,CAAQ,eAAe,CAAA,CACvB,WAAA,CAAY,4DAA4D,EACxE,cAAA,CAAe,kBAAA,EAAoB,iBAAiB,CAAA,CACpD,MAAA,CAAO,mBAAA,EAAqB,0CAA0C,CAAA,CACtE,MAAA,CAAO,aAAA,EAAe,8BAA8B,CAAA,CACpD,MAAA,CAAO,QAAA,EAAU,WAAW,CAAA,CAC5B,MAAA,CAAO,OAAO,GAAA,EAAK,IAAA,KAAS;AACzB,IAAA,MAAM,SAAA,CAAU;AAAA,MACZ,GAAA;AAAA,MACA,SAAS,IAAA,CAAK,IAAA;AAAA,MACd,KAAK,IAAA,CAAK,GAAA;AAAA,MACV,MAAA,EAAQ,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA;AAAA,MAC3B,IAAA,EAAM,OAAA,CAAQ,IAAA,CAAK,IAAI;AAAA,KAC1B,CAAA;AAAA,EACL,CAAC,CAAA;AAEL,EAAA,OAAA,CACK,QAAQ,kBAAkB,CAAA,CAC1B,WAAA,CAAY,2DAA2D,EACvE,MAAA,CAAO,kBAAA,EAAoB,wCAAwC,CAAA,CACnE,OAAO,QAAA,EAAU,WAAW,EAC5B,MAAA,CAAO,OAAO,KAAK,IAAA,KAAS;AACzB,IAAA,MAAM,YAAA,CAAa;AAAA,MACf,GAAA;AAAA,MACA,aAAA,EAAe,OAAA,CAAQ,IAAA,CAAK,aAAa,CAAA;AAAA,MACzC,IAAA,EAAM,OAAA,CAAQ,IAAA,CAAK,IAAI;AAAA,KAC1B,CAAA;AAAA,EACL,CAAC,CAAA;AACT,CAAA,MAAO;AACH,EAAA,OAAA,CACK,KAAK,OAAO,CAAA,CACZ,YAAY,6EAAwE,CAAA,CACpF,QAAQ,OAAO,CAAA;AAEpB,EAAA,OAAA,CACK,QAAQ,aAAa,CAAA,CACrB,WAAA,CAAY,8CAA8C,EAC1D,cAAA,CAAe,kBAAA,EAAoB,iBAAiB,CAAA,CACpD,OAAO,eAAA,EAAiB,2DAA2D,CAAA,CACnF,MAAA,CAAO,qBAAqB,mCAAmC,CAAA,CAC/D,MAAA,CAAO,mBAAA,EAAqB,0CAA0C,CAAA,CACtE,MAAA,CAAO,aAAA,EAAe,8BAA8B,EACpD,MAAA,CAAO,cAAA,EAAgB,qCAAqC,CAAA,CAC5D,OAAO,QAAA,EAAU,WAAW,EAC5B,MAAA,CAAO,OAAO,MAAM,IAAA,KAAS;AAC1B,IAAA,MAAM,YAAA,CAAa;AAAA,MACf,IAAA;AAAA,MACA,SAAS,IAAA,CAAK,IAAA;AAAA,MACd,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,KAAK,IAAA,CAAK,GAAA;AAAA,MACV,MAAA,EAAQ,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA;AAAA,MAC3B,KAAK,IAAA,CAAK,GAAA;AAAA,MACV,IAAA,EAAM,OAAA,CAAQ,IAAA,CAAK,IAAI;AAAA,KAC1B,CAAA;AAAA,EACL,CAAC,CAAA;AAEL,EAAA,OAAA,CACK,OAAA,CAAQ,0BAA0B,CAAA,CAClC,WAAA,CAAY,sCAAmC,CAAA,CAC/C,MAAA,CAAO,kBAAA,EAAoB,wCAAwC,CAAA,CACnE,MAAA,CAAO,oBAAoB,qDAAqD,CAAA,CAChF,OAAO,QAAA,EAAU,WAAW,EAC5B,MAAA,CAAO,OAAO,SAAA,EAAW,WAAA,EAAa,IAAA,KAAS;AAC5C,IAAA,MAAM,SAAA,CAAU;AAAA,MACZ,SAAA;AAAA,MACA,WAAA;AAAA,MACA,aAAA,EAAe,OAAA,CAAQ,IAAA,CAAK,aAAa,CAAA;AAAA,MACzC,aAAA,EAAe,OAAA,CAAQ,IAAA,CAAK,aAAa,CAAA;AAAA,MACzC,IAAA,EAAM,OAAA,CAAQ,IAAA,CAAK,IAAI;AAAA,KAC1B,CAAA;AAAA,EACL,CAAC,CAAA;AAEL,EAAA,OAAA,CACK,OAAA,CAAQ,gBAAgB,CAAA,CACxB,WAAA,CAAY,oDAAoD,CAAA,CAChE,MAAA,CAAO,QAAA,EAAU,WAAW,CAAA,CAC5B,MAAA,CAAO,OAAO,WAAW,IAAA,KAAS;AAC/B,IAAA,MAAM,SAAA,CAAU,EAAE,SAAA,EAAW,IAAA,EAAM,QAAQ,IAAA,CAAK,IAAI,GAAG,CAAA;AAAA,EAC3D,CAAC,CAAA;AAEL,EAAA,OAAA,CACK,OAAA,CAAQ,kBAAkB,CAAA,CAC1B,WAAA,CAAY,sEAAsE,CAAA,CAClF,cAAA,CAAe,oBAAoB,iBAAiB,CAAA,CACpD,OAAO,eAAA,EAAiB,wBAAwB,EAChD,MAAA,CAAO,mBAAA,EAAqB,mCAAmC,CAAA,CAC/D,MAAA,CAAO,OAAO,IAAA,EAAM,IAAA,KAAS;AAC1B,IAAA,MAAM,EAAE,IAAA,EAAM,MAAA,EAAO,GAAI,MAAM,SAAS,IAAI,CAAA;AAC5C,IAAA,MAAM,MAAMH,gBAAAA,CAAiB;AAAA,MACzB,SAAS,IAAA,CAAK,IAAA;AAAA,MACd,YAAA,EAAc,IAAA;AAAA,MACd,cAAA,EAAgB,MAAA;AAAA,MAChB,YAAA,EAAc,IAAA,CAAK,IAAA,IAAQ,YAAA,CAAa,IAAI,CAAA;AAAA,MAC5C,SAAA,EAAW,IAAA,CAAK,QAAA,IAAA,iBAAY,IAAI,IAAA,IAAO,WAAA,EAAY,CAAE,OAAA,CAAQ,SAAA,EAAW,GAAG;AAAA,KAC9E,CAAA;AACD,IAAA,OAAA,CAAQ,MAAA,CAAO,MAAM,GAAG,CAAA;AAAA,EAG5B,CAAC,CAAA;AACT;AAEA,OAAA,CAAQ,WAAW,OAAA,CAAQ,IAAI,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AAC5C,EAAA,OAAA,CAAQ,KAAA,CAAM,UAAU,GAAA,YAAe,KAAA,GAAQ,IAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA,CAAE,CAAA;AAC1E,EAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAClB,CAAC,CAAA","file":"cli.js","sourcesContent":["// Shared helpers for stamp-cli commands.\n\nimport { createHash } from 'node:crypto';\nimport { readFile, stat } from 'node:fs/promises';\nimport { basename } from 'node:path';\n\n/** Read a path into bytes. */\nexport async function readBytes(path: string): Promise<Uint8Array> {\n const buf = await readFile(path);\n return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n}\n\n/**\n * Stream-hash a path with SHA-256. For very large content we want to avoid\n * loading the whole file into memory; for small files the cost is negligible.\n */\nexport async function hashFile(path: string): Promise<{ hash: string; length: number }> {\n const bytes = await readBytes(path);\n const h = createHash('sha256').update(bytes).digest('hex');\n return { hash: 'sha256:' + h, length: bytes.byteLength };\n}\n\n/** Infer a conservative MIME from a filename. Falls back to application/octet-stream. */\nexport function mimeFromPath(path: string): string {\n const name = basename(path).toLowerCase();\n const ext = name.split('.').pop();\n switch (ext) {\n case 'md':\n case 'markdown':\n return 'text/markdown';\n case 'txt':\n return 'text/plain';\n case 'html':\n case 'htm':\n return 'text/html';\n case 'json':\n return 'application/json';\n case 'pdf':\n return 'application/pdf';\n case 'png':\n return 'image/png';\n case 'jpg':\n case 'jpeg':\n return 'image/jpeg';\n case 'gif':\n return 'image/gif';\n case 'webp':\n return 'image/webp';\n case 'mp3':\n return 'audio/mpeg';\n case 'mp4':\n return 'video/mp4';\n case 'wav':\n return 'audio/wav';\n case 'zip':\n return 'application/zip';\n case 'tar':\n return 'application/x-tar';\n case 'gz':\n return 'application/gzip';\n default:\n return 'application/octet-stream';\n }\n}\n\nexport async function pathExists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Read JSON from a path or `-` for stdin.\n */\nexport async function readJson<T = unknown>(pathOrDash: string): Promise<T> {\n let text: string;\n if (pathOrDash === '-' || pathOrDash === '/dev/stdin') {\n text = await readStdin();\n } else {\n text = (await readFile(pathOrDash, 'utf8')) as string;\n }\n return JSON.parse(text) as T;\n}\n\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf8');\n process.stdin.on('data', (chunk) => {\n data += chunk;\n });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Emit structured output. */\nexport function emit(json: boolean, result: Record<string, unknown>): void {\n if (json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n for (const [k, v] of Object.entries(result)) {\n console.log(`${k}: ${typeof v === 'object' ? JSON.stringify(v) : v}`);\n }\n }\n}\n\nexport function die(msg: string, code = 1): never {\n console.error(`error: ${msg}`);\n process.exit(code);\n}\n","// `stamp verify <stamp-path> [content-path]` — run the full SPEC §8\n// verification algorithm locally. Structured JSON output with `--json`.\n\nimport { verify, type StampEnvelope } from '@orangecheck/stamp-core';\n\nimport { die, emit, hashFile, pathExists, readBytes, readJson } from '../util.js';\n\nexport interface VerifyOptions {\n stampPath: string;\n contentPath?: string;\n requireAnchor: boolean;\n /**\n * If set, skip the BIP-322 signature verification. Mostly useful for CI\n * smoke tests with placeholder signatures; production verification should\n * never pass this.\n */\n skipSignature: boolean;\n json: boolean;\n}\n\nexport async function runVerify(opts: VerifyOptions): Promise<void> {\n if (!(await pathExists(opts.stampPath))) die(`no such file: ${opts.stampPath}`);\n\n const envelope = await readJson<StampEnvelope>(opts.stampPath);\n\n let contentBytes: Uint8Array | undefined;\n if (opts.contentPath) {\n if (!(await pathExists(opts.contentPath))) die(`no such file: ${opts.contentPath}`);\n contentBytes = await readBytes(opts.contentPath);\n }\n\n // Lazy-load bip322-js so it's only pulled in when needed (heavy dep).\n let verifyBip322: ((msg: string, sig: string, addr: string) => Promise<boolean>) | undefined;\n if (!opts.skipSignature) {\n const mod = (await import('bip322-js')) as unknown as {\n Verifier?: { verifySignature(a: string, m: string, s: string): boolean };\n default?: { Verifier?: { verifySignature(a: string, m: string, s: string): boolean } };\n };\n const Verifier = mod.Verifier ?? mod.default?.Verifier;\n if (!Verifier) die('bip322-js Verifier export not found');\n verifyBip322 = async (m, s, a) => {\n try {\n return Verifier.verifySignature(a, m, s);\n } catch {\n return false;\n }\n };\n }\n\n const r = await verify({\n envelope,\n content: contentBytes,\n verifyBip322,\n skipSignatureVerification: opts.skipSignature,\n });\n\n if (!r.ok) {\n emit(opts.json, {\n ok: false,\n code: r.code,\n message: r.message,\n });\n process.exit(2);\n }\n\n const anchorLabel =\n r.anchor.status === 'none'\n ? 'none'\n : r.anchor.status === 'pending'\n ? 'pending'\n : `confirmed at block ${r.anchor.blockHeight}`;\n\n if (opts.requireAnchor && r.anchor.status !== 'confirmed') {\n emit(opts.json, {\n ok: false,\n code: 'E_NO_ANCHOR',\n message: `required confirmed OTS anchor, got ${r.anchor.status}`,\n });\n process.exit(2);\n }\n\n emit(opts.json, {\n ok: true,\n id: r.id,\n signer: envelope.signer.address,\n signed_at: envelope.signed_at,\n content_hash: envelope.content.hash,\n content_mime: envelope.content.mime,\n content_length: envelope.content.length,\n content_checked: Boolean(contentBytes),\n anchor: anchorLabel,\n signature_checked: !opts.skipSignature,\n stake: envelope.stake,\n });\n void hashFile;\n}\n","// `stamp anchor <stamp-path>` — submit (or re-submit) an existing stamp's id\n// to OTS calendars. If the proof is already confirmed, no-op. If it's\n// pending, try to upgrade via the listed calendars.\n\nimport { writeFile } from 'node:fs/promises';\n\nimport { submitToCalendars, toStampOts } from '@orangecheck/stamp-ots';\nimport type { StampEnvelope } from '@orangecheck/stamp-core';\n\nimport { die, emit, pathExists, readJson } from '../util.js';\n\nexport interface AnchorOptions {\n stampPath: string;\n json: boolean;\n}\n\nexport async function runAnchor(opts: AnchorOptions): Promise<void> {\n if (!(await pathExists(opts.stampPath))) die(`no such file: ${opts.stampPath}`);\n const envelope = await readJson<StampEnvelope>(opts.stampPath);\n\n if (envelope.ots?.status === 'confirmed') {\n emit(opts.json, {\n ok: true,\n already: 'confirmed',\n block_height: envelope.ots.block_height,\n });\n return;\n }\n\n try {\n const proof = await submitToCalendars(envelope.id);\n const next: StampEnvelope = { ...envelope, ots: toStampOts(proof) };\n await writeFile(opts.stampPath, JSON.stringify(next, null, 2) + '\\n', 'utf8');\n emit(opts.json, {\n ok: true,\n id: next.id,\n status: next.ots?.status,\n calendars: next.ots?.calendars ?? [],\n written: opts.stampPath,\n });\n } catch (e) {\n die(`OTS submission failed: ${e instanceof Error ? e.message : String(e)}`);\n }\n}\n","// `git-stamp tag <tagname>` — stamp a git tag's tree. Meant to be invoked as\n// `git-stamp tag v1.2.3` (the same binary as `stamp`; we detect the alias\n// from argv[1] basename and also accept explicit `git tag` subcommand).\n//\n// The stamp covers the `git rev-parse <tag>^{tree}` output concatenated with\n// the tag name and object id, so changing any of (tree contents, tag object,\n// or tag name) invalidates the envelope.\n\nimport { execFile } from 'node:child_process';\nimport { writeFile, mkdir } from 'node:fs/promises';\nimport { promisify } from 'node:util';\n\nimport { createHash } from 'node:crypto';\nimport { canonicalMessage, stamp, type StampEnvelope } from '@orangecheck/stamp-core';\nimport { submitToCalendars, toStampOts } from '@orangecheck/stamp-ots';\n\nimport { die, emit } from '../util.js';\nimport { createInterface } from 'node:readline/promises';\n\nconst exec = promisify(execFile);\n\nexport interface GitTagOptions {\n tag: string;\n address: string;\n sig?: string;\n anchor: boolean;\n json: boolean;\n}\n\nasync function gitCapture(args: string[]): Promise<string> {\n const { stdout } = await exec('git', args);\n return stdout.trim();\n}\n\nexport async function runGitTag(opts: GitTagOptions): Promise<void> {\n // Validate that we're inside a git repo.\n try {\n await gitCapture(['rev-parse', '--is-inside-work-tree']);\n } catch {\n die('not inside a git work tree');\n }\n\n // Resolve the tag to its commit + tree, and the tag object itself.\n let treeId: string;\n let tagObjectId: string;\n try {\n treeId = await gitCapture(['rev-parse', `${opts.tag}^{tree}`]);\n tagObjectId = await gitCapture(['rev-parse', opts.tag]);\n } catch (e) {\n die(`cannot resolve git tag ${opts.tag}: ${e instanceof Error ? e.message : String(e)}`);\n }\n\n // Canonical content = \"oc-stamp/git-tag:v1\\n\" + tag + \"\\n\" + object_id + \"\\n\" + tree_id.\n // Hashed into content.hash; the whole thing is what the stamp commits to.\n const contentBytes = new TextEncoder().encode(\n `oc-stamp/git-tag:v1\\ntag: ${opts.tag}\\nobject: ${tagObjectId}\\ntree: ${treeId}\\n`\n );\n const contentHash = 'sha256:' + createHash('sha256').update(contentBytes).digest('hex');\n const contentLength = contentBytes.byteLength;\n const mime = 'application/x-git-tag';\n const signedAt = new Date().toISOString().replace(/\\.\\d+Z$/, 'Z');\n\n const msg = canonicalMessage({\n address: opts.address,\n content_hash: contentHash,\n content_length: contentLength,\n content_mime: mime,\n signed_at: signedAt,\n });\n\n let signature: string;\n if (opts.sig) {\n signature = opts.sig;\n } else {\n console.error('\\nSign this message with your Bitcoin wallet (BIP-322):\\n');\n console.error('─'.repeat(60));\n console.error(msg);\n console.error('─'.repeat(60));\n console.error();\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n try {\n signature = (await rl.question('paste signature (base64): ')).trim();\n } finally {\n rl.close();\n }\n if (!signature) die('no signature provided');\n }\n\n const envelope: StampEnvelope = await stamp({\n content: { hash: contentHash, length: contentLength },\n mime,\n signer: {\n address: opts.address,\n signMessage: async () => signature,\n },\n signedAt: new Date(signedAt),\n });\n\n let final = envelope;\n if (opts.anchor) {\n try {\n const proof = await submitToCalendars(envelope.id);\n final = { ...envelope, ots: toStampOts(proof) };\n } catch (e) {\n console.error(\n `warning: OTS submission failed (${e instanceof Error ? e.message : String(e)}). ` +\n `The stamp is still valid; you can retry anchoring later with \\`stamp anchor\\`.`\n );\n }\n }\n\n // Store under .git/stamps/<tag>.stamp — keeps stamps co-located with the\n // repo history and discoverable by `git-stamp verify <tag>` without a\n // separate config.\n const gitDir = await gitCapture(['rev-parse', '--git-dir']);\n const stampsDir = `${gitDir}/stamps`;\n await mkdir(stampsDir, { recursive: true });\n const outPath = `${stampsDir}/${opts.tag}.stamp`;\n await writeFile(outPath, JSON.stringify(final, null, 2) + '\\n', 'utf8');\n\n emit(opts.json, {\n ok: true,\n tag: opts.tag,\n tree: treeId,\n object: tagObjectId,\n id: final.id,\n signer: final.signer.address,\n ots: final.ots?.status ?? 'not anchored',\n written: outPath,\n });\n}\n\nexport interface GitVerifyOptions {\n tag: string;\n requireAnchor: boolean;\n json: boolean;\n}\n\nexport async function runGitVerify(opts: GitVerifyOptions): Promise<void> {\n const gitDir = await gitCapture(['rev-parse', '--git-dir']);\n const stampPath = `${gitDir}/stamps/${opts.tag}.stamp`;\n const { runVerify } = await import('./verify.js');\n await runVerify({\n stampPath,\n requireAnchor: opts.requireAnchor,\n skipSignature: false,\n json: opts.json,\n });\n}\n","// `stamp file <path>` — sign a file with a BIP-322 signature from the user's\n// wallet, submit to OTS calendars, write <path>.stamp alongside.\n//\n// The signing step is done out-of-band: we print the canonical message and\n// wait for the user to paste the signature. Wallet CLIs vary too much to\n// automate reliably, so we keep the coupling loose and well-explained.\n\nimport { appendFile, writeFile } from 'node:fs/promises';\nimport { createInterface } from 'node:readline/promises';\n\nimport { canonicalMessage, stamp, type StampEnvelope, type StampStake } from '@orangecheck/stamp-core';\nimport { submitToCalendars, toStampOts } from '@orangecheck/stamp-ots';\n\nimport { die, emit, hashFile, mimeFromPath, pathExists } from '../util.js';\n\nexport interface StampFileOptions {\n path: string;\n address: string;\n mime?: string;\n signedAt?: string;\n stake?: StampStake;\n anchor: boolean;\n out?: string;\n /** If set, pass-through signature (no interactive prompt). */\n sig?: string;\n json: boolean;\n}\n\nexport async function runStampFile(opts: StampFileOptions): Promise<void> {\n if (!(await pathExists(opts.path))) die(`no such file: ${opts.path}`);\n\n const { hash, length } = await hashFile(opts.path);\n const mime = opts.mime ?? mimeFromPath(opts.path);\n const signedAt = opts.signedAt ?? new Date().toISOString().replace(/\\.\\d+Z$/, 'Z');\n\n const msg = canonicalMessage({\n address: opts.address,\n content_hash: hash,\n content_length: length,\n content_mime: mime,\n signed_at: signedAt,\n });\n\n let signature: string;\n if (opts.sig) {\n signature = opts.sig;\n } else {\n // Interactive: print the message, ask for the BIP-322 signature.\n console.error('\\nSign this message with your Bitcoin wallet (BIP-322):\\n');\n console.error('─'.repeat(60));\n console.error(msg);\n console.error('─'.repeat(60));\n console.error();\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n try {\n signature = (await rl.question('paste signature (base64): ')).trim();\n } finally {\n rl.close();\n }\n if (!signature) die('no signature provided');\n }\n\n const envelope: StampEnvelope = await stamp({\n content: { hash, length },\n mime,\n signer: {\n address: opts.address,\n signMessage: async () => signature,\n },\n signedAt: new Date(signedAt),\n stake: opts.stake,\n });\n\n let final = envelope;\n if (opts.anchor) {\n try {\n const proof = await submitToCalendars(envelope.id);\n final = { ...envelope, ots: toStampOts(proof) };\n } catch (e) {\n console.error(\n `warning: OTS submission failed (${e instanceof Error ? e.message : String(e)}). ` +\n `The stamp is still valid; you can retry anchoring later with \\`stamp anchor\\`.`\n );\n }\n }\n\n const outPath = opts.out ?? `${opts.path}.stamp`;\n await writeFile(outPath, JSON.stringify(final, null, 2) + '\\n', 'utf8');\n\n emit(opts.json, {\n ok: true,\n id: final.id,\n signer: final.signer.address,\n signed_at: final.signed_at,\n content_hash: final.content.hash,\n content_length: final.content.length,\n content_mime: final.content.mime,\n ots: final.ots\n ? `${final.ots.status} (${final.ots.calendars.length} calendar${final.ots.calendars.length === 1 ? '' : 's'})`\n : 'not anchored',\n written: outPath,\n });\n void appendFile;\n}\n","/**\n * @orangecheck/stamp-cli — shell interface to OC Stamp.\n *\n * stamp file <path> — sign a file, optionally anchor\n * stamp verify <stamp> [content] — full SPEC §8 verification\n * stamp anchor <stamp> — submit/re-submit to OTS calendars\n * stamp canonical <path> — print the canonical message (dry run)\n *\n * Git aliases (same binary, invoked as `git-stamp`):\n *\n * git-stamp tag <tagname> — stamp a git tag\n * git-stamp verify <tagname> — verify the stored stamp for a tag\n *\n * The `stamp` and `git-stamp` binaries share this entrypoint — we dispatch\n * on argv[1] basename so each alias shows only its relevant subcommands in\n * --help.\n */\n\nimport { basename } from 'node:path';\n\nimport { Command } from 'commander';\n\nimport { runAnchor } from './commands/anchor.js';\nimport { runGitTag, runGitVerify } from './commands/git-tag.js';\nimport { runStampFile } from './commands/stamp-file.js';\nimport { runVerify } from './commands/verify.js';\n\nimport { canonicalMessage } from '@orangecheck/stamp-core';\nimport { hashFile, mimeFromPath } from './util.js';\n\nconst invoked = basename(process.argv[1] ?? 'stamp');\n\nconst program = new Command();\n\nif (invoked.startsWith('git-stamp')) {\n // git-stamp alias: narrow, tag-focused surface.\n program\n .name('git-stamp')\n .description('Stamp git tags with your Bitcoin address, anchored to Bitcoin.')\n .version('0.1.0');\n\n program\n .command('tag <tagname>')\n .description('Sign and (optionally) anchor a stamp over <tagname>^{tree}')\n .requiredOption('--addr <address>', 'Bitcoin address')\n .option('--sig <signature>', 'BIP-322 signature (non-interactive mode)')\n .option('--no-anchor', 'Skip OTS calendar submission')\n .option('--json', 'Emit JSON')\n .action(async (tag, opts) => {\n await runGitTag({\n tag,\n address: opts.addr,\n sig: opts.sig,\n anchor: Boolean(opts.anchor),\n json: Boolean(opts.json),\n });\n });\n\n program\n .command('verify <tagname>')\n .description('Verify the stamp stored under .git/stamps/<tagname>.stamp')\n .option('--require-anchor', 'Fail unless the OTS proof is confirmed')\n .option('--json', 'Emit JSON')\n .action(async (tag, opts) => {\n await runGitVerify({\n tag,\n requireAnchor: Boolean(opts.requireAnchor),\n json: Boolean(opts.json),\n });\n });\n} else {\n program\n .name('stamp')\n .description('OC Stamp — sign anything with your Bitcoin address, anchor to Bitcoin.')\n .version('0.1.0');\n\n program\n .command('file <path>')\n .description('Sign a file and write <path>.stamp alongside')\n .requiredOption('--addr <address>', 'Bitcoin address')\n .option('--mime <type>', 'Override the MIME type (default: inferred from extension)')\n .option('--signed-at <iso>', 'Override signed_at (default: now)')\n .option('--sig <signature>', 'BIP-322 signature (non-interactive mode)')\n .option('--no-anchor', 'Skip OTS calendar submission')\n .option('--out <path>', 'Output path (default: <path>.stamp)')\n .option('--json', 'Emit JSON')\n .action(async (path, opts) => {\n await runStampFile({\n path,\n address: opts.addr,\n mime: opts.mime,\n signedAt: opts.signedAt,\n sig: opts.sig,\n anchor: Boolean(opts.anchor),\n out: opts.out,\n json: Boolean(opts.json),\n });\n });\n\n program\n .command('verify <stamp> [content]')\n .description('Run the full SPEC §8 verification')\n .option('--require-anchor', 'Fail unless the OTS proof is confirmed')\n .option('--skip-signature', 'Skip BIP-322 verification (for CI smoke tests only)')\n .option('--json', 'Emit JSON')\n .action(async (stampPath, contentPath, opts) => {\n await runVerify({\n stampPath,\n contentPath,\n requireAnchor: Boolean(opts.requireAnchor),\n skipSignature: Boolean(opts.skipSignature),\n json: Boolean(opts.json),\n });\n });\n\n program\n .command('anchor <stamp>')\n .description('Submit an existing stamp envelope to OTS calendars')\n .option('--json', 'Emit JSON')\n .action(async (stampPath, opts) => {\n await runAnchor({ stampPath, json: Boolean(opts.json) });\n });\n\n program\n .command('canonical <path>')\n .description('Print the canonical message a stamp over <path> would sign (dry run)')\n .requiredOption('--addr <address>', 'Bitcoin address')\n .option('--mime <type>', 'Override the MIME type')\n .option('--signed-at <iso>', 'Override signed_at (default: now)')\n .action(async (path, opts) => {\n const { hash, length } = await hashFile(path);\n const msg = canonicalMessage({\n address: opts.addr,\n content_hash: hash,\n content_length: length,\n content_mime: opts.mime ?? mimeFromPath(path),\n signed_at: opts.signedAt ?? new Date().toISOString().replace(/\\.\\d+Z$/, 'Z'),\n });\n process.stdout.write(msg);\n // No trailing newline — the canonical message itself has no trailing\n // LF after signed_at, and users pipe this directly into signing tools.\n });\n}\n\nprogram.parseAsync(process.argv).catch((err) => {\n console.error(`error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n});\n"]}
1
+ {"version":3,"sources":["../src/anchor-check.ts","../src/util.ts","../src/commands/verify.ts","../src/commands/anchor.ts","../src/commands/git-tag.ts","../src/commands/stamp-file.ts","../src/cli.ts"],"names":["verify","mempoolHeaderSource","createHash","submitToCalendars","toStampOts","writeFile","runVerify","canonicalMessage","createInterface","stamp","basename"],"mappings":"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","file":"cli.js","sourcesContent":["// SPEC §6.3 / §8 step 5 for the CLI: a claimed OTS anchor is only reported as\n// anchored once the proof chains to the block header at the claimed height.\n\nimport type { StampEnvelope } from '@orangecheck/stamp-core';\nimport {\n fromStampOts,\n makeAnchorVerifier,\n submitToCalendars,\n toStampOts,\n upgradeProof,\n type BlockHeaderSource,\n} from '@orangecheck/stamp-ots';\n\nexport type AnchorState = 'anchored' | 'unverified' | 'pending' | 'none' | 'fail';\n\nexport interface AnchorOutcome {\n state: AnchorState;\n blockHeight?: number;\n message?: string;\n}\n\n/**\n * Check the envelope's anchor claim. A header source that cannot answer leaves\n * the claim unverified (offline verifiers MAY defer, §6.3); a header that\n * answers and does not match fails it.\n */\nexport async function checkAnchorClaim(\n env: StampEnvelope,\n headers: BlockHeaderSource\n): Promise<AnchorOutcome> {\n const ots = env.ots;\n if (!ots) return { state: 'none' };\n if (ots.status !== 'confirmed' || ots.block_height === null || !ots.block_hash) {\n return { state: 'pending' };\n }\n const blockHeight = ots.block_height;\n let header: Uint8Array | null = null;\n try {\n header = await headers.getHeaderAt(blockHeight);\n } catch {\n header = null;\n }\n if (!header) {\n return { state: 'unverified', blockHeight, message: 'block header source unreachable' };\n }\n const verify = makeAnchorVerifier({ headerSource: { getHeaderAt: async () => header } });\n const ok = await verify(ots.proof, blockHeight, ots.block_hash, env.id);\n return ok\n ? { state: 'anchored', blockHeight }\n : { state: 'fail', blockHeight, message: `OTS proof does not chain to block ${blockHeight}` };\n}\n\n/**\n * The next OTS state for an envelope: submit when it has no proof, ask the\n * listed calendars to upgrade a pending one, leave a confirmed one alone.\n */\nexport async function advanceOts(\n env: StampEnvelope,\n opts: { headers: BlockHeaderSource; fetch?: typeof fetch }\n): Promise<StampEnvelope> {\n if (!env.ots) {\n const proof = await submitToCalendars(env.id, { fetch: opts.fetch });\n return { ...env, ots: toStampOts(proof) };\n }\n if (env.ots.status === 'confirmed') return env;\n const next = await upgradeProof(fromStampOts(env.ots), env.id, {\n headerSource: opts.headers,\n fetch: opts.fetch,\n });\n return { ...env, ots: toStampOts(next) };\n}\n","// Shared helpers for stamp-cli commands.\n\nimport { createHash } from 'node:crypto';\nimport { readFile, stat } from 'node:fs/promises';\nimport { basename } from 'node:path';\n\n/** Read a path into bytes. */\nexport async function readBytes(path: string): Promise<Uint8Array> {\n const buf = await readFile(path);\n return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n}\n\n/**\n * Stream-hash a path with SHA-256. For very large content we want to avoid\n * loading the whole file into memory; for small files the cost is negligible.\n */\nexport async function hashFile(path: string): Promise<{ hash: string; length: number }> {\n const bytes = await readBytes(path);\n const h = createHash('sha256').update(bytes).digest('hex');\n return { hash: 'sha256:' + h, length: bytes.byteLength };\n}\n\n/** Infer a conservative MIME from a filename. Falls back to application/octet-stream. */\nexport function mimeFromPath(path: string): string {\n const name = basename(path).toLowerCase();\n const ext = name.split('.').pop();\n switch (ext) {\n case 'md':\n case 'markdown':\n return 'text/markdown';\n case 'txt':\n return 'text/plain';\n case 'html':\n case 'htm':\n return 'text/html';\n case 'json':\n return 'application/json';\n case 'pdf':\n return 'application/pdf';\n case 'png':\n return 'image/png';\n case 'jpg':\n case 'jpeg':\n return 'image/jpeg';\n case 'gif':\n return 'image/gif';\n case 'webp':\n return 'image/webp';\n case 'mp3':\n return 'audio/mpeg';\n case 'mp4':\n return 'video/mp4';\n case 'wav':\n return 'audio/wav';\n case 'zip':\n return 'application/zip';\n case 'tar':\n return 'application/x-tar';\n case 'gz':\n return 'application/gzip';\n default:\n return 'application/octet-stream';\n }\n}\n\nexport async function pathExists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Read JSON from a path or `-` for stdin.\n */\nexport async function readJson<T = unknown>(pathOrDash: string): Promise<T> {\n let text: string;\n if (pathOrDash === '-' || pathOrDash === '/dev/stdin') {\n text = await readStdin();\n } else {\n text = (await readFile(pathOrDash, 'utf8')) as string;\n }\n return JSON.parse(text) as T;\n}\n\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf8');\n process.stdin.on('data', (chunk) => {\n data += chunk;\n });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Emit structured output. */\nexport function emit(json: boolean, result: Record<string, unknown>): void {\n if (json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n for (const [k, v] of Object.entries(result)) {\n console.log(`${k}: ${typeof v === 'object' ? JSON.stringify(v) : v}`);\n }\n }\n}\n\nexport function die(msg: string, code = 1): never {\n console.error(`error: ${msg}`);\n process.exit(code);\n}\n","// `stamp verify <stamp-path> [content-path]` — run the full SPEC §8\n// verification algorithm locally. Structured JSON output with `--json`.\n\nimport { verify, type StampEnvelope } from '@orangecheck/stamp-core';\nimport { mempoolHeaderSource } from '@orangecheck/stamp-ots';\n\nimport { checkAnchorClaim } from '../anchor-check.js';\n\nimport { die, emit, hashFile, pathExists, readBytes, readJson } from '../util.js';\n\nexport interface VerifyOptions {\n stampPath: string;\n contentPath?: string;\n requireAnchor: boolean;\n /**\n * If set, skip the BIP-322 signature verification. Mostly useful for CI\n * smoke tests with placeholder signatures; production verification should\n * never pass this.\n */\n skipSignature: boolean;\n /** Esplora-compatible API for block headers. Default mempool.space. */\n headersUrl?: string;\n json: boolean;\n}\n\nexport async function runVerify(opts: VerifyOptions): Promise<void> {\n if (!(await pathExists(opts.stampPath))) die(`no such file: ${opts.stampPath}`);\n\n const envelope = await readJson<StampEnvelope>(opts.stampPath);\n\n let contentBytes: Uint8Array | undefined;\n if (opts.contentPath) {\n if (!(await pathExists(opts.contentPath))) die(`no such file: ${opts.contentPath}`);\n contentBytes = await readBytes(opts.contentPath);\n }\n\n // Lazy-load bip322-js so it's only pulled in when needed (heavy dep).\n let verifyBip322: ((msg: string, sig: string, addr: string) => Promise<boolean>) | undefined;\n if (!opts.skipSignature) {\n const mod = (await import('bip322-js')) as unknown as {\n Verifier?: { verifySignature(a: string, m: string, s: string): boolean };\n default?: { Verifier?: { verifySignature(a: string, m: string, s: string): boolean } };\n };\n const Verifier = mod.Verifier ?? mod.default?.Verifier;\n if (!Verifier) die('bip322-js Verifier export not found');\n verifyBip322 = async (m, s, a) => {\n try {\n return Verifier.verifySignature(a, m, s);\n } catch {\n return false;\n }\n };\n }\n\n const r = await verify({\n envelope,\n content: contentBytes,\n verifyBip322,\n skipSignatureVerification: opts.skipSignature,\n });\n\n if (!r.ok) {\n emit(opts.json, {\n ok: false,\n code: r.code,\n message: r.message,\n });\n process.exit(2);\n }\n\n const anchor = await checkAnchorClaim(\n envelope,\n mempoolHeaderSource({ baseUrl: opts.headersUrl })\n );\n if (anchor.state === 'fail') {\n emit(opts.json, { ok: false, code: 'E_BAD_ANCHOR', message: anchor.message });\n process.exit(2);\n }\n\n const anchorLabel =\n anchor.state === 'anchored'\n ? `confirmed at block ${anchor.blockHeight} (checked against the block header)`\n : anchor.state === 'unverified'\n ? `claims block ${anchor.blockHeight}, unverified: ${anchor.message}`\n : anchor.state;\n\n if (opts.requireAnchor && anchor.state !== 'anchored') {\n emit(opts.json, {\n ok: false,\n code: 'E_NO_ANCHOR',\n message: `required a verified OTS anchor, got ${anchor.state}`,\n });\n process.exit(2);\n }\n\n emit(opts.json, {\n ok: true,\n id: r.id,\n signer: envelope.signer.address,\n signed_at: envelope.signed_at,\n content_hash: envelope.content.hash,\n content_mime: envelope.content.mime,\n content_length: envelope.content.length,\n content_checked: Boolean(contentBytes),\n anchor: anchorLabel,\n anchor_state: anchor.state,\n signature_checked: !opts.skipSignature,\n stake: envelope.stake,\n });\n void hashFile;\n}\n","// `stamp anchor <stamp-path>` — advance a stamp's OTS proof: submit its id to\n// the calendars when it has none, ask the listed calendars to upgrade a\n// pending one, leave a confirmed one alone.\n\nimport { writeFile } from 'node:fs/promises';\n\nimport type { StampEnvelope } from '@orangecheck/stamp-core';\nimport { mempoolHeaderSource } from '@orangecheck/stamp-ots';\n\nimport { advanceOts } from '../anchor-check.js';\nimport { die, emit, pathExists, readJson } from '../util.js';\n\nexport interface AnchorOptions {\n stampPath: string;\n /** Esplora-compatible API for block headers. Default mempool.space. */\n headersUrl?: string;\n json: boolean;\n}\n\nexport async function runAnchor(opts: AnchorOptions): Promise<void> {\n if (!(await pathExists(opts.stampPath))) die(`no such file: ${opts.stampPath}`);\n const envelope = await readJson<StampEnvelope>(opts.stampPath);\n\n if (envelope.ots?.status === 'confirmed') {\n emit(opts.json, {\n ok: true,\n already: 'confirmed',\n block_height: envelope.ots.block_height,\n });\n return;\n }\n\n let next: StampEnvelope;\n try {\n next = await advanceOts(envelope, {\n headers: mempoolHeaderSource({ baseUrl: opts.headersUrl }),\n });\n } catch (e) {\n die(`OTS ${envelope.ots ? 'upgrade' : 'submission'} failed: ${e instanceof Error ? e.message : String(e)}`);\n }\n const changed = JSON.stringify(next.ots) !== JSON.stringify(envelope.ots);\n if (changed) {\n await writeFile(opts.stampPath, JSON.stringify(next, null, 2) + '\\n', 'utf8');\n }\n emit(opts.json, {\n ok: true,\n id: next.id,\n status: next.ots?.status,\n block_height: next.ots?.block_height ?? null,\n calendars: next.ots?.calendars ?? [],\n written: changed ? opts.stampPath : null,\n });\n}\n","// `git-stamp tag <tagname>` — stamp a git tag's tree. Meant to be invoked as\n// `git-stamp tag v1.2.3` (the same binary as `stamp`; we detect the alias\n// from argv[1] basename and also accept explicit `git tag` subcommand).\n//\n// The stamp covers the `git rev-parse <tag>^{tree}` output concatenated with\n// the tag name and object id, so changing any of (tree contents, tag object,\n// or tag name) invalidates the envelope.\n\nimport { execFile } from 'node:child_process';\nimport { writeFile, mkdir } from 'node:fs/promises';\nimport { promisify } from 'node:util';\n\nimport { createHash } from 'node:crypto';\nimport { canonicalMessage, stamp, type StampEnvelope } from '@orangecheck/stamp-core';\nimport { submitToCalendars, toStampOts } from '@orangecheck/stamp-ots';\n\nimport { die, emit } from '../util.js';\nimport { createInterface } from 'node:readline/promises';\n\nconst exec = promisify(execFile);\n\nexport interface GitTagOptions {\n tag: string;\n address: string;\n sig?: string;\n anchor: boolean;\n json: boolean;\n}\n\nasync function gitCapture(args: string[]): Promise<string> {\n const { stdout } = await exec('git', args);\n return stdout.trim();\n}\n\nexport async function runGitTag(opts: GitTagOptions): Promise<void> {\n // Validate that we're inside a git repo.\n try {\n await gitCapture(['rev-parse', '--is-inside-work-tree']);\n } catch {\n die('not inside a git work tree');\n }\n\n // Resolve the tag to its commit + tree, and the tag object itself.\n let treeId: string;\n let tagObjectId: string;\n try {\n treeId = await gitCapture(['rev-parse', `${opts.tag}^{tree}`]);\n tagObjectId = await gitCapture(['rev-parse', opts.tag]);\n } catch (e) {\n die(`cannot resolve git tag ${opts.tag}: ${e instanceof Error ? e.message : String(e)}`);\n }\n\n // Canonical content = \"oc-stamp/git-tag:v1\\n\" + tag + \"\\n\" + object_id + \"\\n\" + tree_id.\n // Hashed into content.hash; the whole thing is what the stamp commits to.\n const contentBytes = new TextEncoder().encode(\n `oc-stamp/git-tag:v1\\ntag: ${opts.tag}\\nobject: ${tagObjectId}\\ntree: ${treeId}\\n`\n );\n const contentHash = 'sha256:' + createHash('sha256').update(contentBytes).digest('hex');\n const contentLength = contentBytes.byteLength;\n const mime = 'application/x-git-tag';\n const signedAt = new Date().toISOString().replace(/\\.\\d+Z$/, 'Z');\n\n const msg = canonicalMessage({\n address: opts.address,\n content_hash: contentHash,\n content_length: contentLength,\n content_mime: mime,\n signed_at: signedAt,\n });\n\n let signature: string;\n if (opts.sig) {\n signature = opts.sig;\n } else {\n console.error('\\nSign this message with your Bitcoin wallet (BIP-322):\\n');\n console.error('─'.repeat(60));\n console.error(msg);\n console.error('─'.repeat(60));\n console.error();\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n try {\n signature = (await rl.question('paste signature (base64): ')).trim();\n } finally {\n rl.close();\n }\n if (!signature) die('no signature provided');\n }\n\n const envelope: StampEnvelope = await stamp({\n content: { hash: contentHash, length: contentLength },\n mime,\n signer: {\n address: opts.address,\n signMessage: async () => signature,\n },\n signedAt: new Date(signedAt),\n });\n\n let final = envelope;\n if (opts.anchor) {\n try {\n const proof = await submitToCalendars(envelope.id);\n final = { ...envelope, ots: toStampOts(proof) };\n } catch (e) {\n console.error(\n `warning: OTS submission failed (${e instanceof Error ? e.message : String(e)}). ` +\n `The stamp is still valid; you can retry anchoring later with \\`stamp anchor\\`.`\n );\n }\n }\n\n // Store under .git/stamps/<tag>.stamp — keeps stamps co-located with the\n // repo history and discoverable by `git-stamp verify <tag>` without a\n // separate config.\n const gitDir = await gitCapture(['rev-parse', '--git-dir']);\n const stampsDir = `${gitDir}/stamps`;\n await mkdir(stampsDir, { recursive: true });\n const outPath = `${stampsDir}/${opts.tag}.stamp`;\n await writeFile(outPath, JSON.stringify(final, null, 2) + '\\n', 'utf8');\n\n emit(opts.json, {\n ok: true,\n tag: opts.tag,\n tree: treeId,\n object: tagObjectId,\n id: final.id,\n signer: final.signer.address,\n ots: final.ots?.status ?? 'not anchored',\n written: outPath,\n });\n}\n\nexport interface GitVerifyOptions {\n tag: string;\n requireAnchor: boolean;\n json: boolean;\n}\n\nexport async function runGitVerify(opts: GitVerifyOptions): Promise<void> {\n const gitDir = await gitCapture(['rev-parse', '--git-dir']);\n const stampPath = `${gitDir}/stamps/${opts.tag}.stamp`;\n const { runVerify } = await import('./verify.js');\n await runVerify({\n stampPath,\n requireAnchor: opts.requireAnchor,\n skipSignature: false,\n json: opts.json,\n });\n}\n","// `stamp file <path>` — sign a file with a BIP-322 signature from the user's\n// wallet, submit to OTS calendars, write <path>.stamp alongside.\n//\n// The signing step is done out-of-band: we print the canonical message and\n// wait for the user to paste the signature. Wallet CLIs vary too much to\n// automate reliably, so we keep the coupling loose and well-explained.\n\nimport { appendFile, writeFile } from 'node:fs/promises';\nimport { createInterface } from 'node:readline/promises';\n\nimport { canonicalMessage, stamp, type StampEnvelope, type StampStake } from '@orangecheck/stamp-core';\nimport { submitToCalendars, toStampOts } from '@orangecheck/stamp-ots';\n\nimport { die, emit, hashFile, mimeFromPath, pathExists } from '../util.js';\n\nexport interface StampFileOptions {\n path: string;\n address: string;\n mime?: string;\n signedAt?: string;\n stake?: StampStake;\n anchor: boolean;\n out?: string;\n /** If set, pass-through signature (no interactive prompt). */\n sig?: string;\n json: boolean;\n}\n\nexport async function runStampFile(opts: StampFileOptions): Promise<void> {\n if (!(await pathExists(opts.path))) die(`no such file: ${opts.path}`);\n\n const { hash, length } = await hashFile(opts.path);\n const mime = opts.mime ?? mimeFromPath(opts.path);\n const signedAt = opts.signedAt ?? new Date().toISOString().replace(/\\.\\d+Z$/, 'Z');\n\n const msg = canonicalMessage({\n address: opts.address,\n content_hash: hash,\n content_length: length,\n content_mime: mime,\n signed_at: signedAt,\n });\n\n let signature: string;\n if (opts.sig) {\n signature = opts.sig;\n } else {\n // Interactive: print the message, ask for the BIP-322 signature.\n console.error('\\nSign this message with your Bitcoin wallet (BIP-322):\\n');\n console.error('─'.repeat(60));\n console.error(msg);\n console.error('─'.repeat(60));\n console.error();\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n try {\n signature = (await rl.question('paste signature (base64): ')).trim();\n } finally {\n rl.close();\n }\n if (!signature) die('no signature provided');\n }\n\n const envelope: StampEnvelope = await stamp({\n content: { hash, length },\n mime,\n signer: {\n address: opts.address,\n signMessage: async () => signature,\n },\n signedAt: new Date(signedAt),\n stake: opts.stake,\n });\n\n let final = envelope;\n if (opts.anchor) {\n try {\n const proof = await submitToCalendars(envelope.id);\n final = { ...envelope, ots: toStampOts(proof) };\n } catch (e) {\n console.error(\n `warning: OTS submission failed (${e instanceof Error ? e.message : String(e)}). ` +\n `The stamp is still valid; you can retry anchoring later with \\`stamp anchor\\`.`\n );\n }\n }\n\n const outPath = opts.out ?? `${opts.path}.stamp`;\n await writeFile(outPath, JSON.stringify(final, null, 2) + '\\n', 'utf8');\n\n emit(opts.json, {\n ok: true,\n id: final.id,\n signer: final.signer.address,\n signed_at: final.signed_at,\n content_hash: final.content.hash,\n content_length: final.content.length,\n content_mime: final.content.mime,\n ots: final.ots\n ? `${final.ots.status} (${final.ots.calendars.length} calendar${final.ots.calendars.length === 1 ? '' : 's'})`\n : 'not anchored',\n written: outPath,\n });\n void appendFile;\n}\n","/**\n * @orangecheck/stamp-cli — shell interface to OC Stamp.\n *\n * stamp file <path> — sign a file, optionally anchor\n * stamp verify <stamp> [content] — full SPEC §8 verification\n * stamp anchor <stamp> — submit to OTS calendars, or upgrade a pending proof\n * stamp canonical <path> — print the canonical message (dry run)\n *\n * Git aliases (same binary, invoked as `git-stamp`):\n *\n * git-stamp tag <tagname> — stamp a git tag\n * git-stamp verify <tagname> — verify the stored stamp for a tag\n *\n * The `stamp` and `git-stamp` binaries share this entrypoint — we dispatch\n * on argv[1] basename so each alias shows only its relevant subcommands in\n * --help.\n */\n\nimport { basename } from 'node:path';\n\nimport { Command } from 'commander';\n\nimport { runAnchor } from './commands/anchor.js';\nimport { runGitTag, runGitVerify } from './commands/git-tag.js';\nimport { runStampFile } from './commands/stamp-file.js';\nimport { runVerify } from './commands/verify.js';\n\nimport { canonicalMessage } from '@orangecheck/stamp-core';\nimport { hashFile, mimeFromPath } from './util.js';\n\nconst invoked = basename(process.argv[1] ?? 'stamp');\n\nconst program = new Command();\n\nif (invoked.startsWith('git-stamp')) {\n // git-stamp alias: narrow, tag-focused surface.\n program\n .name('git-stamp')\n .description('Stamp git tags with your Bitcoin address, anchored to Bitcoin.')\n .version('0.2.0');\n\n program\n .command('tag <tagname>')\n .description('Sign and (optionally) anchor a stamp over <tagname>^{tree}')\n .requiredOption('--addr <address>', 'Bitcoin address')\n .option('--sig <signature>', 'BIP-322 signature (non-interactive mode)')\n .option('--no-anchor', 'Skip OTS calendar submission')\n .option('--json', 'Emit JSON')\n .action(async (tag, opts) => {\n await runGitTag({\n tag,\n address: opts.addr,\n sig: opts.sig,\n anchor: Boolean(opts.anchor),\n json: Boolean(opts.json),\n });\n });\n\n program\n .command('verify <tagname>')\n .description('Verify the stamp stored under .git/stamps/<tagname>.stamp')\n .option('--require-anchor', 'Fail unless the OTS anchor is confirmed and checked against the block header')\n .option('--json', 'Emit JSON')\n .action(async (tag, opts) => {\n await runGitVerify({\n tag,\n requireAnchor: Boolean(opts.requireAnchor),\n json: Boolean(opts.json),\n });\n });\n} else {\n program\n .name('stamp')\n .description('OC Stamp — sign anything with your Bitcoin address, anchor to Bitcoin.')\n .version('0.2.0');\n\n program\n .command('file <path>')\n .description('Sign a file and write <path>.stamp alongside')\n .requiredOption('--addr <address>', 'Bitcoin address')\n .option('--mime <type>', 'Override the MIME type (default: inferred from extension)')\n .option('--signed-at <iso>', 'Override signed_at (default: now)')\n .option('--sig <signature>', 'BIP-322 signature (non-interactive mode)')\n .option('--no-anchor', 'Skip OTS calendar submission')\n .option('--out <path>', 'Output path (default: <path>.stamp)')\n .option('--json', 'Emit JSON')\n .action(async (path, opts) => {\n await runStampFile({\n path,\n address: opts.addr,\n mime: opts.mime,\n signedAt: opts.signedAt,\n sig: opts.sig,\n anchor: Boolean(opts.anchor),\n out: opts.out,\n json: Boolean(opts.json),\n });\n });\n\n program\n .command('verify <stamp> [content]')\n .description('Run the full SPEC §8 verification')\n .option('--require-anchor', 'Fail unless the OTS anchor is confirmed and checked against the block header')\n .option('--skip-signature', 'Skip BIP-322 verification (for CI smoke tests only)')\n .option('--headers-url <url>', 'Esplora API for block headers (default: https://mempool.space/api)')\n .option('--json', 'Emit JSON')\n .action(async (stampPath, contentPath, opts) => {\n await runVerify({\n stampPath,\n contentPath,\n requireAnchor: Boolean(opts.requireAnchor),\n skipSignature: Boolean(opts.skipSignature),\n headersUrl: opts.headersUrl,\n json: Boolean(opts.json),\n });\n });\n\n program\n .command('anchor <stamp>')\n .description('Submit a stamp to OTS calendars, or upgrade its pending proof')\n .option('--headers-url <url>', 'Esplora API for block headers (default: https://mempool.space/api)')\n .option('--json', 'Emit JSON')\n .action(async (stampPath, opts) => {\n await runAnchor({ stampPath, headersUrl: opts.headersUrl, json: Boolean(opts.json) });\n });\n\n program\n .command('canonical <path>')\n .description('Print the canonical message a stamp over <path> would sign (dry run)')\n .requiredOption('--addr <address>', 'Bitcoin address')\n .option('--mime <type>', 'Override the MIME type')\n .option('--signed-at <iso>', 'Override signed_at (default: now)')\n .action(async (path, opts) => {\n const { hash, length } = await hashFile(path);\n const msg = canonicalMessage({\n address: opts.addr,\n content_hash: hash,\n content_length: length,\n content_mime: opts.mime ?? mimeFromPath(path),\n signed_at: opts.signedAt ?? new Date().toISOString().replace(/\\.\\d+Z$/, 'Z'),\n });\n process.stdout.write(msg);\n // No trailing newline — the canonical message itself has no trailing\n // LF after signed_at, and users pipe this directly into signing tools.\n });\n}\n\nprogram.parseAsync(process.argv).catch((err) => {\n console.error(`error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n});\n"]}
package/package.json CHANGED
@@ -1,58 +1,61 @@
1
1
  {
2
- "name": "@orangecheck/stamp-cli",
3
- "version": "0.1.0",
4
- "description": "Shell interface to OC Stamp — sign files and git tags with your Bitcoin address, anchor to Bitcoin, verify offline. Exposes `stamp` and `git-stamp` binaries.",
5
- "keywords": [
6
- "bitcoin",
7
- "bip322",
8
- "opentimestamps",
9
- "provenance",
10
- "oc-stamp",
11
- "git-stamp",
12
- "cli",
13
- "orangecheck"
14
- ],
15
- "author": "OrangeCheck",
16
- "license": "MIT",
17
- "repository": {
18
- "type": "git",
19
- "url": "https://github.com/orangecheck/oc-packages.git",
20
- "directory": "stamp-cli"
21
- },
22
- "homepage": "https://stamp.ochk.io",
23
- "bugs": {
24
- "url": "https://github.com/orangecheck/oc-stamp-protocol/issues"
25
- },
26
- "type": "module",
27
- "bin": {
28
- "stamp": "./dist/cli.js",
29
- "git-stamp": "./dist/cli.js"
30
- },
31
- "main": "./dist/cli.js",
32
- "files": [
33
- "dist",
34
- "README.md",
35
- "LICENSE"
36
- ],
37
- "scripts": {
38
- "build": "tsup",
39
- "dev": "tsup --watch",
40
- "type-check": "tsc --noEmit",
41
- "test": "vitest run",
42
- "test:watch": "vitest",
43
- "clean": "rm -rf dist",
44
- "prepublishOnly": "npm run clean && npm run build"
45
- },
46
- "dependencies": {
47
- "@orangecheck/stamp-core": "^0.1.2",
48
- "@orangecheck/stamp-ots": "^0.1.1",
49
- "bip322-js": "^3.0.0",
50
- "commander": "^12.1.0"
51
- },
52
- "devDependencies": {
53
- "@types/node": "^22.10.2",
54
- "tsup": "^8.3.5",
55
- "typescript": "^5.7.2",
56
- "vitest": "^3.2.4"
57
- }
2
+ "name": "@orangecheck/stamp-cli",
3
+ "version": "0.2.0",
4
+ "description": "Shell interface to OC Stamp — sign files and git tags with your Bitcoin address, anchor to Bitcoin, verify offline. Exposes `stamp` and `git-stamp` binaries.",
5
+ "keywords": [
6
+ "bitcoin",
7
+ "bip322",
8
+ "opentimestamps",
9
+ "provenance",
10
+ "oc-stamp",
11
+ "git-stamp",
12
+ "cli",
13
+ "orangecheck"
14
+ ],
15
+ "author": "OrangeCheck",
16
+ "license": "MIT",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/orangecheck/oc-packages.git",
20
+ "directory": "stamp-cli"
21
+ },
22
+ "homepage": "https://stamp.ochk.io",
23
+ "bugs": {
24
+ "url": "https://github.com/orangecheck/oc-stamp-protocol/issues"
25
+ },
26
+ "type": "module",
27
+ "bin": {
28
+ "stamp": "./dist/cli.js",
29
+ "git-stamp": "./dist/cli.js"
30
+ },
31
+ "main": "./dist/cli.js",
32
+ "files": [
33
+ "dist",
34
+ "README.md",
35
+ "LICENSE"
36
+ ],
37
+ "scripts": {
38
+ "build": "tsup",
39
+ "dev": "tsup --watch",
40
+ "type-check": "tsc --noEmit",
41
+ "test": "vitest run",
42
+ "test:watch": "vitest",
43
+ "clean": "rm -rf dist",
44
+ "prepublishOnly": "npm run clean && npm run build"
45
+ },
46
+ "dependencies": {
47
+ "@orangecheck/stamp-core": "^1.0.0",
48
+ "@orangecheck/stamp-ots": "^0.3.0",
49
+ "bip322-js": "^3.0.0",
50
+ "commander": "^12.1.0"
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "^22.10.2",
54
+ "tsup": "^8.3.5",
55
+ "typescript": "^5.7.2",
56
+ "vitest": "^4.1.11"
57
+ },
58
+ "publishConfig": {
59
+ "access": "public"
60
+ }
58
61
  }