@sanning/proof 0.19.1 → 0.20.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 (98) hide show
  1. package/README.md +30 -29
  2. package/dist/agent-record.d.ts +62 -0
  3. package/dist/agent-record.js +527 -0
  4. package/dist/agent-schemas.generated.d.ts +15 -0
  5. package/dist/agent-schemas.generated.js +5759 -0
  6. package/dist/case-file.d.ts +32 -89
  7. package/dist/case-file.js +41 -93
  8. package/dist/case.d.ts +339 -822
  9. package/dist/case.js +667 -1160
  10. package/dist/chain.d.ts +19 -47
  11. package/dist/chain.js +78 -205
  12. package/dist/claims.d.ts +211 -0
  13. package/dist/claims.js +1081 -0
  14. package/dist/cli.d.ts +45 -68
  15. package/dist/cli.js +618 -1022
  16. package/dist/compose.js +23 -65
  17. package/dist/crypto.d.ts +7 -8
  18. package/dist/crypto.js +60 -147
  19. package/dist/declaration.d.ts +68 -194
  20. package/dist/declaration.js +175 -518
  21. package/dist/environment.d.ts +9 -30
  22. package/dist/environment.js +17 -66
  23. package/dist/evidence.d.ts +119 -160
  24. package/dist/evidence.js +744 -1103
  25. package/dist/exit-codes.d.ts +11 -27
  26. package/dist/exit-codes.js +24 -59
  27. package/dist/file-match.d.ts +33 -79
  28. package/dist/file-match.js +33 -69
  29. package/dist/grading.d.ts +98 -135
  30. package/dist/grading.js +224 -380
  31. package/dist/handoff.d.ts +62 -160
  32. package/dist/handoff.js +153 -393
  33. package/dist/index.d.ts +14 -10
  34. package/dist/index.js +60 -167
  35. package/dist/json-schema.d.ts +29 -0
  36. package/dist/json-schema.js +298 -0
  37. package/dist/merkle.js +16 -28
  38. package/dist/message-parts.d.ts +56 -212
  39. package/dist/message-parts.js +142 -502
  40. package/dist/side-content.d.ts +11 -22
  41. package/dist/side-content.js +22 -65
  42. package/dist/types.d.ts +17 -0
  43. package/dist/types.js +19 -5
  44. package/dist/verifier.d.ts +40 -114
  45. package/dist/verifier.js +196 -535
  46. package/dist/witness-cache.d.ts +24 -45
  47. package/dist/witness-cache.js +38 -81
  48. package/dist/witness-lookup.d.ts +36 -57
  49. package/dist/witness-lookup.js +89 -139
  50. package/dist/zip-reader.d.ts +18 -33
  51. package/dist/zip-reader.js +19 -34
  52. package/package.json +11 -3
  53. package/src/agent-record.ts +608 -0
  54. package/src/agent-schemas.generated.ts +5764 -0
  55. package/src/case-file.ts +45 -109
  56. package/src/case.ts +814 -1328
  57. package/src/chain.ts +85 -224
  58. package/src/claims.ts +1253 -0
  59. package/src/cli.ts +714 -1176
  60. package/src/compose.ts +33 -79
  61. package/src/crypto.ts +60 -147
  62. package/src/declaration.ts +219 -656
  63. package/src/environment.ts +17 -65
  64. package/src/evidence.ts +958 -1381
  65. package/src/exit-codes.ts +24 -63
  66. package/src/file-match.ts +40 -89
  67. package/src/grading.ts +287 -421
  68. package/src/handoff.ts +175 -427
  69. package/src/index.ts +131 -177
  70. package/src/json-schema.ts +295 -0
  71. package/src/merkle.ts +16 -28
  72. package/src/message-parts.ts +155 -533
  73. package/src/side-content.ts +25 -68
  74. package/src/types.ts +55 -36
  75. package/src/verifier.ts +202 -526
  76. package/src/witness-cache.ts +45 -94
  77. package/src/witness-lookup.ts +107 -177
  78. package/src/zip-reader.ts +20 -38
  79. package/vectors/README.md +52 -34
  80. package/vectors/agent-record.json +2175 -0
  81. package/vectors/case-file-index.json +1 -1
  82. package/vectors/case-split.json +2 -2
  83. package/vectors/chain-reading.json +3 -3
  84. package/vectors/file-match.json +285 -148
  85. package/vectors/jcs-reader.json +6 -6
  86. package/vectors/pack-grading.json +102 -25
  87. package/vectors/sandbox-evidence.json +573 -581
  88. package/vectors/stamp-on-chain.json +18 -18
  89. package/vectors/witness-cache.json +49 -49
  90. package/dist/agent-proof.d.ts +0 -28
  91. package/dist/agent-proof.js +0 -226
  92. package/dist/run-adapters.d.ts +0 -10
  93. package/dist/run-adapters.js +0 -35
  94. package/dist/run.d.ts +0 -209
  95. package/dist/run.js +0 -1405
  96. package/src/agent-proof.ts +0 -264
  97. package/src/run-adapters.ts +0 -44
  98. package/src/run.ts +0 -1598
package/dist/index.d.ts CHANGED
@@ -1,19 +1,22 @@
1
- export { ACCEPTED_SPEC_MAJORS, contentHashes, jcs, specVersionSupported, verifyEnvelope, } from "./verifier.js";
1
+ export { ACCEPTED_SPEC_MAJORS, contentHashes, jcs, specVersionSupported, verifyEnvelope, envelopeFault, envelopeFaults, } from "./verifier.js";
2
+ export { ENVELOPE_FAULTS } from "./types.js";
3
+ export type { EnvelopeFault } from "./types.js";
2
4
  export { jcsParse } from "./verifier.js";
3
- export { exceedsTextDepth, hasNonFiniteNumber, jcsParseWithinLimits, MAX_READ_DEPTH } from "./verifier.js";
4
5
  export { bytesToHex, deriveOperatorAddress, ed25519Refusal, ed25519Verify, hexToBytes, sha256Bytes, sha256Hex, utf8, verifyRsaPssSha256, } from "./crypto.js";
5
6
  export { EMPTY_TREE_ROOT_HEX, auditPath, leafHash, merkleRoot, nodeHash, verifyInclusion, } from "./merkle.js";
6
7
  export type { ContentRole, Envelope, Subject, VerificationResult, VerifyOptions } from "./types.js";
7
8
  export { ACCEPTED_EVIDENCE_MAJORS, ANCHOR_TRACE_BODY_TYPE, CO_SIGNATURES_NOTE, EXPORT_BODY_TYPE, STAMP_BODY_VERSION, STAMP_TRACE_BODY_TYPE, STAMP_EVIDENCE_BODY_TYPE, coSignaturesPresent, disclosedContent, recomputeExportVerdict, verifyEvidenceBundle, } from "./evidence.js";
8
- export type { AnchorTraceBody, AttestationPayload, AttestationRecord, AttestationResult, CheckpointResult, ComposeVerdictResult, DisclosedContentResult, DisclosedEventContent, DisclosureStatus, EvidenceBundle, EvidenceBundleResult, EvidenceIssuer, EvidenceStatus, EvidenceVerdict, EventResult, ExportBody, ExportResult, OnChainOutcome, OnChainResult, PerGatewayOutcome, AnchorRef, StampBody, StampEntry, StampResult, StampSubtree, StampSubtreeResult, StampTraceBody, StampEvidenceBody, StampEvidenceEvent, StampEvidenceInclusion, TraceCheckpoint, TraceEvent, TraceInclusion, VerdictAttestation, VerdictCheckpoint, VerdictEvent, VerdictObject, VerdictOnChain, VerdictOnChainGateway, VerifyEvidenceOptions, } from "./evidence.js";
9
+ export type { AnchorTraceBody, AttestationPayload, AttestationRecord, AttestationResult, CheckpointResult, ComposeVerdictResult, DisclosedContentResult, DisclosedEventContent, DisclosureStatus, EvidenceBundle, EvidenceBundleResult, EvidenceIssuer, EvidenceStatus, EventResult, ExportBody, ExportResult, OnChainOutcome, OnChainResult, PerGatewayOutcome, AnchorRef, StampBody, StampEntry, StampResult, StampSubtree, StampSubtreeResult, StampTraceBody, StampEvidenceBody, StampEvidenceEvent, StampEvidenceInclusion, TraceCheckpoint, TraceEvent, TraceInclusion, VerdictAttestation, VerdictCheckpoint, VerdictEvent, VerdictObject, VerdictOnChain, VerdictOnChainGateway, VerifyEvidenceOptions, } from "./evidence.js";
9
10
  export { PACK_GRADE_CAUSE_KINDS, PACK_VERDICTS, accountDisclosure, completenessNotes, gradeCauses, gradePack, renderCause, signedLeafCount, } from "./grading.js";
10
11
  export type { CompletenessNote, DisclosureAccount, GradeInput, PackGrade, PackGradeCause, PackGradeCauseKind, PackVerdict, } from "./grading.js";
11
12
  export { DECLARATION_CONTENT_KINDS, DECLARATION_DEVIATION_KINDS, DECLARATION_NOTE_KINDS, DECLARATION_ROLES, DECLARATION_VERDICTS, DECLARATION_VERSION, DECLARATION_VERSION_V2, DECLARATION_VERSION_V3, DECLARATION_VERSIONS, checkDeclaration, declarationClaims, packRecords, renderContentFinding, renderDeclarationSummary, renderDeviation, renderNote, } from "./declaration.js";
12
13
  export type { DeclarationCheck, DeclarationClaims, DeclarationContentFinding, DeclarationContentKind, DeclarationDeviation, DeclarationDeviationKind, DeclarationNote, DeclarationNoteKind, DeclarationRole, DeclarationVerdict, PackRecord, } from "./declaration.js";
13
- export { CASE_BODY_TYPES, CASE_EXCEPTION_KINDS, CASE_QUARANTINED_PROFILES, CASE_RECORD_PROFILES, CASE_RECORD_STATUSES, CASE_NOTE_KINDS, CASE_RELIANCE, CASE_RELIANCE_HANDOFF_CLAUSE, CASE_RELIANCE_SANDBOX, CASE_VERDICTS, CONTENT_WITHHELD_BY_DECLARATION, CO_SIGNATURES_PRESENT, VERDICT_DISPLAY_TITLES, WITNESS_NOT_LOOKED_UP, WITNESS_STATES, WITNESS_TIME_CACHED, WITNESS_TIME_RECORDED, caseReliance, readCase, renderCaseNote, renderCaseSummary, renderException, renderWitnessLine, } from "./case.js";
14
+ export { CASE_BODY_TYPES, CASE_EXCEPTION_KINDS, CASE_QUARANTINED_PROFILES, CASE_RECORD_PROFILES, CASE_RECORD_STATUSES, CASE_NOTE_KINDS, CASE_RELIANCE, CASE_RELIANCE_HANDOFF_CLAUSE, CASE_RELIANCE_SANDBOX, CASE_VERDICTS, CONTENT_WITHHELD_BY_DECLARATION, CO_SIGNATURES_PRESENT, VERDICT_DISPLAY_TITLES, WITNESS_NOT_LOOKED_UP, WITNESS_STATES, WITNESS_TIME_CACHED, WITNESS_TIME_RECORDED, caseProblems, caseReliance, readCase, renderCaseNote, renderCaseSummary, renderException, renderWitnessLine, } from "./case.js";
14
15
  export { MAX_BLOCK_TIME, MAX_WITNESS_CACHE_DEPTH, WITNESS_CACHE_NAME, WITNESS_CACHE_VERSION, checkWitnessCache, formatBlockTime, readWitnessCache, renderWitnessTime, witnessTimeQuery, } from "./witness-cache.js";
15
16
  export type { CachedWitnessTime, WitnessTimeAnswer, WitnessTimeCheck } from "./witness-cache.js";
16
- export { lookupPublicRecord, onChainHalf, witnessLine } from "./witness-lookup.js";
17
+ export { lookupPublicRecord, onChainHalf, onChainOutcome, onChainRow, witnessLine, } from "./witness-lookup.js";
18
+ export { CLAIMS, CLAIM_LABELS, CLAIM_QUESTIONS, CLAIM_STATES, ENVELOPE_FAULT_KINDS, KIND_CLAIMS, NOTE_FINDINGS, NOTE_ORDER, NOT_IN_SCOPE_REASONS, NOT_PROVEN_REASONS, PERSON_TITLES, PERSON_TITLE_PARTS, REASON_KINDS, RECORD_REASON_CLAIMS, RECORD_REASON_LINES, SANDBOX_PERSON_LINE, VERDICTS, VERDICT_COLOURS, VERDICT_TITLES, bundleProblems, claimsOf, downgraded, note, orderedNotes, restOnSigned, personText, problem, problemToJson, renderFindingNote, renderPerson, verdictOf, withItems, } from "./claims.js";
19
+ export type { Claim, ClaimEntry, ClaimItem, ClaimState, Labels, LinePart, NoteEntry, NotInScopeReason, NotProvenReason, Person, Problem, ProblemItem, ProblemJson, ProblemValues, ReasonKind, Verdict, VerdictJson, } from "./claims.js";
17
20
  export type { OnChainHalf, OnChainRow, PublicRecordPack, PublicRecordResult, PublicRecordState, WitnessLookupOptions, WitnessTimeRow, } from "./witness-lookup.js";
18
21
  export type { CaseException, CaseExceptionKind, CaseNote, CaseNoteKind, CasePack, CasePackReading, CaseReading, CaseRecordReading, CaseRecordStatus, CaseVerdict, WitnessLine, WitnessState, } from "./case.js";
19
22
  export { CASE_FILE_FINDING_KINDS, CASE_FILE_INDEX_NAME, CASE_FILE_VERSION, HOW_TO_VERIFY_NAME, REPORT_README_FIRST_LINE, howToVerifyText, isPackRef, readCaseFileIndex, renderCaseFileFinding, } from "./case-file.js";
@@ -22,14 +25,15 @@ export { FILE_MATCH_SCOPE, NOT_READ_REASONS, SKIPPED_REASONS, fileMatchToJson, m
22
25
  export type { FileCommitment, FileMatchPack, FileMatchReading, MatchedFile, NotRead, NotReadReason, OfferedFile, SkippedFile, SkippedReason, UnmatchedFile, } from "./file-match.js";
23
26
  export { ADAPTER_CHAIN_NAMESPACES, CHAIN_READING_SCOPE, readChainLinks, readChains, renderChainFinding, } from "./chain.js";
24
27
  export type { ChainFinding, ChainFindingKind, ChainLink, ChainReading, ChainSource, ChainSummary, } from "./chain.js";
25
- export { EXIT_CODES, EXIT_CODES_HELP, EXIT_FAILED, EXIT_MALFORMED, EXIT_MIXED, EXIT_SANDBOX, EXIT_UNDETERMINED, EXIT_VERIFIED, exitCodeFor, sandboxExit, } from "./exit-codes.js";
26
- export { SANDBOX_HEADLINE, SANDBOX_LINE, SANDBOX_TITLE, environmentMarker, onlySimulatedUnsettled, packEnvelopes, } from "./environment.js";
28
+ export { EXIT_CODES, EXIT_CODES_HELP, EXIT_COULD_NOT_RUN, EXIT_FAILED, EXIT_INCOMPLETE, EXIT_SANDBOX, EXIT_VERIFIED, exitCodeFor, } from "./exit-codes.js";
29
+ export { environmentMarker, packEnvelopes, } from "./environment.js";
27
30
  export type { EnvironmentMarker } from "./environment.js";
28
31
  export { attestationSignatureToHex, composeExport } from "./compose.js";
29
32
  export type { ComposeExportOptions, ComposeExportResult, ExporterKey } from "./compose.js";
30
- export { AGENT_PROOF_SPEC_VERSION, isAgentProofSpec, verifyAgentProof } from "./agent-proof.js";
31
- export type { AgentProofBundle, AgentProofResult, VerifyAgentProofOptions, } from "./agent-proof.js";
32
- export { CANDIDATE_NAMESPACE, DEFINED_EVENT_TYPES, NOT_A_HANDOFF_FINDING, isConformantHandoffRecord, readHandoff, readHandoffs, recordIsMalformed, } from "./handoff.js";
33
+ export { CANDIDATE_NAMESPACE, DEFINED_EVENT_TYPES, NOT_A_HANDOFF_FINDING, isConformantHandoffRecord, readHandoff, readHandoffs, recordDefect, recordIsMalformed, recordIsNonconforming, } from "./handoff.js";
33
34
  export type { CandidateReading, HandoffReading, HandoffRecord, HandoffVerdict, HeldRecord, } from "./handoff.js";
34
35
  export { BYTES_FOR_UNKNOWN_PART, CONFLICTING_PART_BYTES, INLINE_BYTES_KEYS, MESSAGE_RESULT_ORDER, PARTS_NOT_AN_ARRAY, PART_ENCODING_MISMATCH, PART_INLINE_BYTES, PART_INLINE_MISMATCHED, PART_MALFORMED_DESCRIPTOR, PART_MATCHED, PART_MISMATCHED, PART_NOT_A_FILE, PART_SUPPLIED_TWICE, PART_UNCHECKED, REFUSAL_ORDER, commitHeldMessage, isFilePart, uncheckedHeldParts, } from "./message-parts.js";
35
36
  export type { HeldMessage, Note, PartReading, Refusal, SuppliedPart } from "./message-parts.js";
37
+ export { AGENT_EVENT_TYPES, RECORD_TYPES_OUTSIDE_AGENT, readAgentRecord, readAgentRecordWithHeld, readAgentRecords, renderAgentReading, } from "./agent-record.js";
38
+ export type { AgentHeldRecord, AgentReason, AgentRecordReading, AgentVerdict } from "./agent-record.js";
39
+ export { AGENT_SCHEMA_PIN, AGENT_SCHEMA_VERSIONS } from "./agent-schemas.generated.js";
package/dist/index.js CHANGED
@@ -1,179 +1,72 @@
1
- // @sanning/proof — TypeScript kernel of the Sanning verification stack.
2
- //
3
- // The verification primitives for the Verifiable Event Envelope family
4
- // (specs/envelope-spec.md), sanning.agent/v1 profile: RFC 8785 (JCS)
5
- // canonicalization, SHA-256, Ed25519 envelope verification, and the
6
- // content-hash extraction used for reverse provenance lookup. Sibling of the
7
- // Python `sanning-proof` kernel and the Go `pkg/proof` reference; conformance
8
- // is byte-for-byte against the shared `test-vectors/` corpus.
9
- //
10
- // Scope boundary (envelope-spec §10 #13): this package verifies a SINGLE
11
- // envelope. Chain walking (previous_hash), checkpoint reconciliation, and
12
- // gateway/transport concerns are consumer-layer logic composed above it.
13
- // ACCEPTED_SPEC_MAJORS is exported for parity with the sibling kernels'
14
- // registries (Python ACCEPTED_SPEC_MAJORS, Go SupportedSpecMajor): a consumer
15
- // can see which profiles this build admits without inferring it from probe
16
- // calls. It is frozen at its definition (`Object.freeze`, typed
17
- // `readonly string[]`) because the verifier reads that same array — an exported
18
- // mutable accept-set would be a runtime-widenable kernel. Additive — no
19
- // existing export changes.
20
- export { ACCEPTED_SPEC_MAJORS, contentHashes, jcs, specVersionSupported, verifyEnvelope, } from "./verifier.js";
21
- // The strict reader of bytes that claim to be JCS, the twin of Python's public
22
- // `canonicalize.jcs_loads`. The enclave attestation adapters read a token's
23
- // JSON through it, so they refuse what the kernel refuses. Additive.
1
+ // @sanning/proof: the TypeScript verification kernel for the Verifiable Event
2
+ // Envelope family (specs/envelope-spec.md): RFC 8785 (JCS), SHA-256, Ed25519
3
+ // envelope verification, and the bundle, pack and case readings built on them.
4
+ // Conformance is byte-for-byte against the shared `test-vectors/` corpus.
5
+ // The accept-set this build admits. Frozen at its definition, because the
6
+ // verifier reads the same array.
7
+ export { ACCEPTED_SPEC_MAJORS, contentHashes, jcs, specVersionSupported, verifyEnvelope, envelopeFault, envelopeFaults, } from "./verifier.js";
8
+ export { ENVELOPE_FAULTS } from "./types.js";
9
+ // The strict reader of bytes that claim to be JCS (Python's `jcs_loads`).
24
10
  export { jcsParse } from "./verifier.js";
25
- // The same reader within the enclave readers' limits (enclave-attestation
26
- // section 2.1): depth checked on the bytes first, every number finite. The
27
- // adapters read a token's header and claims and the manifest through it.
28
- // Additive.
29
- export { exceedsTextDepth, hasNonFiniteNumber, jcsParseWithinLimits, MAX_READ_DEPTH } from "./verifier.js";
30
11
  export { bytesToHex, deriveOperatorAddress, ed25519Refusal, ed25519Verify, hexToBytes, sha256Bytes, sha256Hex, utf8, verifyRsaPssSha256, } from "./crypto.js";
31
12
  export { EMPTY_TREE_ROOT_HEX, auditPath, leafHash, merkleRoot, nodeHash, verifyInclusion, } from "./merkle.js";
32
- // Evidence-bundle verification (specs/evidence-bundle.md): the signed
33
- // sanning.evidence/v1 wrapper carrying the sanning.anchor.trace/v3 body. The CLI
34
- // (`npx @sanning/proof verify`) is built on this. The same path dispatches on the
35
- // issuer-composed sanning.evidence.export/v2 body (specs/evidence-export.md) to
36
- // verifyExportBody (embedded RSA-PSS operator attestations + a recomputed §4
37
- // verdict object with per-gateway on-chain outcomes).
38
- //
39
- // `disclosedContent` is the INGEST half of the same path (evidence-bundle
40
- // §5.1). A received bundle carries its disclosed raw bytes as lowercase hex, so
41
- // materializing them was, until now, every consumer re-implementing the
42
- // encoding convention — and a consumer that copied the field VERBATIM wrote
43
- // files that failed verification on genuine evidence. This hands back DECODED
44
- // bytes, and only for events whose verification bound them to the committed
45
- // content_hash. Additive; verifyEvidenceBundle's behavior is unchanged.
13
+ // Evidence-bundle verification (specs/evidence-bundle.md), including the
14
+ // sanning.evidence.export/v2 body (specs/evidence-export.md).
15
+ // `disclosedContent` returns decoded disclosed bytes, only for events whose
16
+ // verification bound them to the committed content_hash.
46
17
  export { ACCEPTED_EVIDENCE_MAJORS, ANCHOR_TRACE_BODY_TYPE, CO_SIGNATURES_NOTE, EXPORT_BODY_TYPE, STAMP_BODY_VERSION, STAMP_TRACE_BODY_TYPE, STAMP_EVIDENCE_BODY_TYPE, coSignaturesPresent, disclosedContent, recomputeExportVerdict, verifyEvidenceBundle, } from "./evidence.js";
47
- // Pack grading (src/grading.ts): what a verification SURFACE may claim about a
48
- // pack — the signed bundle PLUS whatever disclosed bytes travelled beside it.
49
- //
50
- // The rule is already normative in evidence-bundle.md §5.1 (absent disclosure is
51
- // undetermined, not failed) and §6 (no status ever means "safe"); what the
52
- // surfaces added on top was a sharper word for undetermined and an account of
53
- // what the pack failed to disclose. It lived twice, in two repos and two
54
- // languages, and the two derivations had already diverged once. It lives here.
55
- //
56
- // Pure — data in, data out, no I/O, so the kernel's scope boundary
57
- // (specs/architecture.md §3) is unchanged. `vectors/pack-grading.json` is the
58
- // conformance statement of the rule and ships in the published tarball, so a
59
- // consumer that cannot yet import `gradePack` can vendor the table, hold its own
60
- // derivation to it, and diff its copy against ours. Additive — no existing
61
- // export changes.
18
+ // Pack grading: what a verification surface may claim about a pack and the
19
+ // disclosed bytes beside it (evidence-bundle.md §5.1, §6). Pure.
20
+ // `vectors/pack-grading.json` states the rule for consumers to test against.
62
21
  export { PACK_GRADE_CAUSE_KINDS, PACK_VERDICTS, accountDisclosure, completenessNotes, gradeCauses, gradePack, renderCause, signedLeafCount, } from "./grading.js";
63
- // The declaration (src/declaration.ts): what a pack SAYS it holds, checked
64
- // against what it does (evidence-bundle.md §5.4).
65
- //
66
- // Every other check in this kernel checks a record that is PRESENT, so a pack
67
- // with half its records dropped verifies perfectly and an auditor cannot tell
68
- // a full hand-over from a trimmed one. The declaration is the pack's own
69
- // statement of what it was meant to contain, inside `body` and therefore under
70
- // the bundle's signature. Any deviation FAILS and every deviation is NAMED; a
71
- // pack that carries no declaration is `partial`, never `verified`; and a
72
- // reading that rests on the UNSIGNED content handed in beside the pack is
73
- // named on its own and carries the weaker word, because whoever assembles a
74
- // case chose those bytes (proof#147).
75
- //
76
- // Pure: data in, data out, no I/O. `gradePack` takes the result as an
77
- // optional fourth argument, so a surface gets one verdict; omitting it is the
78
- // pre-§5.4 behavior, unchanged. Additive: no existing export changes.
22
+ // The declaration: what a pack says it holds, checked against what it does
23
+ // (evidence-bundle.md §5.4). Pure. `gradePack` takes the result as an optional
24
+ // fourth argument.
79
25
  export { DECLARATION_CONTENT_KINDS, DECLARATION_DEVIATION_KINDS, DECLARATION_NOTE_KINDS, DECLARATION_ROLES, DECLARATION_VERDICTS, DECLARATION_VERSION, DECLARATION_VERSION_V2, DECLARATION_VERSION_V3, DECLARATION_VERSIONS, checkDeclaration, declarationClaims, packRecords, renderContentFinding, renderDeclarationSummary, renderDeviation, renderNote, } from "./declaration.js";
80
- // The case (src/case.ts): one verdict over SEVERAL packs, across organizations
81
- // (anchor#198). The layer above the declaration, and the closure for what a
82
- // declaration cannot reach.
83
- //
84
- // A pack a party assembles about itself is not self-proving about what that
85
- // party LEFT OUT (envelope-spec.md §4.1 A15, evidence-bundle.md §5.4.2 rule 7),
86
- // because the omission happens before any reader runs. Reading several parties'
87
- // packs at once is what closes it: a `handoff.sent` with no counterpart is
88
- // always named, and where a pack signed by the key it names is in the case, the
89
- // reading says that pack holds no counterpart (unless every candidate was
90
- // accounted for under A20, which reads as no counterpart and names no pack). Whether a party that presented
91
- // no such pack recorded anything is not established (proof#143). `readCase`
92
- // verifies every pack itself, offline, so it is async. Matching is on keys and hashes alone and NEVER on tenancy, so a pair from two
93
- // organizations verifies (DL-60).
94
- //
95
- // Pure: data in, data out, no I/O. Additive: a new module, no existing export
96
- // changes, and no new verdict word anywhere.
97
- export { CASE_BODY_TYPES, CASE_EXCEPTION_KINDS, CASE_QUARANTINED_PROFILES, CASE_RECORD_PROFILES, CASE_RECORD_STATUSES, CASE_NOTE_KINDS, CASE_RELIANCE, CASE_RELIANCE_HANDOFF_CLAUSE, CASE_RELIANCE_SANDBOX, CASE_VERDICTS, CONTENT_WITHHELD_BY_DECLARATION, CO_SIGNATURES_PRESENT, VERDICT_DISPLAY_TITLES, WITNESS_NOT_LOOKED_UP, WITNESS_STATES, WITNESS_TIME_CACHED, WITNESS_TIME_RECORDED, caseReliance, readCase, renderCaseNote, renderCaseSummary, renderException, renderWitnessLine, } from "./case.js";
98
- // The witnessed-time cache (evidence-bundle 5.6.6, v1.25, A30): read it, look it
99
- // up, print it. Never an input to a verdict.
26
+ // The case: one verdict over several parties' packs, closing what a single
27
+ // pack cannot prove about its own omissions (evidence-bundle.md §5.5).
28
+ // Matching is on keys and hashes alone, never tenancy, so a pair across two
29
+ // organizations verifies. `readCase` verifies every pack itself, offline.
30
+ export { CASE_BODY_TYPES, CASE_EXCEPTION_KINDS, CASE_QUARANTINED_PROFILES, CASE_RECORD_PROFILES, CASE_RECORD_STATUSES, CASE_NOTE_KINDS, CASE_RELIANCE, CASE_RELIANCE_HANDOFF_CLAUSE, CASE_RELIANCE_SANDBOX, CASE_VERDICTS, CONTENT_WITHHELD_BY_DECLARATION, CO_SIGNATURES_PRESENT, VERDICT_DISPLAY_TITLES, WITNESS_NOT_LOOKED_UP, WITNESS_STATES, WITNESS_TIME_CACHED, WITNESS_TIME_RECORDED, caseProblems, caseReliance, readCase, renderCaseNote, renderCaseSummary, renderException, renderWitnessLine, } from "./case.js";
31
+ // The witnessed-time cache (evidence-bundle.md §5.6.6). Never an input to a
32
+ // verdict.
100
33
  export { MAX_BLOCK_TIME, MAX_WITNESS_CACHE_DEPTH, WITNESS_CACHE_NAME, WITNESS_CACHE_VERSION, checkWitnessCache, formatBlockTime, readWitnessCache, renderWitnessTime, witnessTimeQuery, } from "./witness-cache.js";
101
- // The public-record (witness) lookup the CLI runs with `--gateways`
102
- // (src/witness-lookup.ts, proof#200): moved out of the CLI so a consumer
103
- // that is not the CLI, the verify page, calls the SAME implementation
104
- // rather than keeping its own copy (verify-page#70). Pure kernel scope: the
105
- // one network call lives in `lookupPublicRecord` and `onChainHalf`, runs
106
- // only when a caller hands in a gateway, and goes through `options.fetchImpl`
107
- // where a caller supplies one (a browser page's own `fetch`) or the ambient
108
- // global `fetch` otherwise, so this export runs in a browser exactly as it
109
- // runs in Node. `onChainHalf` and `witnessLine` are the CLI's own unchanged
110
- // building blocks; `lookupPublicRecord` is the new one-call, four-state entry
111
- // point a page wants, additive over both. `confirmed` from
112
- // `lookupPublicRecord` is a claim about the BYTES only, never about whether
113
- // the pack itself verifies, and a caller must never show it apart from the
114
- // pack's own verdict.
115
- export { lookupPublicRecord, onChainHalf, witnessLine } from "./witness-lookup.js";
116
- // The case file's index (src/case-file.ts, evidence-bundle.md §5.6, A25):
117
- // compared with the drop it describes, with NO verdict contribution. The index
118
- // is never an input to `readCase`. Pure: bytes and a file list in.
34
+ // The public-record lookup behind `--gateways`. The only network call runs when
35
+ // a caller hands in a gateway, through `options.fetchImpl` or the global
36
+ // `fetch`, so it runs in a browser. `confirmed` is a claim about the bytes
37
+ // only: never show it apart from the pack's own verdict.
38
+ export { lookupPublicRecord, onChainHalf, onChainOutcome, onChainRow, witnessLine, } from "./witness-lookup.js";
39
+ // Six claims, three verdicts, and the person layer (evidence-bundle.md section 3): every
40
+ // detailed kind maps to one claim and one state, and the verdict is read off the claims.
41
+ export { CLAIMS, CLAIM_LABELS, CLAIM_QUESTIONS, CLAIM_STATES, ENVELOPE_FAULT_KINDS, KIND_CLAIMS, NOTE_FINDINGS, NOTE_ORDER, NOT_IN_SCOPE_REASONS, NOT_PROVEN_REASONS, PERSON_TITLES, PERSON_TITLE_PARTS, REASON_KINDS, RECORD_REASON_CLAIMS, RECORD_REASON_LINES, SANDBOX_PERSON_LINE, VERDICTS, VERDICT_COLOURS, VERDICT_TITLES, bundleProblems, claimsOf, downgraded, note, orderedNotes, restOnSigned, personText, problem, problemToJson, renderFindingNote, renderPerson, verdictOf, withItems, } from "./claims.js";
42
+ // The case file's index (evidence-bundle.md §5.6), compared with the drop it
43
+ // describes. Never an input to `readCase` or any verdict.
119
44
  export { CASE_FILE_FINDING_KINDS, CASE_FILE_INDEX_NAME, CASE_FILE_VERSION, HOW_TO_VERIFY_NAME, REPORT_README_FIRST_LINE, howToVerifyText, isPackRef, readCaseFileIndex, renderCaseFileFinding, } from "./case-file.js";
120
- // Files handed in beside a pack (src/file-match.ts, evidence-bundle.md §5.7,
121
- // A29, proof#92): each file's SHA-256 matched against the commitments the
122
- // pack's SIGNED records make, by hash alone. Never moves a verdict.
45
+ // Files handed in beside a pack (evidence-bundle.md §5.7), matched by SHA-256
46
+ // against the pack's signed commitments. Never moves a verdict.
123
47
  export { FILE_MATCH_SCOPE, NOT_READ_REASONS, SKIPPED_REASONS, fileMatchToJson, matchCaseFiles, matchFiles, notAccountedFor, renderFileMatch, } from "./file-match.js";
124
- // Chain reading (src/chain.ts): following the pointer every sanning.events/v2
125
- // record carries to the record before it, over the records ONE bundle presents.
126
- //
127
- // Every anchored event has carried that pointer since the profile was ratified
128
- // and nothing we shipped read it, so a bundle with an event removed — and a
129
- // chain that restarted after a crash and now asserts two beginnings — passed
130
- // every check we had (proof#43). The verifier was right not to do this: it
131
- // verifies a single envelope and says so. Nothing above it did it either.
132
- //
133
- // Pure — data in, data out, no I/O — so the kernel's scope boundary
134
- // (specs/architecture.md §3) is unchanged, and the rule ships as
135
- // `vectors/chain-reading.json` beside the pack-grading table for the same
136
- // reason: a rule consumers must agree with needs a statement they can fetch.
137
- //
138
- // It returns FINDINGS, never a verdict, and it feeds no status on its own: a
139
- // pack's signed v3 declaration can claim a chain complete and in order, and
140
- // `checkDeclaration` holds that claim to the links `readChainLinks` reads
141
- // (evidence-bundle.md 5.4.2 rule 11). Chain links are
142
- // deletion/reorder-evidence for the events present and NOT a completeness proof
143
- // (`anchor/docs/profile-sanning.events-v2.md` §5), drop the last N events of a
144
- // chain and nothing dangles. `CHAIN_READING_SCOPE` is that sentence, exported so
145
- // every surface prints the same limit rather than paraphrasing it into a claim.
146
- // Additive — no existing export changes.
48
+ // Chain reading: findings over the `previous_hash` links one bundle presents,
49
+ // never a verdict and never a completeness proof. `CHAIN_READING_SCOPE` is the
50
+ // sentence every surface prints beside them. `vectors/chain-reading.json`
51
+ // states the rule; a v3 declaration's chain claim is checked against
52
+ // `readChainLinks` (evidence-bundle.md §5.4.2 rule 11).
147
53
  export { ADAPTER_CHAIN_NAMESPACES, CHAIN_READING_SCOPE, readChainLinks, readChains, renderChainFinding, } from "./chain.js";
148
- // The `proof export` composer (specs/evidence-export.md §5, phase 2): produce a
149
- // signed, offline-verifiable sanning.evidence.export/v2 artifact from a source
150
- // anchor-trace bundle + operator attestations + an exporter Ed25519 key. The
151
- // inverse of verifyEvidenceBundle's verifyExportBody dispatch.
152
- // One exit-code table for every verb (0.13.0): the verdict word to the exit
153
- // code, and the help text every verb prints. Additive.
154
- export { EXIT_CODES, EXIT_CODES_HELP, EXIT_FAILED, EXIT_MALFORMED, EXIT_MIXED, EXIT_SANDBOX, EXIT_UNDETERMINED, EXIT_VERIFIED, exitCodeFor, sandboxExit, } from "./exit-codes.js";
155
- // Sandbox evidence: the environment marker over the envelopes a pack or case
156
- // holds (envelope-spec §2, the `environment_marker` MAY), and the headline and
157
- // line both commands print for it. Additive.
158
- export { SANDBOX_HEADLINE, SANDBOX_LINE, SANDBOX_TITLE, environmentMarker, onlySimulatedUnsettled, packEnvelopes, } from "./environment.js";
54
+ // The `proof export` composer (specs/evidence-export.md §5): a signed,
55
+ // offline-verifiable sanning.evidence.export/v2 artifact. Also the one
56
+ // exit-code table and help text every verb uses.
57
+ export { EXIT_CODES, EXIT_CODES_HELP, EXIT_COULD_NOT_RUN, EXIT_FAILED, EXIT_INCOMPLETE, EXIT_SANDBOX, EXIT_VERIFIED, exitCodeFor, } from "./exit-codes.js";
58
+ // Sandbox evidence: the environment marker over a pack's or case's envelopes
59
+ // (envelope-spec section 2).
60
+ export { environmentMarker, packEnvelopes, } from "./environment.js";
159
61
  export { attestationSignatureToHex, composeExport } from "./compose.js";
160
- // Agent inclusion-proof bundle verification: the
161
- // sanning.agent.proof/v1 bundle. The CLI sniffs spec_version and routes here so
162
- // one verifier covers both agent and anchor bundles.
163
- export { AGENT_PROOF_SPEC_VERSION, isAgentProofSpec, verifyAgentProof } from "./agent-proof.js";
164
- // The hand-off pairing rule (src/handoff.ts): which records are candidates to
165
- // be the counterpart of a hand-off record, how a candidate set of more than one
166
- // is ordered, and what a formed pair grades to (specs/envelope-spec.md §4.1
167
- // v1.9, proof#132 and proof#136). The Python half is src/sanning_proof/handoff.py and the two
168
- // answer identically on identical bytes. Additive: a new module, and no
169
- // existing export changes.
170
- export { CANDIDATE_NAMESPACE, DEFINED_EVENT_TYPES, NOT_A_HANDOFF_FINDING, isConformantHandoffRecord, readHandoff, readHandoffs, recordIsMalformed, } from "./handoff.js";
171
- // A file part's BYTES (src/message-parts.ts): what a file part is, and what a
172
- // receiver that HOLDS a part's bytes commits to (envelope-spec.md section 4.1
173
- // v1.13, A18, proof#145). A receiver that holds the bytes hashes them and, on a
174
- // mismatch, commits to the message AS IT HELD IT, so the pair fails on
175
- // `message_hash` rather than verifying over bytes nobody checked. The Python
176
- // half is src/sanning_proof/message_parts.py and the two are held together by
177
- // cross-kernel/run_parts.sh. Pure: it neither canonicalizes nor hashes the
178
- // message.
62
+ // The hand-off pairing rule (envelope-spec.md §4.1). The Python half answers
63
+ // identically on identical bytes.
64
+ export { CANDIDATE_NAMESPACE, DEFINED_EVENT_TYPES, NOT_A_HANDOFF_FINDING, isConformantHandoffRecord, readHandoff, readHandoffs, recordDefect, recordIsMalformed, recordIsNonconforming, } from "./handoff.js";
65
+ // File parts (envelope-spec.md §4.1): a receiver holding a part's bytes
66
+ // commits to the message as it held it, so a mismatch fails on `message_hash`
67
+ // rather than verifying over unchecked bytes.
179
68
  export { BYTES_FOR_UNKNOWN_PART, CONFLICTING_PART_BYTES, INLINE_BYTES_KEYS, MESSAGE_RESULT_ORDER, PARTS_NOT_AN_ARRAY, PART_ENCODING_MISMATCH, PART_INLINE_BYTES, PART_INLINE_MISMATCHED, PART_MALFORMED_DESCRIPTOR, PART_MATCHED, PART_MISMATCHED, PART_NOT_A_FILE, PART_SUPPLIED_TWICE, PART_UNCHECKED, REFUSAL_ORDER, commitHeldMessage, isFilePart, uncheckedHeldParts, } from "./message-parts.js";
69
+ // Reading a sanning.agent record (vendor/specs/agent-events.md §10) against
70
+ // the schemas bundled from the pinned specs release: no file read, no fetch.
71
+ export { AGENT_EVENT_TYPES, RECORD_TYPES_OUTSIDE_AGENT, readAgentRecord, readAgentRecordWithHeld, readAgentRecords, renderAgentReading, } from "./agent-record.js";
72
+ export { AGENT_SCHEMA_PIN, AGENT_SCHEMA_VERSIONS } from "./agent-schemas.generated.js";
@@ -0,0 +1,29 @@
1
+ export type JsonSchema = boolean | {
2
+ readonly [keyword: string]: unknown;
3
+ };
4
+ export type SchemaReason = "unknown_field" | "missing_field" | "bad_value";
5
+ export interface SchemaError {
6
+ readonly reason: SchemaReason;
7
+ readonly at: string;
8
+ }
9
+ /** Validate against schemas that reference each other by `$id`. */
10
+ export declare class SchemaSet {
11
+ private readonly documents;
12
+ private readonly patterns;
13
+ constructor(documents: readonly JsonSchema[]);
14
+ /** Every error `value` has against the document whose `$id` is `id`; empty when it validates. */
15
+ validate(id: string, value: unknown): SchemaError[];
16
+ private check;
17
+ private passes;
18
+ private resolve;
19
+ private pattern;
20
+ }
21
+ /** JSON equality, without recursion so a deeply nested value cannot overflow the stack. */
22
+ export declare function deepEqual(a: unknown, b: unknown): boolean;
23
+ export declare function isObject(v: unknown): v is Record<string, unknown>;
24
+ export declare function has(obj: object, key: string): boolean;
25
+ /** One JSON Pointer reference token (RFC 6901). */
26
+ export declare function escapeToken(t: string): string;
27
+ export declare function unescapeToken(t: string): string;
28
+ /** Freeze `value` and every object and array inside it. */
29
+ export declare function deepFreeze<T>(value: T): T;
@@ -0,0 +1,298 @@
1
+ // A JSON Schema (draft 2020-12) validator for the keywords the pinned
2
+ // sanning.agent schemas use, and no others. It reads schemas handed to it as
3
+ // data, resolves `$ref` among them by `$id`, and never fetches anything. A
4
+ // keyword outside the supported set throws rather than being skipped: a later
5
+ // pin that adds one must fail loudly, never validate less than it says.
6
+ //
7
+ // Errors are collected in all-errors mode and returned as the reasons of
8
+ // agent-events.md §10 step 4 and §10.1: `unknown_field` (additionalProperties), `missing_field`
9
+ // (required) and `bad_value` (anything else), each at a JSON Pointer.
10
+ // Keywords that carry no assertion.
11
+ const ANNOTATIONS = new Set(["$schema", "$id", "$defs", "title", "description"]);
12
+ const ASSERTIONS = new Set([
13
+ "$ref",
14
+ "type",
15
+ "const",
16
+ "enum",
17
+ "not",
18
+ "anyOf",
19
+ "properties",
20
+ "additionalProperties",
21
+ "required",
22
+ "minProperties",
23
+ "items",
24
+ "minItems",
25
+ "maxItems",
26
+ "uniqueItems",
27
+ "pattern",
28
+ "minLength",
29
+ "maxLength",
30
+ "minimum",
31
+ "maximum",
32
+ ]);
33
+ /** Validate against schemas that reference each other by `$id`. */
34
+ export class SchemaSet {
35
+ documents = new Map();
36
+ patterns = new Map();
37
+ constructor(documents) {
38
+ for (const d of documents) {
39
+ if (typeof d !== "object" || typeof d.$id !== "string") {
40
+ throw new Error("json-schema: every document needs an $id");
41
+ }
42
+ supportedOnly(d);
43
+ this.documents.set(stripFragment(d.$id), d);
44
+ }
45
+ }
46
+ /** Every error `value` has against the document whose `$id` is `id`; empty when it validates. */
47
+ validate(id, value) {
48
+ const doc = this.documents.get(id);
49
+ if (doc === undefined)
50
+ throw new Error(`json-schema: no document ${id}`);
51
+ const errors = [];
52
+ this.check(doc, id, value, "", errors);
53
+ return errors;
54
+ }
55
+ check(schema, base, value, at, errors) {
56
+ if (schema === true)
57
+ return;
58
+ if (schema === false) {
59
+ errors.push({ reason: "bad_value", at });
60
+ return;
61
+ }
62
+ const s = schema;
63
+ const bad = () => {
64
+ errors.push({ reason: "bad_value", at });
65
+ };
66
+ if (s.$ref !== undefined) {
67
+ const [doc, target] = this.resolve(String(s.$ref), base);
68
+ this.check(target, doc, value, at, errors);
69
+ }
70
+ if (s.type !== undefined) {
71
+ const types = Array.isArray(s.type) ? s.type : [s.type];
72
+ if (!types.some((t) => hasType(value, t)))
73
+ bad();
74
+ }
75
+ if (has(s, "const") && !deepEqual(value, s.const))
76
+ bad();
77
+ if (s.enum !== undefined && !s.enum.some((e) => deepEqual(value, e)))
78
+ bad();
79
+ if (s.not !== undefined && this.passes(s.not, base, value))
80
+ bad();
81
+ if (s.anyOf !== undefined) {
82
+ const branchErrors = [];
83
+ let passed = false;
84
+ for (const branch of s.anyOf) {
85
+ const e = [];
86
+ this.check(branch, base, value, at, e);
87
+ if (e.length === 0) {
88
+ passed = true;
89
+ break;
90
+ }
91
+ branchErrors.push(...e);
92
+ }
93
+ if (!passed) {
94
+ errors.push(...branchErrors);
95
+ bad();
96
+ }
97
+ }
98
+ if (typeof value === "string") {
99
+ if (s.pattern !== undefined && !this.pattern(String(s.pattern)).test(value))
100
+ bad();
101
+ if (s.minLength !== undefined && codePoints(value) < s.minLength)
102
+ bad();
103
+ if (s.maxLength !== undefined && codePoints(value) > s.maxLength)
104
+ bad();
105
+ }
106
+ if (typeof value === "number") {
107
+ if (s.minimum !== undefined && value < s.minimum)
108
+ bad();
109
+ if (s.maximum !== undefined && value > s.maximum)
110
+ bad();
111
+ }
112
+ if (Array.isArray(value)) {
113
+ if (s.minItems !== undefined && value.length < s.minItems)
114
+ bad();
115
+ if (s.maxItems !== undefined && value.length > s.maxItems)
116
+ bad();
117
+ if (s.uniqueItems === true && !allUnique(value))
118
+ bad();
119
+ if (s.items !== undefined) {
120
+ value.forEach((item, i) => this.check(s.items, base, item, `${at}/${i}`, errors));
121
+ }
122
+ }
123
+ if (isObject(value)) {
124
+ const props = (s.properties ?? {});
125
+ if (s.required !== undefined) {
126
+ for (const name of s.required) {
127
+ if (!has(value, name))
128
+ errors.push({ reason: "missing_field", at: `${at}/${escapeToken(name)}` });
129
+ }
130
+ }
131
+ if (s.minProperties !== undefined && Object.keys(value).length < s.minProperties)
132
+ bad();
133
+ for (const key of Object.keys(value)) {
134
+ const child = `${at}/${escapeToken(key)}`;
135
+ if (has(props, key)) {
136
+ this.check(props[key], base, value[key], child, errors);
137
+ }
138
+ else if (s.additionalProperties === false) {
139
+ errors.push({ reason: "unknown_field", at: child });
140
+ }
141
+ else if (s.additionalProperties !== undefined) {
142
+ this.check(s.additionalProperties, base, value[key], child, errors);
143
+ }
144
+ }
145
+ }
146
+ }
147
+ passes(schema, base, value) {
148
+ const e = [];
149
+ this.check(schema, base, value, "", e);
150
+ return e.length === 0;
151
+ }
152
+ resolve(ref, base) {
153
+ const url = new URL(ref, base);
154
+ const doc = stripFragment(url.href);
155
+ let target = this.documents.get(doc);
156
+ if (target === undefined)
157
+ throw new Error(`json-schema: no document for $ref ${ref}`);
158
+ const fragment = decodeURIComponent(url.hash.slice(1));
159
+ if (fragment !== "") {
160
+ if (!fragment.startsWith("/"))
161
+ throw new Error(`json-schema: unsupported $ref ${ref}`);
162
+ for (const token of fragment.slice(1).split("/")) {
163
+ const t = unescapeToken(token);
164
+ if (!isObject(target) || !has(target, t))
165
+ throw new Error(`json-schema: unresolved $ref ${ref}`);
166
+ target = target[t];
167
+ }
168
+ }
169
+ return [doc, target];
170
+ }
171
+ pattern(source) {
172
+ let re = this.patterns.get(source);
173
+ if (re === undefined) {
174
+ // ECMA-262 with the `u` flag, as JSON Schema reads `pattern`: `$` is the
175
+ // end of the string, with no exception for a final newline.
176
+ re = new RegExp(source, "u");
177
+ this.patterns.set(source, re);
178
+ }
179
+ return re;
180
+ }
181
+ }
182
+ /** Throw on a keyword this validator does not implement, anywhere in `schema`. */
183
+ function supportedOnly(schema) {
184
+ const stack = [schema];
185
+ while (stack.length > 0) {
186
+ const s = stack.pop();
187
+ if (typeof s === "boolean")
188
+ continue;
189
+ if (!isObject(s))
190
+ throw new Error("json-schema: a schema is an object or a boolean");
191
+ for (const [k, v] of Object.entries(s)) {
192
+ if (!ANNOTATIONS.has(k) && !ASSERTIONS.has(k))
193
+ throw new Error(`json-schema: unsupported keyword ${k}`);
194
+ if (k === "properties" || k === "$defs")
195
+ stack.push(...Object.values(v));
196
+ else if (k === "anyOf")
197
+ stack.push(...v);
198
+ else if (k === "items" || k === "not" || k === "additionalProperties")
199
+ stack.push(v);
200
+ }
201
+ }
202
+ }
203
+ function stripFragment(id) {
204
+ const i = id.indexOf("#");
205
+ return i === -1 ? id : id.slice(0, i);
206
+ }
207
+ function hasType(value, type) {
208
+ switch (type) {
209
+ case "null":
210
+ return value === null;
211
+ case "boolean":
212
+ return typeof value === "boolean";
213
+ case "string":
214
+ return typeof value === "string";
215
+ case "number":
216
+ return typeof value === "number" && Number.isFinite(value);
217
+ case "integer":
218
+ return Number.isInteger(value);
219
+ case "array":
220
+ return Array.isArray(value);
221
+ case "object":
222
+ return isObject(value);
223
+ default:
224
+ throw new Error(`json-schema: unsupported type ${type}`);
225
+ }
226
+ }
227
+ /** String length as JSON Schema counts it: in code points, not UTF-16 code units. */
228
+ function codePoints(s) {
229
+ let n = 0;
230
+ for (const _ of s)
231
+ n++;
232
+ return n;
233
+ }
234
+ function allUnique(items) {
235
+ for (let i = 0; i < items.length; i++) {
236
+ for (let j = i + 1; j < items.length; j++) {
237
+ if (deepEqual(items[i], items[j]))
238
+ return false;
239
+ }
240
+ }
241
+ return true;
242
+ }
243
+ /** JSON equality, without recursion so a deeply nested value cannot overflow the stack. */
244
+ export function deepEqual(a, b) {
245
+ const stack = [[a, b]];
246
+ while (stack.length > 0) {
247
+ const [x, y] = stack.pop();
248
+ if (x === y)
249
+ continue;
250
+ if (Array.isArray(x)) {
251
+ if (!Array.isArray(y) || x.length !== y.length)
252
+ return false;
253
+ for (let i = 0; i < x.length; i++)
254
+ stack.push([x[i], y[i]]);
255
+ continue;
256
+ }
257
+ if (isObject(x)) {
258
+ if (!isObject(y))
259
+ return false;
260
+ const kx = Object.keys(x);
261
+ if (kx.length !== Object.keys(y).length)
262
+ return false;
263
+ for (const k of kx) {
264
+ if (!has(y, k))
265
+ return false;
266
+ stack.push([x[k], y[k]]);
267
+ }
268
+ continue;
269
+ }
270
+ return false;
271
+ }
272
+ return true;
273
+ }
274
+ export function isObject(v) {
275
+ return v !== null && typeof v === "object" && !Array.isArray(v);
276
+ }
277
+ export function has(obj, key) {
278
+ return Object.prototype.hasOwnProperty.call(obj, key);
279
+ }
280
+ /** One JSON Pointer reference token (RFC 6901). */
281
+ export function escapeToken(t) {
282
+ return t.replaceAll("~", "~0").replaceAll("/", "~1");
283
+ }
284
+ export function unescapeToken(t) {
285
+ return t.replaceAll("~1", "/").replaceAll("~0", "~");
286
+ }
287
+ /** Freeze `value` and every object and array inside it. */
288
+ export function deepFreeze(value) {
289
+ const stack = [value];
290
+ while (stack.length > 0) {
291
+ const v = stack.pop();
292
+ if (v !== null && typeof v === "object" && !Object.isFrozen(v)) {
293
+ Object.freeze(v);
294
+ stack.push(...Object.values(v));
295
+ }
296
+ }
297
+ return value;
298
+ }