@bcts/provenance-mark-cli 1.0.0-alpha.13

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.
@@ -0,0 +1,889 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) {
13
+ __defProp(to, key, {
14
+ get: ((k) => from[k]).bind(null, key),
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ });
17
+ }
18
+ }
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
23
+ value: mod,
24
+ enumerable: true
25
+ }) : target, mod));
26
+
27
+ //#endregion
28
+ let fs = require("fs");
29
+ fs = __toESM(fs);
30
+ let path = require("path");
31
+ path = __toESM(path);
32
+ let _bcts_dcbor = require("@bcts/dcbor");
33
+ let _bcts_uniform_resources = require("@bcts/uniform-resources");
34
+ let _bcts_components = require("@bcts/components");
35
+ let _bcts_provenance_mark = require("@bcts/provenance-mark");
36
+ let _bcts_envelope = require("@bcts/envelope");
37
+ let _bcts_known_values = require("@bcts/known-values");
38
+
39
+ //#region src/utils.ts
40
+ /**
41
+ * Utilities module - 1:1 port of utils.rs
42
+ *
43
+ * Helper functions for CLI operations.
44
+ */
45
+ /**
46
+ * Read a new path, supporting globbing, and resolving relative paths.
47
+ *
48
+ * Corresponds to Rust `read_new_path()`
49
+ */
50
+ function readNewPath(pathStr) {
51
+ let effectivePath;
52
+ if (path.isAbsolute(pathStr)) effectivePath = pathStr;
53
+ else {
54
+ const currentDir = process.cwd();
55
+ effectivePath = path.join(currentDir, pathStr);
56
+ }
57
+ return path.normalize(effectivePath);
58
+ }
59
+ /**
60
+ * Read an existing directory path, supporting globbing, and resolving relative paths.
61
+ *
62
+ * Corresponds to Rust `read_existing_directory_path()`
63
+ */
64
+ function readExistingDirectoryPath(pathStr) {
65
+ const effectivePath = readNewPath(pathStr);
66
+ if (!fs.existsSync(effectivePath)) throw new Error(`Path does not exist: ${effectivePath}`);
67
+ if (!fs.statSync(effectivePath).isDirectory()) throw new Error(`Path is not a directory: ${effectivePath}`);
68
+ return effectivePath;
69
+ }
70
+ /**
71
+ * Read an argument from command line or stdin.
72
+ *
73
+ * Corresponds to Rust `read_argument()`
74
+ */
75
+ function readArgument(argument) {
76
+ if (argument !== void 0 && argument !== "") return argument;
77
+ const input = readStdinSync();
78
+ if (input.trim() === "") throw new Error("No argument provided");
79
+ return input.trim();
80
+ }
81
+ /**
82
+ * Read all stdin synchronously.
83
+ */
84
+ function readStdinSync() {
85
+ let input = "";
86
+ const BUFSIZE = 256;
87
+ const buf = Buffer.alloc(BUFSIZE);
88
+ try {
89
+ const fd = process.stdin.fd;
90
+ while (true) try {
91
+ const bytesRead = fs.readSync(fd, buf, 0, BUFSIZE, null);
92
+ if (bytesRead === 0) break;
93
+ input += buf.toString("utf8", 0, bytesRead);
94
+ } catch {
95
+ break;
96
+ }
97
+ } catch {}
98
+ return input;
99
+ }
100
+ /**
101
+ * Convert bytes to hex string.
102
+ */
103
+ function bytesToHex(bytes) {
104
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
105
+ }
106
+ /**
107
+ * Convert hex string to bytes.
108
+ */
109
+ function hexToBytes(hex) {
110
+ const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
111
+ const bytes = new Uint8Array(cleanHex.length / 2);
112
+ for (let i = 0; i < cleanHex.length; i += 2) bytes[i / 2] = parseInt(cleanHex.slice(i, i + 2), 16);
113
+ return bytes;
114
+ }
115
+ /**
116
+ * Convert bytes to base64 string.
117
+ */
118
+ function toBase64(bytes) {
119
+ return Buffer.from(bytes).toString("base64");
120
+ }
121
+ /**
122
+ * Convert base64 string to bytes.
123
+ */
124
+ function fromBase64(base64) {
125
+ return new Uint8Array(Buffer.from(base64, "base64"));
126
+ }
127
+
128
+ //#endregion
129
+ //#region src/cmd/info.ts
130
+ /**
131
+ * Info args - 1:1 port of info.rs
132
+ *
133
+ * Shared arguments for supplying provenance mark `info` payloads.
134
+ */
135
+ /**
136
+ * Parse info args to CBOR.
137
+ *
138
+ * Corresponds to Rust `InfoArgs::to_cbor()`
139
+ */
140
+ function parseInfoArgs(args) {
141
+ if (args.info !== void 0) return parseInfo(args.info, args.infoTag);
142
+ if (args.infoTag !== void 0) throw new Error("--info-tag requires a UR payload");
143
+ }
144
+ /**
145
+ * Parse hex-encoded CBOR.
146
+ *
147
+ * Corresponds to Rust `parse_hex()`
148
+ */
149
+ function parseHex(input) {
150
+ const trimmed = input.trim();
151
+ const hexStr = trimmed.startsWith("0x") ? trimmed.slice(2) : trimmed;
152
+ try {
153
+ return (0, _bcts_dcbor.decodeCbor)(hexToBytes(hexStr));
154
+ } catch (e) {
155
+ const message = e instanceof Error ? e.message : String(e);
156
+ throw new Error(`failed to decode hex info payload: ${message}`);
157
+ }
158
+ }
159
+ /**
160
+ * Parse info payload from raw string.
161
+ *
162
+ * Corresponds to Rust `parse_info()`
163
+ */
164
+ function parseInfo(raw, tagOverride) {
165
+ const trimmed = raw.trim();
166
+ if (trimmed === "") throw new Error("info payload must not be empty");
167
+ if (trimmed.length >= 3 && trimmed.slice(0, 3).toLowerCase() === "ur:") return parseUrPayload(trimmed, tagOverride);
168
+ try {
169
+ const cborResult = parseHex(trimmed);
170
+ if (tagOverride !== void 0) throw new Error("--info-tag is only valid when the payload is a UR");
171
+ return cborResult;
172
+ } catch (hexErr) {
173
+ try {
174
+ return parseUrPayload(trimmed, tagOverride);
175
+ } catch (urErr) {
176
+ const hexMsg = hexErr instanceof Error ? hexErr.message : String(hexErr);
177
+ const urMsg = urErr instanceof Error ? urErr.message : String(urErr);
178
+ throw new Error(`failed to parse --info payload as hex (${hexMsg}) or UR (${urMsg})`);
179
+ }
180
+ }
181
+ }
182
+ /**
183
+ * Parse UR payload.
184
+ *
185
+ * Corresponds to Rust `parse_ur_payload()`
186
+ */
187
+ function parseUrPayload(input, tagOverride) {
188
+ let ur;
189
+ try {
190
+ ur = _bcts_uniform_resources.UR.fromURString(input.trim());
191
+ } catch (e) {
192
+ const message = e instanceof Error ? e.message : String(e);
193
+ throw new Error(`failed to parse UR info payload: ${message}`);
194
+ }
195
+ const typeStr = ur.urTypeStr();
196
+ const registeredTag = (0, _bcts_dcbor.getGlobalTagsStore)().tagForName(typeStr);
197
+ const registeredTagValue = registeredTag !== void 0 ? Number(registeredTag.value) : void 0;
198
+ if (registeredTagValue !== void 0 && tagOverride !== void 0) throw new Error(`UR type '${typeStr}' has a known CBOR tag; --info-tag must not be supplied`);
199
+ const expectedTag = registeredTagValue ?? tagOverride;
200
+ if (expectedTag === void 0) throw new Error(`UR type '${typeStr}' is not registered; supply --info-tag with the CBOR tag value`);
201
+ return ensureTag(ur.cbor(), expectedTag, typeStr);
202
+ }
203
+ /**
204
+ * Ensure CBOR has the expected tag.
205
+ *
206
+ * Corresponds to Rust `ensure_tag()`
207
+ */
208
+ function ensureTag(cborValue, expectedTag, typeStr) {
209
+ if ((0, _bcts_dcbor.isTagged)(cborValue)) {
210
+ const tag = (0, _bcts_dcbor.tagValue)(cborValue);
211
+ if (tag !== BigInt(expectedTag)) throw new Error(`UR type '${typeStr}' encodes CBOR tag ${tag} but ${expectedTag} was expected`);
212
+ return cborValue;
213
+ }
214
+ return (0, _bcts_dcbor.cbor)({
215
+ tag: expectedTag,
216
+ value: cborValue
217
+ });
218
+ }
219
+
220
+ //#endregion
221
+ //#region src/cmd/seed.ts
222
+ /**
223
+ * Seed parsing - 1:1 port of seed.rs
224
+ *
225
+ * Functions for parsing provenance seeds from various formats.
226
+ */
227
+ /**
228
+ * Parse a seed from a string.
229
+ *
230
+ * Supports the following formats:
231
+ * - `ur:seed/...` - UR-encoded seed
232
+ * - `0x...` or hex string - Hex-encoded seed
233
+ * - Base64 string - Base64-encoded seed
234
+ *
235
+ * Corresponds to Rust `parse_seed()`
236
+ */
237
+ function parseSeed(input) {
238
+ const trimmed = input.trim();
239
+ if (trimmed === "") throw new Error("seed string is empty");
240
+ if (trimmed.toLowerCase().startsWith("ur:")) return parseSeedUr(trimmed);
241
+ const hexResult = parseSeedHex(trimmed);
242
+ if (hexResult !== void 0) return hexResult;
243
+ return parseSeedBase64(trimmed);
244
+ }
245
+ /**
246
+ * Parse a seed from a UR string.
247
+ *
248
+ * Corresponds to Rust `parse_seed_ur()`
249
+ */
250
+ function parseSeedUr(input) {
251
+ try {
252
+ const ur = _bcts_uniform_resources.UR.fromURString(input);
253
+ return seedFromExact(_bcts_components.Seed.fromUR(ur).toData());
254
+ } catch (e) {
255
+ const message = e instanceof Error ? e.message : String(e);
256
+ throw new Error(`failed to parse seed UR: ${message}`);
257
+ }
258
+ }
259
+ /**
260
+ * Parse a seed from a hex string.
261
+ *
262
+ * Returns undefined if the string is not valid hex format.
263
+ *
264
+ * Corresponds to Rust `parse_seed_hex()`
265
+ */
266
+ function parseSeedHex(input) {
267
+ const source = input.startsWith("0x") ? input.slice(2) : input;
268
+ if (source === "") return;
269
+ if (source.length % 2 !== 0) return;
270
+ if (!/^[0-9a-fA-F]+$/.test(source)) return;
271
+ try {
272
+ return seedFromExact(hexToBytes(source));
273
+ } catch (e) {
274
+ const message = e instanceof Error ? e.message : String(e);
275
+ throw new Error(`failed to decode hex seed: ${message}`);
276
+ }
277
+ }
278
+ /**
279
+ * Parse a seed from a base64 string.
280
+ *
281
+ * Corresponds to Rust `parse_seed_base64()`
282
+ */
283
+ function parseSeedBase64(input) {
284
+ try {
285
+ return seedFromExact(fromBase64(input));
286
+ } catch (e) {
287
+ const message = e instanceof Error ? e.message : String(e);
288
+ throw new Error(`failed to decode base64 seed: ${message}`);
289
+ }
290
+ }
291
+ /**
292
+ * Create a seed from exactly PROVENANCE_SEED_LENGTH bytes.
293
+ *
294
+ * Corresponds to Rust `seed_from_exact()`
295
+ */
296
+ function seedFromExact(bytes) {
297
+ if (bytes.length !== _bcts_provenance_mark.PROVENANCE_SEED_LENGTH) throw new Error(`seed must be ${_bcts_provenance_mark.PROVENANCE_SEED_LENGTH} bytes but found ${bytes.length}`);
298
+ return _bcts_provenance_mark.ProvenanceSeed.fromBytes(bytes);
299
+ }
300
+
301
+ //#endregion
302
+ //#region src/cmd/new.ts
303
+ /**
304
+ * New command - 1:1 port of new.rs
305
+ *
306
+ * Initialize a directory with a new provenance mark chain.
307
+ */
308
+ /**
309
+ * Output format for the creation summary.
310
+ *
311
+ * Corresponds to Rust `OutputFormat`
312
+ */
313
+ let OutputFormat = /* @__PURE__ */ function(OutputFormat$1) {
314
+ OutputFormat$1["Markdown"] = "markdown";
315
+ OutputFormat$1["Ur"] = "ur";
316
+ OutputFormat$1["Json"] = "json";
317
+ return OutputFormat$1;
318
+ }({});
319
+ /**
320
+ * Resolution level for the provenance mark chain.
321
+ *
322
+ * Corresponds to Rust `Resolution`
323
+ */
324
+ let Resolution = /* @__PURE__ */ function(Resolution$1) {
325
+ /** Good for physical works of art and applications requiring minimal mark size. */
326
+ Resolution$1["Low"] = "low";
327
+ /** Good for digital works of art. */
328
+ Resolution$1["Medium"] = "medium";
329
+ /** Good for general use. */
330
+ Resolution$1["Quartile"] = "quartile";
331
+ /** Industrial strength, largest mark. */
332
+ Resolution$1["High"] = "high";
333
+ return Resolution$1;
334
+ }({});
335
+ /**
336
+ * Convert Resolution to ProvenanceMarkResolution.
337
+ */
338
+ function resolutionToProvenanceMarkResolution(res) {
339
+ switch (res) {
340
+ case Resolution.Low: return _bcts_provenance_mark.ProvenanceMarkResolution.Low;
341
+ case Resolution.Medium: return _bcts_provenance_mark.ProvenanceMarkResolution.Medium;
342
+ case Resolution.Quartile: return _bcts_provenance_mark.ProvenanceMarkResolution.Quartile;
343
+ case Resolution.High: return _bcts_provenance_mark.ProvenanceMarkResolution.High;
344
+ }
345
+ }
346
+ /**
347
+ * Parse a resolution string.
348
+ */
349
+ function parseResolution(value) {
350
+ switch (value.toLowerCase()) {
351
+ case "low": return Resolution.Low;
352
+ case "medium": return Resolution.Medium;
353
+ case "quartile": return Resolution.Quartile;
354
+ case "high": return Resolution.High;
355
+ default: throw new Error(`Invalid resolution: ${value}. Must be one of: low, medium, quartile, high`);
356
+ }
357
+ }
358
+ /**
359
+ * Parse an output format string.
360
+ */
361
+ function parseOutputFormat(value) {
362
+ switch (value.toLowerCase()) {
363
+ case "markdown": return OutputFormat.Markdown;
364
+ case "ur": return OutputFormat.Ur;
365
+ case "json": return OutputFormat.Json;
366
+ default: throw new Error(`Invalid format: ${value}. Must be one of: markdown, ur, json`);
367
+ }
368
+ }
369
+ /**
370
+ * Create default args for the new command.
371
+ */
372
+ function defaultNewCommandArgs() {
373
+ return {
374
+ path: "",
375
+ resolution: Resolution.Quartile,
376
+ comment: "Genesis mark.",
377
+ quiet: false,
378
+ format: OutputFormat.Markdown,
379
+ info: {}
380
+ };
381
+ }
382
+ /**
383
+ * New command implementation.
384
+ *
385
+ * Corresponds to Rust `impl Exec for CommandArgs`
386
+ */
387
+ var NewCommand = class {
388
+ args;
389
+ constructor(args) {
390
+ this.args = args;
391
+ }
392
+ exec() {
393
+ const dirPath = this.createDir();
394
+ const marksPath = path.join(dirPath, "marks");
395
+ fs.mkdirSync(marksPath);
396
+ const resolution = resolutionToProvenanceMarkResolution(this.args.resolution);
397
+ let generator;
398
+ if (this.args.seed !== void 0) generator = _bcts_provenance_mark.ProvenanceMarkGenerator.newWithSeed(resolution, this.args.seed);
399
+ else generator = _bcts_provenance_mark.ProvenanceMarkGenerator.newRandom(resolution);
400
+ const date = this.args.date ?? /* @__PURE__ */ new Date();
401
+ const info = parseInfoArgs(this.args.info);
402
+ const mark = generator.next(date, info);
403
+ const markInfo = _bcts_provenance_mark.ProvenanceMarkInfo.new(mark, this.args.comment);
404
+ const markJson = JSON.stringify(markInfo.toJSON(), null, 2);
405
+ const markPath = path.join(marksPath, `mark-${mark.seq()}.json`);
406
+ fs.writeFileSync(markPath, markJson);
407
+ const generatorJson = JSON.stringify(generator.toJSON(), null, 2);
408
+ const generatorPath = path.join(dirPath, "generator.json");
409
+ fs.writeFileSync(generatorPath, generatorJson);
410
+ const statusLines = [`Provenance mark chain created at: ${dirPath}`, `Mark ${mark.seq()} written to: ${markPath}`];
411
+ switch (this.args.format) {
412
+ case OutputFormat.Markdown: {
413
+ const paragraphs = [];
414
+ if (!this.args.quiet) paragraphs.push(...statusLines);
415
+ paragraphs.push(markInfo.markdownSummary());
416
+ return paragraphs.join("\n\n");
417
+ }
418
+ case OutputFormat.Ur:
419
+ if (!this.args.quiet) for (const line of statusLines) console.error(line);
420
+ return markInfo.ur().toString();
421
+ case OutputFormat.Json:
422
+ if (!this.args.quiet) for (const line of statusLines) console.error(line);
423
+ return JSON.stringify(markInfo.toJSON(), null, 2);
424
+ }
425
+ }
426
+ createDir() {
427
+ const dirPath = readNewPath(this.args.path);
428
+ if (fs.existsSync(dirPath)) throw new Error(`Path already exists: ${dirPath}`);
429
+ const parent = path.dirname(dirPath);
430
+ if (!fs.existsSync(parent)) throw new Error(`Parent directory does not exist: ${parent}`);
431
+ fs.mkdirSync(dirPath);
432
+ return dirPath;
433
+ }
434
+ };
435
+
436
+ //#endregion
437
+ //#region src/cmd/next.ts
438
+ /**
439
+ * Next command - 1:1 port of next.rs
440
+ *
441
+ * Generate the next provenance mark in a chain.
442
+ */
443
+ /**
444
+ * Create default args for the next command.
445
+ */
446
+ function defaultNextCommandArgs() {
447
+ return {
448
+ path: "",
449
+ comment: "Blank.",
450
+ quiet: false,
451
+ format: OutputFormat.Markdown,
452
+ info: {}
453
+ };
454
+ }
455
+ /**
456
+ * Next command implementation.
457
+ *
458
+ * Corresponds to Rust `impl Exec for CommandArgs`
459
+ */
460
+ var NextCommand = class {
461
+ args;
462
+ constructor(args) {
463
+ this.args = args;
464
+ }
465
+ exec() {
466
+ const dirPath = readExistingDirectoryPath(this.args.path);
467
+ const generatorPath = path.join(dirPath, "generator.json");
468
+ const generatorJson = fs.readFileSync(generatorPath, "utf-8");
469
+ const generator = _bcts_provenance_mark.ProvenanceMarkGenerator.fromJSON(JSON.parse(generatorJson));
470
+ const date = this.args.date ?? /* @__PURE__ */ new Date();
471
+ const info = parseInfoArgs(this.args.info);
472
+ const mark = generator.next(date, info);
473
+ const markInfo = _bcts_provenance_mark.ProvenanceMarkInfo.new(mark, this.args.comment);
474
+ const marksPath = path.join(dirPath, "marks");
475
+ const markJson = JSON.stringify(markInfo.toJSON(), null, 2);
476
+ const markPath = path.join(marksPath, `mark-${mark.seq()}.json`);
477
+ fs.writeFileSync(markPath, markJson);
478
+ const newGeneratorJson = JSON.stringify(generator.toJSON(), null, 2);
479
+ fs.writeFileSync(generatorPath, newGeneratorJson);
480
+ const statusLine = `Mark ${mark.seq()} written to: ${markPath}`;
481
+ switch (this.args.format) {
482
+ case OutputFormat.Markdown: {
483
+ const paragraphs = [];
484
+ if (!this.args.quiet) paragraphs.push(statusLine);
485
+ paragraphs.push(markInfo.markdownSummary());
486
+ return paragraphs.join("\n\n");
487
+ }
488
+ case OutputFormat.Ur:
489
+ if (!this.args.quiet) console.error(statusLine);
490
+ return markInfo.ur().toString();
491
+ case OutputFormat.Json:
492
+ if (!this.args.quiet) console.error(statusLine);
493
+ return JSON.stringify(markInfo.toJSON(), null, 2);
494
+ }
495
+ }
496
+ };
497
+
498
+ //#endregion
499
+ //#region src/cmd/print.ts
500
+ /**
501
+ * Print command - 1:1 port of print.rs
502
+ *
503
+ * Prints provenance marks in a chain.
504
+ */
505
+ /**
506
+ * Create default args for the print command.
507
+ */
508
+ function defaultPrintCommandArgs() {
509
+ return {
510
+ path: "",
511
+ start: 0,
512
+ format: OutputFormat.Markdown
513
+ };
514
+ }
515
+ /**
516
+ * Print command implementation.
517
+ *
518
+ * Corresponds to Rust `impl Exec for CommandArgs`
519
+ */
520
+ var PrintCommand = class {
521
+ args;
522
+ constructor(args) {
523
+ this.args = args;
524
+ }
525
+ exec() {
526
+ const dirPath = readExistingDirectoryPath(this.args.path);
527
+ const generatorPath = path.join(dirPath, "generator.json");
528
+ const generatorJson = fs.readFileSync(generatorPath, "utf-8");
529
+ const lastValidSeq = _bcts_provenance_mark.ProvenanceMarkGenerator.fromJSON(JSON.parse(generatorJson)).nextSeq() - 1;
530
+ const startSeq = this.args.start;
531
+ const endSeq = this.args.end ?? lastValidSeq;
532
+ if (startSeq > endSeq) throw new Error("The start sequence number must be less than or equal to the end sequence number.");
533
+ if (endSeq > lastValidSeq) throw new Error("The end sequence number must be less than or equal to the last valid sequence number.");
534
+ const markInfos = [];
535
+ for (let seq = startSeq; seq <= endSeq; seq++) {
536
+ const markPath = path.join(dirPath, "marks", `mark-${seq}.json`);
537
+ const markJson = fs.readFileSync(markPath, "utf-8");
538
+ const markInfo = _bcts_provenance_mark.ProvenanceMarkInfo.fromJSON(JSON.parse(markJson));
539
+ markInfos.push(markInfo);
540
+ }
541
+ switch (this.args.format) {
542
+ case OutputFormat.Markdown: return markInfos.map((info) => info.markdownSummary()).join("\n");
543
+ case OutputFormat.Ur: return markInfos.map((info) => info.ur().toString()).join("\n");
544
+ case OutputFormat.Json: {
545
+ const jsonArray = markInfos.map((info) => info.toJSON());
546
+ return JSON.stringify(jsonArray, null, 2);
547
+ }
548
+ }
549
+ }
550
+ };
551
+
552
+ //#endregion
553
+ //#region src/cmd/validate.ts
554
+ /**
555
+ * Validate command - 1:1 port of validate.rs
556
+ *
557
+ * Validate one or more provenance marks.
558
+ */
559
+ /**
560
+ * Output format for the validation report.
561
+ *
562
+ * Corresponds to Rust `Format`
563
+ */
564
+ let ValidateFormat = /* @__PURE__ */ function(ValidateFormat$1) {
565
+ ValidateFormat$1["Text"] = "text";
566
+ ValidateFormat$1["JsonCompact"] = "json-compact";
567
+ ValidateFormat$1["JsonPretty"] = "json-pretty";
568
+ return ValidateFormat$1;
569
+ }({});
570
+ /**
571
+ * Convert ValidateFormat to ValidationReportFormat.
572
+ */
573
+ function formatToValidationReportFormat(format) {
574
+ switch (format) {
575
+ case ValidateFormat.Text: return _bcts_provenance_mark.ValidationReportFormat.Text;
576
+ case ValidateFormat.JsonCompact: return _bcts_provenance_mark.ValidationReportFormat.JsonCompact;
577
+ case ValidateFormat.JsonPretty: return _bcts_provenance_mark.ValidationReportFormat.JsonPretty;
578
+ }
579
+ }
580
+ /**
581
+ * Parse a format string.
582
+ */
583
+ function parseValidateFormat(value) {
584
+ switch (value.toLowerCase()) {
585
+ case "text": return ValidateFormat.Text;
586
+ case "json-compact": return ValidateFormat.JsonCompact;
587
+ case "json-pretty": return ValidateFormat.JsonPretty;
588
+ default: throw new Error(`Invalid format: ${value}. Must be one of: text, json-compact, json-pretty`);
589
+ }
590
+ }
591
+ /**
592
+ * Create default args for the validate command.
593
+ */
594
+ function defaultValidateCommandArgs() {
595
+ return {
596
+ marks: [],
597
+ warn: false,
598
+ format: ValidateFormat.Text
599
+ };
600
+ }
601
+ /**
602
+ * Validate command implementation.
603
+ *
604
+ * Corresponds to Rust `impl Exec for CommandArgs`
605
+ */
606
+ var ValidateCommand = class {
607
+ args;
608
+ constructor(args) {
609
+ this.args = args;
610
+ }
611
+ exec() {
612
+ let marks;
613
+ if (this.args.dir !== void 0) marks = this.loadMarksFromDir(this.args.dir);
614
+ else marks = this.parseMarksFromUrs(this.args.marks);
615
+ const report = (0, _bcts_provenance_mark.validate)(marks);
616
+ const output = (0, _bcts_provenance_mark.formatReport)(report, formatToValidationReportFormat(this.args.format));
617
+ if ((0, _bcts_provenance_mark.hasIssues)(report) && !this.args.warn) throw new Error(`Validation failed with issues:\n${output}`);
618
+ return output;
619
+ }
620
+ /**
621
+ * Parse marks from UR strings.
622
+ *
623
+ * Corresponds to Rust `parse_marks_from_urs()`
624
+ */
625
+ parseMarksFromUrs(urStrings) {
626
+ const marks = [];
627
+ for (const urString of urStrings) {
628
+ const mark = this.extractProvenanceMark(urString.trim());
629
+ marks.push(mark);
630
+ }
631
+ return marks;
632
+ }
633
+ /**
634
+ * Extract a ProvenanceMark from a UR string.
635
+ *
636
+ * Supports three types of URs:
637
+ * 1. `ur:provenance` - Direct provenance mark
638
+ * 2. `ur:envelope` - Envelope with a 'provenance' assertion
639
+ * 3. Any other UR type - Attempts to decode CBOR as an envelope
640
+ *
641
+ * Corresponds to Rust `extract_provenance_mark()`
642
+ */
643
+ extractProvenanceMark(urString) {
644
+ let ur;
645
+ try {
646
+ ur = _bcts_uniform_resources.UR.fromURString(urString);
647
+ } catch (e) {
648
+ const message = e instanceof Error ? e.message : String(e);
649
+ throw new Error(`Failed to parse UR '${urString}': ${message}`);
650
+ }
651
+ const urType = ur.urTypeStr();
652
+ const cborValue = ur.cbor();
653
+ if (urType === "provenance") try {
654
+ return _bcts_provenance_mark.ProvenanceMark.fromUntaggedCbor(cborValue);
655
+ } catch (e) {
656
+ const message = e instanceof Error ? e.message : String(e);
657
+ throw new Error(`Failed to decode provenance mark from '${urString}': ${message}`);
658
+ }
659
+ let envelope;
660
+ try {
661
+ envelope = _bcts_envelope.Envelope.fromUntaggedCbor(cborValue);
662
+ } catch (e) {
663
+ const message = e instanceof Error ? e.message : String(e);
664
+ throw new Error(`UR type '${urType}' is not 'provenance', and CBOR is not decodable as an envelope: ${message}`);
665
+ }
666
+ return this.extractProvenanceMarkFromEnvelope(envelope, urString);
667
+ }
668
+ /**
669
+ * Extract a ProvenanceMark from an Envelope.
670
+ *
671
+ * The envelope must contain exactly one 'provenance' assertion,
672
+ * and the object subject of that assertion must be a ProvenanceMark.
673
+ *
674
+ * Corresponds to Rust `extract_provenance_mark_from_envelope()`
675
+ */
676
+ extractProvenanceMarkFromEnvelope(envelope, urString) {
677
+ let workingEnvelope = envelope;
678
+ if (envelope.isWrapped()) {
679
+ const innerEnvelope = envelope.unwrap();
680
+ if (innerEnvelope !== void 0) workingEnvelope = innerEnvelope;
681
+ }
682
+ const provenancePredicate = _bcts_envelope.Envelope.newWithKnownValue(_bcts_known_values.PROVENANCE);
683
+ const provenanceAssertions = workingEnvelope.assertionsWithPredicate(provenancePredicate);
684
+ if (provenanceAssertions.length === 0) throw new Error(`Envelope in '${urString}' does not contain a 'provenance' assertion`);
685
+ if (provenanceAssertions.length > 1) throw new Error(`Envelope in '${urString}' contains ${provenanceAssertions.length} 'provenance' assertions, expected exactly one`);
686
+ const objectEnvelope = provenanceAssertions[0].asObject();
687
+ if (objectEnvelope === void 0) throw new Error(`Failed to extract object from provenance assertion in '${urString}'`);
688
+ try {
689
+ const cborValue = objectEnvelope.asLeaf();
690
+ if (cborValue === void 0) throw new Error("Object envelope is not a leaf");
691
+ return _bcts_provenance_mark.ProvenanceMark.fromTaggedCbor(cborValue);
692
+ } catch (e) {
693
+ const message = e instanceof Error ? e.message : String(e);
694
+ throw new Error(`Failed to decode ProvenanceMark from provenance assertion in '${urString}': ${message}`);
695
+ }
696
+ }
697
+ /**
698
+ * Load marks from a directory.
699
+ *
700
+ * Corresponds to Rust `load_marks_from_dir()`
701
+ */
702
+ loadMarksFromDir(dirPath) {
703
+ const resolvedPath = readExistingDirectoryPath(dirPath);
704
+ const marksPath = path.join(resolvedPath, "marks");
705
+ if (!fs.existsSync(marksPath) || !fs.statSync(marksPath).isDirectory()) throw new Error(`Marks subdirectory not found: ${marksPath}`);
706
+ const markFiles = fs.readdirSync(marksPath).map((entry) => path.join(marksPath, entry)).filter((p) => p.endsWith(".json")).sort();
707
+ if (markFiles.length === 0) throw new Error(`No mark JSON files found in: ${marksPath}`);
708
+ const marks = [];
709
+ for (const markFile of markFiles) try {
710
+ const jsonContent = fs.readFileSync(markFile, "utf-8");
711
+ const markInfo = _bcts_provenance_mark.ProvenanceMarkInfo.fromJSON(JSON.parse(jsonContent));
712
+ marks.push(markInfo.mark());
713
+ } catch (e) {
714
+ const message = e instanceof Error ? e.message : String(e);
715
+ throw new Error(`Failed to parse JSON from ${markFile}: ${message}`);
716
+ }
717
+ return marks;
718
+ }
719
+ };
720
+
721
+ //#endregion
722
+ //#region src/index.ts
723
+ /**
724
+ * @bcts/provenance-mark-cli - Command line tool for creating and managing Provenance Marks
725
+ *
726
+ * This is a 1:1 TypeScript port of provenance-mark-cli-rust.
727
+ *
728
+ * @packageDocumentation
729
+ */
730
+ const VERSION = "1.0.0-alpha.13";
731
+
732
+ //#endregion
733
+ Object.defineProperty(exports, 'NewCommand', {
734
+ enumerable: true,
735
+ get: function () {
736
+ return NewCommand;
737
+ }
738
+ });
739
+ Object.defineProperty(exports, 'NextCommand', {
740
+ enumerable: true,
741
+ get: function () {
742
+ return NextCommand;
743
+ }
744
+ });
745
+ Object.defineProperty(exports, 'OutputFormat', {
746
+ enumerable: true,
747
+ get: function () {
748
+ return OutputFormat;
749
+ }
750
+ });
751
+ Object.defineProperty(exports, 'PrintCommand', {
752
+ enumerable: true,
753
+ get: function () {
754
+ return PrintCommand;
755
+ }
756
+ });
757
+ Object.defineProperty(exports, 'Resolution', {
758
+ enumerable: true,
759
+ get: function () {
760
+ return Resolution;
761
+ }
762
+ });
763
+ Object.defineProperty(exports, 'VERSION', {
764
+ enumerable: true,
765
+ get: function () {
766
+ return VERSION;
767
+ }
768
+ });
769
+ Object.defineProperty(exports, 'ValidateCommand', {
770
+ enumerable: true,
771
+ get: function () {
772
+ return ValidateCommand;
773
+ }
774
+ });
775
+ Object.defineProperty(exports, 'ValidateFormat', {
776
+ enumerable: true,
777
+ get: function () {
778
+ return ValidateFormat;
779
+ }
780
+ });
781
+ Object.defineProperty(exports, '__toESM', {
782
+ enumerable: true,
783
+ get: function () {
784
+ return __toESM;
785
+ }
786
+ });
787
+ Object.defineProperty(exports, 'bytesToHex', {
788
+ enumerable: true,
789
+ get: function () {
790
+ return bytesToHex;
791
+ }
792
+ });
793
+ Object.defineProperty(exports, 'defaultNewCommandArgs', {
794
+ enumerable: true,
795
+ get: function () {
796
+ return defaultNewCommandArgs;
797
+ }
798
+ });
799
+ Object.defineProperty(exports, 'defaultNextCommandArgs', {
800
+ enumerable: true,
801
+ get: function () {
802
+ return defaultNextCommandArgs;
803
+ }
804
+ });
805
+ Object.defineProperty(exports, 'defaultPrintCommandArgs', {
806
+ enumerable: true,
807
+ get: function () {
808
+ return defaultPrintCommandArgs;
809
+ }
810
+ });
811
+ Object.defineProperty(exports, 'defaultValidateCommandArgs', {
812
+ enumerable: true,
813
+ get: function () {
814
+ return defaultValidateCommandArgs;
815
+ }
816
+ });
817
+ Object.defineProperty(exports, 'fromBase64', {
818
+ enumerable: true,
819
+ get: function () {
820
+ return fromBase64;
821
+ }
822
+ });
823
+ Object.defineProperty(exports, 'hexToBytes', {
824
+ enumerable: true,
825
+ get: function () {
826
+ return hexToBytes;
827
+ }
828
+ });
829
+ Object.defineProperty(exports, 'parseInfoArgs', {
830
+ enumerable: true,
831
+ get: function () {
832
+ return parseInfoArgs;
833
+ }
834
+ });
835
+ Object.defineProperty(exports, 'parseOutputFormat', {
836
+ enumerable: true,
837
+ get: function () {
838
+ return parseOutputFormat;
839
+ }
840
+ });
841
+ Object.defineProperty(exports, 'parseResolution', {
842
+ enumerable: true,
843
+ get: function () {
844
+ return parseResolution;
845
+ }
846
+ });
847
+ Object.defineProperty(exports, 'parseSeed', {
848
+ enumerable: true,
849
+ get: function () {
850
+ return parseSeed;
851
+ }
852
+ });
853
+ Object.defineProperty(exports, 'parseValidateFormat', {
854
+ enumerable: true,
855
+ get: function () {
856
+ return parseValidateFormat;
857
+ }
858
+ });
859
+ Object.defineProperty(exports, 'readArgument', {
860
+ enumerable: true,
861
+ get: function () {
862
+ return readArgument;
863
+ }
864
+ });
865
+ Object.defineProperty(exports, 'readExistingDirectoryPath', {
866
+ enumerable: true,
867
+ get: function () {
868
+ return readExistingDirectoryPath;
869
+ }
870
+ });
871
+ Object.defineProperty(exports, 'readNewPath', {
872
+ enumerable: true,
873
+ get: function () {
874
+ return readNewPath;
875
+ }
876
+ });
877
+ Object.defineProperty(exports, 'readStdinSync', {
878
+ enumerable: true,
879
+ get: function () {
880
+ return readStdinSync;
881
+ }
882
+ });
883
+ Object.defineProperty(exports, 'toBase64', {
884
+ enumerable: true,
885
+ get: function () {
886
+ return toBase64;
887
+ }
888
+ });
889
+ //# sourceMappingURL=src-XNNUeTzh.cjs.map