@sanning/proof 0.12.0 → 0.14.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.
Files changed (59) hide show
  1. package/README.md +25 -12
  2. package/dist/agent-proof.d.ts +2 -2
  3. package/dist/agent-proof.js +4 -4
  4. package/dist/case-file.d.ts +126 -0
  5. package/dist/case-file.js +353 -0
  6. package/dist/case.d.ts +217 -26
  7. package/dist/case.js +535 -124
  8. package/dist/cli.d.ts +64 -8
  9. package/dist/cli.js +799 -219
  10. package/dist/compose.js +6 -1
  11. package/dist/crypto.d.ts +1 -1
  12. package/dist/crypto.js +5 -1
  13. package/dist/declaration.d.ts +58 -52
  14. package/dist/declaration.js +256 -33
  15. package/dist/evidence.d.ts +38 -0
  16. package/dist/evidence.js +238 -22
  17. package/dist/exit-codes.d.ts +17 -0
  18. package/dist/exit-codes.js +50 -0
  19. package/dist/file-match.d.ts +105 -0
  20. package/dist/file-match.js +374 -0
  21. package/dist/grading.d.ts +28 -13
  22. package/dist/grading.js +90 -31
  23. package/dist/index.d.ts +14 -7
  24. package/dist/index.js +20 -6
  25. package/dist/message-parts.d.ts +18 -10
  26. package/dist/message-parts.js +25 -15
  27. package/dist/types.d.ts +1 -0
  28. package/dist/verifier.d.ts +63 -4
  29. package/dist/verifier.js +223 -15
  30. package/dist/witness-cache.d.ts +85 -0
  31. package/dist/witness-cache.js +264 -0
  32. package/dist/zip-reader.d.ts +50 -0
  33. package/dist/zip-reader.js +220 -0
  34. package/package.json +2 -2
  35. package/src/agent-proof.ts +4 -4
  36. package/src/case-file.ts +422 -0
  37. package/src/case.ts +671 -131
  38. package/src/cli.ts +932 -217
  39. package/src/compose.ts +8 -1
  40. package/src/crypto.ts +5 -1
  41. package/src/declaration.ts +248 -52
  42. package/src/evidence.ts +257 -23
  43. package/src/exit-codes.ts +54 -0
  44. package/src/file-match.ts +461 -0
  45. package/src/grading.ts +109 -52
  46. package/src/index.ts +101 -2
  47. package/src/message-parts.ts +25 -15
  48. package/src/types.ts +5 -0
  49. package/src/verifier.ts +225 -16
  50. package/src/witness-cache.ts +306 -0
  51. package/src/zip-reader.ts +229 -0
  52. package/vectors/README.md +66 -8
  53. package/vectors/case-file-index.json +668 -0
  54. package/vectors/case-split.json +218 -9
  55. package/vectors/file-match.json +1808 -0
  56. package/vectors/jcs-reader.json +82 -3
  57. package/vectors/pack-grading.json +68 -4
  58. package/vectors/stamp-on-chain.json +20 -5
  59. package/vectors/witness-cache.json +1304 -0
package/dist/cli.d.ts CHANGED
@@ -1,10 +1,16 @@
1
1
  #!/usr/bin/env node
2
+ import { type WitnessLine } from "./case.js";
3
+ import { type CachedWitnessTime, type WitnessTimeAnswer, type WitnessTimeCheck } from "./witness-cache.js";
2
4
  interface Cli {
3
5
  out: (s: string) => void;
4
6
  err: (s: string) => void;
5
7
  fetchImpl?: typeof fetch;
6
8
  }
7
- export declare function runCli(argv: string[], io: Cli): Promise<number>;
9
+ /** Each control character in `text` as a visible escape: `\x1b` for ESC,
10
+ * `\u202e` for RIGHT-TO-LEFT OVERRIDE. Every other character is unchanged, a
11
+ * backslash included, so a line with none is printed as it was. */
12
+ export declare function escapeControl(text: string): string;
13
+ export declare function runCli(argv: string[], stream: Cli): Promise<number>;
8
14
  /** The error text for an input with no pack in it, word for word the page's. */
9
15
  export declare const NO_BUNDLE = "No bundle.json found. An evidence pack contains bundle.json plus logs/.";
10
16
  /** A directory nested deeper than this below an argument refuses the input. */
@@ -28,18 +34,23 @@ export declare class CaseInputError extends Error {
28
34
  /**
29
35
  * `bundle.json` bytes that `readBundleBytes` will not read. `tooDeep` separates
30
36
  * the one refusal that is not a parse error; `detail` is the parser's own words,
31
- * which differ by kernel and are printed by `verify` only.
37
+ * which differ by kernel and are printed by `verify` only. `duplicate` marks the
38
+ * one parse refusal whose `detail` is kernel wording, identical in both kernels
39
+ * (`duplicate key "<name>"`, proof#144), so both commands print it.
32
40
  */
33
41
  export declare class BundleReadError extends Error {
34
42
  readonly tooDeep: boolean;
35
43
  readonly detail: string;
36
- constructor(tooDeep: boolean, detail: string);
44
+ readonly duplicate: boolean;
45
+ constructor(tooDeep: boolean, detail: string, duplicate?: boolean);
37
46
  }
47
+ export declare const NOT_I_JSON = "is not I-JSON (RFC 7493)";
38
48
  /**
39
49
  * How both `verify` and `case` turn `bundle.json` bytes into JSON, in both
40
50
  * kernels (`read_bundle_bytes` in the Python twin). UTF-8 with each ill-formed
41
51
  * sequence read as U+FFFD, and a byte-order mark kept; then nesting deeper than
42
- * MAX_JSON_DEPTH is refused before any parser walks into it; then `JSON.parse`.
52
+ * MAX_JSON_DEPTH is refused before any parser walks into it; then `JSON.parse`,
53
+ * refusing an object that repeats a member name (I-JSON, RFC 7493; proof#144).
43
54
  * Throws `BundleReadError`.
44
55
  */
45
56
  export declare function readBundleBytes(bytes: Uint8Array): unknown;
@@ -64,9 +75,15 @@ export interface SplitCase {
64
75
  }
65
76
  /** One name the walk found that is not a directory. */
66
77
  export interface TreeEntry {
78
+ /** Where it sits on disk. Empty for an entry read out of a case-file `.zip`. */
67
79
  fsPath: string;
68
- /** `true` for a regular file; `false` for a link or anything else. */
80
+ /**
81
+ * `true` for a regular file; `false` for a link or anything else, including a
82
+ * `.zip` entry the reader refused.
83
+ */
69
84
  regular: boolean;
85
+ /** The bytes of an entry read out of a case-file `.zip`. */
86
+ data?: Uint8Array | null;
70
87
  }
71
88
  /**
72
89
  * The page's `splitCase` followed by its `assemble` per pack, over the walk's
@@ -88,8 +105,47 @@ export declare function readFileEntry(entry: TreeEntry, key: string): Promise<Ui
88
105
  * with the way through.
89
106
  */
90
107
  export declare function treeFromArguments(paths: readonly string[]): Promise<Map<string, TreeEntry>>;
91
- export declare const CASE_EXIT_CODES: Readonly<Record<string, number>>;
92
- export declare const CASE_USAGE = "sanning-proof case -- one verdict over several evidence packs, offline\n\n sanning-proof case <folder>... [--gateways <url,url>] [--json]\n\n <folder> a pack folder (bundle.json plus logs/), or a folder that holds\n several packs, such as an unpacked decision file. case reads\n folders only: given a .zip, it exits 2 and says to unzip it\n first (for example, unzip file.zip -d case/) and pass the folder.\n Packs are found by the verify page's splitting rule: every\n bundle.json is a pack, a file belongs to the deepest pack whose\n bundle.json or logs/ it sits in, and every other file is listed\n as outside every pack and never opened. A .zip inside a folder is\n a file like any other. A symbolic link is never followed: it is\n listed as outside and not read, even under a pack's logs/.\n Several folders are read as one folder holding them, each under\n its own name. A folder nested more than 32 levels deep, more than\n 50000 files and folders in all, or a name that is not valid UTF-8\n exits 2.\n --gateways comma-separated gateway URLs. Each pack's witnesses are then\n re-fetched on chain, pack by pack, and reported beside the case\n reading. Without it the on-chain half is NOT checked, and the\n output says so.\n --json the full reading as JSON: the verdict, every exception with its\n rendered line, every record, every contribution, the packs, the\n files outside them, and the on-chain half.\n\nEach pack's bundle.json is read as verify reads it, so the two commands\nclassify one bundle the same way.\n\nWhat a case reading establishes: every pack is verified offline by this\nkernel; every record every pack supplied is read, in one pile, under the\nhand-off rules of envelope-spec section 4.1; a hand-off record with no\ncounterpart among the case's records is always named, and when a pack signed by\nthe key it names is in the case, the reading says that pack holds none, unless\nevery candidate it had was accounted for by another record (A20), which reads\nas no counterpart and names no pack.\n\nWhat it does not establish: that the case is complete (a party can decline to\nhand over a pack); that a party which presented no pack under the named key\nrecorded nothing; that two organizations are independent of each other; or\nthat any witness was re-fetched on chain, which the reading never does.\n\nExit codes: 0 verified \u00B7 1 failed \u00B7 2 malformed, usage, an input that cannot\nbe read as a case, or an unexpected error in this command \u00B7 3 incomplete or\npartial (undetermined, not failed) \u00B7 4 mixed (more than one outcome: read the\nexceptions). With --gateways, a witness that does not match on chain exits 1,\nand an on-chain half that could not be settled turns 0 into 3.";
108
+ export declare const CASE_USAGE: string;
109
+ interface OnChainRow {
110
+ ref: string;
111
+ witnesses: number;
112
+ confirmed: number;
113
+ mismatched: number;
114
+ unreachable: number;
115
+ not_checked: number;
116
+ /** Present only where the pack caches a witness time (5.6.6, v1.25, A30). */
117
+ witness_times?: WitnessTimeRow[];
118
+ }
119
+ interface WitnessTimeRow {
120
+ stamp_ref: string;
121
+ cached: {
122
+ block_height: number;
123
+ block_time: number;
124
+ };
125
+ outcome: WitnessTimeCheck["outcome"];
126
+ answers: {
127
+ gateway: string;
128
+ outcome: WitnessTimeAnswer["outcome"];
129
+ block_height: number | null;
130
+ block_time: number | null;
131
+ }[];
132
+ }
133
+ interface OnChainHalf {
134
+ /** Present only where a lookup ran: each gateway that answered, in the order given. */
135
+ answered?: string[];
136
+ checked: boolean;
137
+ gateways: string[];
138
+ packs: OnChainRow[];
139
+ verdict: "not_checked" | "confirmed" | "failed" | "undetermined";
140
+ }
141
+ /**
142
+ * `cached` is every witness time the packs cache (5.6.6, v1.25, A30). Where no
143
+ * lookup ran, each is printed labelled not checked. Where one ran, each time
144
+ * the public record matched is printed as the record's, each time no lookup
145
+ * settled stays labelled not checked, and a time the record contradicts is the
146
+ * reason the line reads `differs`.
147
+ */
148
+ export declare function witnessLine(onChain: OnChainHalf, cached?: readonly CachedWitnessTime[]): WitnessLine;
93
149
  /**
94
150
  * The case verdict's code, moved only by an on-chain half that was asked for:
95
151
  * a witness that does not match is a failure whatever the reading said, and an
@@ -102,5 +158,5 @@ export declare function caseExitCode(verdict: string, onChainVerdict: string): n
102
158
  * never 1, because 1 would name the evidence failed over a defect in this
103
159
  * command.
104
160
  */
105
- export declare function runCase(argv: readonly string[], io: Cli): Promise<number>;
161
+ export declare function runCase(argv: readonly string[], stream: Cli): Promise<number>;
106
162
  export {};