@agenticprimitives/content-primitives 1.0.0-alpha.10

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 (45) hide show
  1. package/CLAUDE.md +62 -0
  2. package/LICENSE +21 -0
  3. package/README.md +63 -0
  4. package/dist/descriptor.d.ts +67 -0
  5. package/dist/descriptor.d.ts.map +1 -0
  6. package/dist/descriptor.js +128 -0
  7. package/dist/descriptor.js.map +1 -0
  8. package/dist/entitlement.d.ts +64 -0
  9. package/dist/entitlement.d.ts.map +1 -0
  10. package/dist/entitlement.js +64 -0
  11. package/dist/entitlement.js.map +1 -0
  12. package/dist/errors.d.ts +9 -0
  13. package/dist/errors.d.ts.map +1 -0
  14. package/dist/errors.js +15 -0
  15. package/dist/errors.js.map +1 -0
  16. package/dist/index.d.ts +13 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +26 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/jcs.d.ts +4 -0
  21. package/dist/jcs.d.ts.map +1 -0
  22. package/dist/jcs.js +25 -0
  23. package/dist/jcs.js.map +1 -0
  24. package/dist/merkle.d.ts +29 -0
  25. package/dist/merkle.d.ts.map +1 -0
  26. package/dist/merkle.js +74 -0
  27. package/dist/merkle.js.map +1 -0
  28. package/dist/reference.d.ts +28 -0
  29. package/dist/reference.d.ts.map +1 -0
  30. package/dist/reference.js +35 -0
  31. package/dist/reference.js.map +1 -0
  32. package/dist/reserved.d.ts +12 -0
  33. package/dist/reserved.d.ts.map +1 -0
  34. package/dist/reserved.js +19 -0
  35. package/dist/reserved.js.map +1 -0
  36. package/dist/resolution.d.ts +41 -0
  37. package/dist/resolution.d.ts.map +1 -0
  38. package/dist/resolution.js +35 -0
  39. package/dist/resolution.js.map +1 -0
  40. package/dist/types.d.ts +194 -0
  41. package/dist/types.d.ts.map +1 -0
  42. package/dist/types.js +2 -0
  43. package/dist/types.js.map +1 -0
  44. package/package.json +64 -0
  45. package/spec.md +16 -0
package/CLAUDE.md ADDED
@@ -0,0 +1,62 @@
1
+ # @agenticprimitives/content-primitives — Claude guide
2
+
3
+ Name → resolve → commit → entitlement-gate → cite, for content that lives
4
+ off-platform and is controlled by third-party rights holders. **Bible verses are
5
+ its first usage domain (spec 267), not its vocabulary.**
6
+
7
+ ## The one idea
8
+
9
+ **Content is not an Agent.** A `CanonicalLocus` (a passage address) is
10
+ **scheme-anchored** — a deterministic `locusId`, never registered, never an SA
11
+ facet. Only *issuers/corpora* and *parties* are Smart Agents (ADR-0010 still
12
+ governs them via `agent-naming`). This is the FRBR Work/Item split and the reason
13
+ this is a new substrate, not an `agent-naming` record type. See ADR-0033.
14
+
15
+ ## What this package owns (FRBR)
16
+
17
+ - `CanonicalLocus` (Work) — `computeLocusId(scheme, normalizedPath)`.
18
+ - `CorpusManifest` (Manifestation) — issuer-owned, Merkle `corpusRoot`.
19
+ - `ContentDescriptor` (Item) — the deliverable leaf; `commitment` +
20
+ `retrievalPointer` + issuer signature. **Never the text.**
21
+ - `Entitlement` / `CitationAssertion` — VC 2.0 subjects (envelope from
22
+ `verifiable-credentials`).
23
+ - Merkle helpers (`/merkle` subpath), commitment + descriptor verification,
24
+ fail-closed `evaluateEntitlement`.
25
+
26
+ ## Hard rules (ADR-0033 — do not break)
27
+
28
+ - **R3 — no rendering text** in any descriptor, a commitment preimage we store,
29
+ or on-chain. Descriptors carry a `retrievalPointer`.
30
+ - **R1 — no licensed/copyrighted content** in src/tests/fixtures (CI:
31
+ `check:no-licensed-content`).
32
+ - **R4 — content-agnostic.** No faith/vertical vocabulary; `contentType` + the
33
+ `ReferenceScheme` are app-injected (CI: `check:no-domain-in-packages`).
34
+ - **R5 — trust = issuer signature + access policy**, never a platform claim.
35
+
36
+ ## Boundary
37
+
38
+ Allowed imports: `@agenticprimitives/types`, `@agenticprimitives/verifiable-credentials`,
39
+ `viem`. ERC-1271 verification is **injected** (`SignatureVerifier`, ADR-0006) — do
40
+ NOT import `agent-account`/`agent-naming`; apps compose them.
41
+
42
+ ## Drift triggers — STOP
43
+
44
+ - "Register a locus / give a verse an SA / put it in `agent-naming`" — **STOP.**
45
+ Loci are scheme-anchored content (ADR-0033).
46
+ - "Store the verse text / put text in the commitment we keep / on-chain" — **STOP** (R3).
47
+ - "Hardcode a translation, book table, OSIS grammar, or `'bible-verse'`" — **STOP.**
48
+ App layer (spec 267); inject a `ReferenceScheme`.
49
+ - "Implement the ZK/payment reserved fns" — that's Phase 4/5 (spec 266 §6).
50
+
51
+ ## Read first
52
+
53
+ `../../specs/266-verifiable-content-substrate.md` ·
54
+ `../../docs/architecture/decisions/0033-content-agnostic-verifiable-content-firewall.md`
55
+ · then `src/index.ts`.
56
+
57
+ ## Validate
58
+
59
+ ```bash
60
+ pnpm --filter @agenticprimitives/content-primitives typecheck
61
+ pnpm --filter @agenticprimitives/content-primitives test
62
+ ```
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Agentic Trust Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # @agenticprimitives/content-primitives
2
+
3
+ The verifiable content substrate — name, resolve, commit, entitlement-gate, and cite content that lives off-platform and is controlled by third-party rights holders.
4
+
5
+ Agents increasingly act on content they do not own: quoting a licensed text, citing a canonical passage, gating access to a rights-held corpus. The naive approaches all fail — copy the text and you violate the license; trust the platform and the citation is unverifiable; mint every passage an identity and the identity layer drowns. This package takes the third path: content is **never an agent and never stored**. A unit of content gets a deterministic, scheme-anchored address; an issuer (who IS a Smart Agent) signs a commitment to it; readers verify the signature, evaluate the entitlement, and cite the result — all without the text ever entering the substrate ([ADR-0033](../../docs/architecture/decisions/0033-content-agnostic-verifiable-content-firewall.md)).
6
+
7
+ The package is strictly content-agnostic: no rendering text in any descriptor or commitment we store (R3), no licensed material in the repo (R1), and the reference grammar is app-injected, never hardcoded (R4). Trust derives from the issuer's signature and access policy, never a platform claim (R5).
8
+
9
+ Part of [agenticprimitives](../../README.md) — the trust substrate for the agent economy: one canonical Smart Agent identity with custody, delegation, naming, credentials, and audit evidence designed as one system.
10
+
11
+ ## Model (FRBR)
12
+
13
+ | FRBR | Type | Notes |
14
+ | --- | --- | --- |
15
+ | Work | `CanonicalLocus` | scheme-anchored deterministic `locusId`; never registered |
16
+ | Manifestation | `CorpusManifest` | issuer-owned, Merkle `corpusRoot`, signed |
17
+ | Item | `ContentDescriptor` | commitment + `retrievalPointer` + issuer signature — **never text** |
18
+ | — | `Entitlement` / `CitationAssertion` | W3C VC 2.0 subjects |
19
+
20
+ The FRBR Work/Item split is why this is a new substrate and not another naming-record type: a content locus is an address computed from a reference scheme, while only issuers, corpora owners, and parties are Smart Agents (ADR-0010 still governs *them*).
21
+
22
+ ## Quick start
23
+
24
+ ```ts
25
+ import {
26
+ buildCanonicalLocus, corpusRef, contentCommitment,
27
+ buildContentDescriptor, verifyContentDescriptor,
28
+ evaluateEntitlement, buildCitationAssertion,
29
+ } from '@agenticprimitives/content-primitives';
30
+
31
+ // 1. App supplies the reference grammar (kept out of the package — R4).
32
+ const clauseScheme = { id: 'standard-clause', normalize: (p: string) => /* canonical form */ p };
33
+ const locus = buildCanonicalLocus(clauseScheme, 'Part 4, Section 2'); // -> { locusId, path: 'Part4.Section2' }
34
+
35
+ // 2. Issuer commits to off-platform text + signs a descriptor (no text on-chain — R3).
36
+ const commitment = contentCommitment(renderingText); // keccak256, off-platform
37
+ const descriptor = await buildContentDescriptor(
38
+ { locusId: locus.locusId, corpusRef: ref, contentType: 'standard-clause',
39
+ commitment, proofPolicy: 'signature', accessPolicy: 'public',
40
+ retrievalPointer: 'content://standard-clause/v3/Part4.Section2', issuer },
41
+ issuerSign, // signs descriptorHash via the issuer SA (ERC-1271)
42
+ );
43
+
44
+ // 3. Reader verifies (signature injected — ADR-0006) + gates + cites.
45
+ const ok = await verifyContentDescriptor(descriptor, { verifySignature });
46
+ const gate = evaluateEntitlement(descriptor.accessPolicy, descriptor.corpusRef);
47
+ ```
48
+
49
+ Entitlement evaluation is fail-closed; Merkle helpers ship under the `/merkle` subpath; ERC-1271 signature verification is dependency-injected so the package stays at the base of the graph.
50
+
51
+ ## Status
52
+
53
+ Phases 1–3 (naming, commitment, descriptor verification, entitlement gating, citation) are implemented and tested. **ZK proofs and paid access are reserved (Phase 4/5) and throw until implemented** — the full SDK surface and phased roadmap live in [spec 266](../../specs/266-verifiable-content-substrate.md) (see [`spec.md`](./spec.md)).
54
+
55
+ Testnet/pilot-ready. Production launch is gated on the public checklist in the root README — including third-party contract audit and governance key rotation. Track every security finding live in [`docs/audits/findings.yaml`](../../docs/audits/findings.yaml).
56
+
57
+ ## Build
58
+
59
+ ```bash
60
+ pnpm --filter @agenticprimitives/content-primitives typecheck
61
+ pnpm --filter @agenticprimitives/content-primitives test
62
+ pnpm --filter @agenticprimitives/content-primitives build
63
+ ```
@@ -0,0 +1,67 @@
1
+ import { type Hex } from 'viem';
2
+ import type { BuildDescriptorInput, ContentCommitment, ContentDescriptor, DelegatingSigner, DelegatedAuthorityVerifier, SignatureVerifier } from './types.js';
3
+ /**
4
+ * The frozen Phase-1 normalization profile id (spec 266 §7). Rules of
5
+ * `canonical-text-v1`: NFC; trim leading/trailing whitespace; collapse internal
6
+ * whitespace runs to a single space; text body only (verse numbers, labels,
7
+ * footnotes, headings, cross-refs, formatting are excluded by the caller before
8
+ * commitment); digest SHA-256 over UTF-8. Bump the version to change any rule.
9
+ */
10
+ export declare const NORMALIZATION_V1 = "ap:normalization:canonical-text-v1";
11
+ /** Apply the canonical-text-v1 normalization to a rendering body. */
12
+ export declare function canonicalizeRendering(text: string): string;
13
+ /**
14
+ * Structured commitment to an off-platform rendering (spec 266 §7):
15
+ * SHA-256 of the canonical-text-v1-normalized body. SHA-256 (not keccak) keeps
16
+ * the content commitment portable/standard; it is verified off-chain and never
17
+ * stored on-chain (ADR-0033 R3). Binds a descriptor to a rendering WITHOUT
18
+ * revealing it.
19
+ */
20
+ export declare function contentCommitment(text: string): ContentCommitment;
21
+ /** True iff `text` canonicalizes+hashes to the commitment value. */
22
+ export declare function verifyCommitment(text: string, commitment: ContentCommitment): boolean;
23
+ /** Throwing variant of {@link verifyCommitment}. */
24
+ export declare function assertCommitment(text: string, commitment: ContentCommitment): void;
25
+ /**
26
+ * Deterministic, domain-separated hash of the unsigned descriptor — both its
27
+ * cryptographic identity (ContentDescriptorId) AND the ERC-1271 signing
28
+ * preimage. `keccak256("ap:content-descriptor:v1\0" || JCS(unsigned))`. The
29
+ * domain separator keeps it from ever colliding with a canonical-locus id.
30
+ */
31
+ export declare function descriptorHash(d: BuildDescriptorInput): Hex;
32
+ /**
33
+ * Build a signed {@link ContentDescriptor}. `sign` signs {@link descriptorHash} — either as the issuer's
34
+ * own Smart Agent (ERC-1271), or, when `delegatingSigner` is given, as the issuer-AUTHORIZED operational
35
+ * key (e.g. Cloud KMS). The attached `delegatingSigner` lets a verifier root trust in the issuer SA while
36
+ * the day-to-day signing key is delegated/rotatable (no issuer custodian key held).
37
+ */
38
+ export declare function buildContentDescriptor(input: BuildDescriptorInput, sign: (hash: Hex) => Promise<Hex> | Hex, delegatingSigner?: DelegatingSigner): Promise<ContentDescriptor>;
39
+ export interface VerifyDescriptorOpts {
40
+ /** Verifies an ERC-1271/ECDSA signature by a signer (injected; ADR-0006). */
41
+ verifySignature: SignatureVerifier;
42
+ /** Verifies an issuer→delegate authorization leaf — REQUIRED when the descriptor carries
43
+ * `delegatingSigner` (else delegate-signed descriptors fail closed). Injected (ADR-0006). */
44
+ verifyDelegatedAuthority?: DelegatedAuthorityVerifier;
45
+ /** Required when proofPolicy is `merkle-membership-v1`. */
46
+ corpusRoot?: Hex;
47
+ inclusionProof?: Hex[];
48
+ /** Current time (seconds) for validity/status checks; defaults to now. */
49
+ nowSeconds?: number;
50
+ }
51
+ /** Result of {@link verifyContentDescriptor} — an auditable VerificationResult. */
52
+ export interface VerificationResult {
53
+ ok: boolean;
54
+ reason?: string;
55
+ signatureVerified: boolean;
56
+ statusOk: boolean;
57
+ withinValidity: boolean;
58
+ inclusionVerified?: boolean;
59
+ }
60
+ /**
61
+ * Verify a descriptor fail-closed (spec 266 §7): status must be `active`, the
62
+ * validity window must contain `now`, the issuer ERC-1271 signature over the
63
+ * canonical descriptor hash must verify, and — for `merkle-membership-v1` — the
64
+ * commitment must prove under `corpusRoot`. Reserved proof policies are rejected.
65
+ */
66
+ export declare function verifyContentDescriptor(d: ContentDescriptor, opts: VerifyDescriptorOpts): Promise<VerificationResult>;
67
+ //# sourceMappingURL=descriptor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"descriptor.d.ts","sourceRoot":"","sources":["../src/descriptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AAEpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAI9J;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,uCAAuC,CAAC;AAErE,qEAAqE;AACrE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAOjE;AAED,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,iBAAiB,GAAG,OAAO,CAGrF;AAED,oDAAoD;AACpD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,iBAAiB,GAAG,IAAI,CAIlF;AAKD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,oBAAoB,GAAG,GAAG,CAE3D;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,oBAAoB,EAC3B,IAAI,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,EACvC,gBAAgB,CAAC,EAAE,gBAAgB,GAClC,OAAO,CAAC,iBAAiB,CAAC,CAG5B;AAED,MAAM,WAAW,oBAAoB;IACnC,6EAA6E;IAC7E,eAAe,EAAE,iBAAiB,CAAC;IACnC;kGAC8F;IAC9F,wBAAwB,CAAC,EAAE,0BAA0B,CAAC;IACtD,2DAA2D;IAC3D,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,cAAc,CAAC,EAAE,GAAG,EAAE,CAAC;IACvB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,mFAAmF;AACnF,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,CAAC,EAAE,iBAAiB,EACpB,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,kBAAkB,CAAC,CAiD7B"}
@@ -0,0 +1,128 @@
1
+ import { keccak256, sha256, concat, toBytes } from 'viem';
2
+ import { jcsCanonicalize } from '@agenticprimitives/verifiable-credentials';
3
+ import { leafHash, verifyInclusion } from './merkle.js';
4
+ import { CommitmentMismatchError } from './errors.js';
5
+ /**
6
+ * The frozen Phase-1 normalization profile id (spec 266 §7). Rules of
7
+ * `canonical-text-v1`: NFC; trim leading/trailing whitespace; collapse internal
8
+ * whitespace runs to a single space; text body only (verse numbers, labels,
9
+ * footnotes, headings, cross-refs, formatting are excluded by the caller before
10
+ * commitment); digest SHA-256 over UTF-8. Bump the version to change any rule.
11
+ */
12
+ export const NORMALIZATION_V1 = 'ap:normalization:canonical-text-v1';
13
+ /** Apply the canonical-text-v1 normalization to a rendering body. */
14
+ export function canonicalizeRendering(text) {
15
+ return text.normalize('NFC').replace(/\s+/g, ' ').trim();
16
+ }
17
+ /**
18
+ * Structured commitment to an off-platform rendering (spec 266 §7):
19
+ * SHA-256 of the canonical-text-v1-normalized body. SHA-256 (not keccak) keeps
20
+ * the content commitment portable/standard; it is verified off-chain and never
21
+ * stored on-chain (ADR-0033 R3). Binds a descriptor to a rendering WITHOUT
22
+ * revealing it.
23
+ */
24
+ export function contentCommitment(text) {
25
+ return {
26
+ type: 'canonicalTextCommitment',
27
+ normalization: NORMALIZATION_V1,
28
+ algorithm: 'sha-256',
29
+ value: sha256(toBytes(canonicalizeRendering(text))),
30
+ };
31
+ }
32
+ /** True iff `text` canonicalizes+hashes to the commitment value. */
33
+ export function verifyCommitment(text, commitment) {
34
+ if (commitment.algorithm !== 'sha-256' || commitment.normalization !== NORMALIZATION_V1)
35
+ return false;
36
+ return contentCommitment(text).value.toLowerCase() === commitment.value.toLowerCase();
37
+ }
38
+ /** Throwing variant of {@link verifyCommitment}. */
39
+ export function assertCommitment(text, commitment) {
40
+ if (!verifyCommitment(text, commitment)) {
41
+ throw new CommitmentMismatchError('rendering does not match descriptor commitment');
42
+ }
43
+ }
44
+ /** Domain separator for the descriptor identity (distinct from the locus id). */
45
+ const DESCRIPTOR_DOMAIN_SEP = 'ap:content-descriptor:v1\0';
46
+ /**
47
+ * Deterministic, domain-separated hash of the unsigned descriptor — both its
48
+ * cryptographic identity (ContentDescriptorId) AND the ERC-1271 signing
49
+ * preimage. `keccak256("ap:content-descriptor:v1\0" || JCS(unsigned))`. The
50
+ * domain separator keeps it from ever colliding with a canonical-locus id.
51
+ */
52
+ export function descriptorHash(d) {
53
+ return keccak256(concat([toBytes(DESCRIPTOR_DOMAIN_SEP), toBytes(jcsCanonicalize(d))]));
54
+ }
55
+ /**
56
+ * Build a signed {@link ContentDescriptor}. `sign` signs {@link descriptorHash} — either as the issuer's
57
+ * own Smart Agent (ERC-1271), or, when `delegatingSigner` is given, as the issuer-AUTHORIZED operational
58
+ * key (e.g. Cloud KMS). The attached `delegatingSigner` lets a verifier root trust in the issuer SA while
59
+ * the day-to-day signing key is delegated/rotatable (no issuer custodian key held).
60
+ */
61
+ export async function buildContentDescriptor(input, sign, delegatingSigner) {
62
+ const signature = await sign(descriptorHash(input));
63
+ return { ...input, signature, ...(delegatingSigner ? { delegatingSigner } : {}) };
64
+ }
65
+ /**
66
+ * Verify a descriptor fail-closed (spec 266 §7): status must be `active`, the
67
+ * validity window must contain `now`, the issuer ERC-1271 signature over the
68
+ * canonical descriptor hash must verify, and — for `merkle-membership-v1` — the
69
+ * commitment must prove under `corpusRoot`. Reserved proof policies are rejected.
70
+ */
71
+ export async function verifyContentDescriptor(d, opts) {
72
+ const now = opts.nowSeconds ?? Math.floor(Date.now() / 1000);
73
+ const statusOk = d.status === 'active';
74
+ const fromOk = !d.validFrom || Math.floor(new Date(d.validFrom).getTime() / 1000) <= now;
75
+ const untilOk = !d.validUntil || Math.floor(new Date(d.validUntil).getTime() / 1000) >= now;
76
+ const withinValidity = fromOk && untilOk;
77
+ const { signature, delegatingSigner, ...unsigned } = d;
78
+ const hash = descriptorHash(unsigned);
79
+ // Trust ALWAYS roots in the issuer SA. Either the issuer signed directly, or it authorized a delegate
80
+ // key (proven by the leaf) that signed — and even then the descriptor's issuer.address must equal the
81
+ // delegating issuer, so a delegate can never re-attribute a descriptor to a different issuer.
82
+ let signatureVerified;
83
+ let sigReason = 'issuer signature did not verify';
84
+ if (delegatingSigner) {
85
+ if (!opts.verifyDelegatedAuthority) {
86
+ signatureVerified = false;
87
+ sigReason = 'descriptor is delegate-signed but no delegated-authority verifier was provided';
88
+ }
89
+ else if (d.issuer.address.toLowerCase() !== delegatingSigner.delegatorIssuer.toLowerCase()) {
90
+ signatureVerified = false;
91
+ sigReason = 'delegatingSigner.delegatorIssuer ≠ descriptor issuer';
92
+ }
93
+ else {
94
+ const authOk = await opts.verifyDelegatedAuthority(delegatingSigner);
95
+ const sigOk = authOk && (await opts.verifySignature({ signer: delegatingSigner.delegateKey, hash, signature }));
96
+ signatureVerified = sigOk;
97
+ if (!authOk)
98
+ sigReason = 'issuer did not authorize the delegate signing key';
99
+ else if (!sigOk)
100
+ sigReason = 'delegate-key signature did not verify';
101
+ }
102
+ }
103
+ else {
104
+ signatureVerified = await opts.verifySignature({ signer: d.issuer.address, hash, signature });
105
+ }
106
+ const base = { ok: false, signatureVerified, statusOk, withinValidity };
107
+ if (!statusOk)
108
+ return { ...base, reason: `descriptor status is ${d.status}` };
109
+ if (!withinValidity)
110
+ return { ...base, reason: 'descriptor outside its validity window' };
111
+ if (!signatureVerified)
112
+ return { ...base, reason: sigReason };
113
+ switch (d.proofPolicy) {
114
+ case 'issuer-signature-v1':
115
+ case 'issuer-signature-and-hash-v1':
116
+ return { ...base, ok: true };
117
+ case 'merkle-membership-v1': {
118
+ if (!d.commitment || !opts.corpusRoot || !opts.inclusionProof) {
119
+ return { ...base, reason: 'merkle-membership-v1 requires commitment + corpusRoot + inclusionProof' };
120
+ }
121
+ const inclusionVerified = verifyInclusion(leafHash(d.commitment.value), opts.inclusionProof, opts.corpusRoot);
122
+ return { ...base, ok: inclusionVerified, inclusionVerified, reason: inclusionVerified ? undefined : 'commitment not included under corpusRoot' };
123
+ }
124
+ default:
125
+ return { ...base, reason: `proofPolicy ${d.proofPolicy} is reserved (spec 266 §6/§8)` };
126
+ }
127
+ }
128
+ //# sourceMappingURL=descriptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"descriptor.js","sourceRoot":"","sources":["../src/descriptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAY,MAAM,MAAM,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAC;AAE5E,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,oCAAoC,CAAC;AAErE,qEAAqE;AACrE,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AAC3D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO;QACL,IAAI,EAAE,yBAAyB;QAC/B,aAAa,EAAE,gBAAgB;QAC/B,SAAS,EAAE,SAAS;QACpB,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC;KACpD,CAAC;AACJ,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,UAA6B;IAC1E,IAAI,UAAU,CAAC,SAAS,KAAK,SAAS,IAAI,UAAU,CAAC,aAAa,KAAK,gBAAgB;QAAE,OAAO,KAAK,CAAC;IACtG,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,UAAU,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;AACxF,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,UAA6B;IAC1E,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,uBAAuB,CAAC,gDAAgD,CAAC,CAAC;IACtF,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,MAAM,qBAAqB,GAAG,4BAA4B,CAAC;AAE3D;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,CAAuB;IACpD,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1F,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,KAA2B,EAC3B,IAAuC,EACvC,gBAAmC;IAEnC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;IACpD,OAAO,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AACpF,CAAC;AAyBD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,CAAoB,EACpB,IAA0B;IAE1B,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC;IACvC,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,GAAG,CAAC;IACzF,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,GAAG,CAAC;IAC5F,MAAM,cAAc,GAAG,MAAM,IAAI,OAAO,CAAC;IAEzC,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,GAAG,QAAQ,EAAE,GAAG,CAAC,CAAC;IACvD,MAAM,IAAI,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IACtC,sGAAsG;IACtG,sGAAsG;IACtG,8FAA8F;IAC9F,IAAI,iBAA0B,CAAC;IAC/B,IAAI,SAAS,GAAG,iCAAiC,CAAC;IAClD,IAAI,gBAAgB,EAAE,CAAC;QACrB,IAAI,CAAC,IAAI,CAAC,wBAAwB,EAAE,CAAC;YACnC,iBAAiB,GAAG,KAAK,CAAC;YAAC,SAAS,GAAG,gFAAgF,CAAC;QAC1H,CAAC;aAAM,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,gBAAgB,CAAC,eAAe,CAAC,WAAW,EAAE,EAAE,CAAC;YAC7F,iBAAiB,GAAG,KAAK,CAAC;YAAC,SAAS,GAAG,sDAAsD,CAAC;QAChG,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,wBAAwB,CAAC,gBAAgB,CAAC,CAAC;YACrE,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,IAAI,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,gBAAgB,CAAC,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;YAChH,iBAAiB,GAAG,KAAK,CAAC;YAC1B,IAAI,CAAC,MAAM;gBAAE,SAAS,GAAG,mDAAmD,CAAC;iBACxE,IAAI,CAAC,KAAK;gBAAE,SAAS,GAAG,uCAAuC,CAAC;QACvE,CAAC;IACH,CAAC;SAAM,CAAC;QACN,iBAAiB,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IAChG,CAAC;IAED,MAAM,IAAI,GAAuB,EAAE,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC5F,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,wBAAwB,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;IAC9E,IAAI,CAAC,cAAc;QAAE,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,wCAAwC,EAAE,CAAC;IAC1F,IAAI,CAAC,iBAAiB;QAAE,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAE9D,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QACtB,KAAK,qBAAqB,CAAC;QAC3B,KAAK,8BAA8B;YACjC,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QAC/B,KAAK,sBAAsB,CAAC,CAAC,CAAC;YAC5B,IAAI,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;gBAC9D,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,wEAAwE,EAAE,CAAC;YACvG,CAAC;YACD,MAAM,iBAAiB,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YAC9G,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,0CAA0C,EAAE,CAAC;QACnJ,CAAC;QACD;YACE,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC,WAAW,+BAA+B,EAAE,CAAC;IAC5F,CAAC;AACH,CAAC"}
@@ -0,0 +1,64 @@
1
+ import type { UnsignedCredential } from '@agenticprimitives/verifiable-credentials';
2
+ import type { Address, Hex } from '@agenticprimitives/types';
3
+ import type { AccessPolicy, ContentCommitment, Entitlement } from './types.js';
4
+ export interface EntitlementDecision {
5
+ decision: 'allow' | 'deny';
6
+ reason?: string;
7
+ }
8
+ /**
9
+ * Gate retrieval against a corpus's access policy (spec 266 §3 step 5).
10
+ * Deterministic, fail-closed (spec 266 §7). An accessPolicy is a POLICY INPUT,
11
+ * not a legal grant (ADR-0033 R5): the platform still decides here.
12
+ * - `public` → allow.
13
+ * - `licensed`/`private` → require a presented {@link Entitlement} whose subject
14
+ * corpusRef matches and which has not expired.
15
+ * - unknown policy → deny.
16
+ *
17
+ * Cryptographic verification of the entitlement VC (issuer signature,
18
+ * revocation) is the caller's job via the `verifiable-credentials` verifier —
19
+ * pass an already-verified credential (ADR-0013: one mechanism, no fallback).
20
+ */
21
+ export declare function evaluateEntitlement(accessPolicy: AccessPolicy, corpusRef: Hex, entitlement?: Entitlement, nowSeconds?: number): EntitlementDecision;
22
+ export interface CitationInput {
23
+ /** Issuer of the citation (the resolving agent's SA, CAIP-10 or DID). */
24
+ issuer: string;
25
+ subjectId: string;
26
+ canonicalId: Hex;
27
+ descriptorId: string;
28
+ contentType: string;
29
+ citationKind: 'quote' | 'reference' | 'summary' | 'paraphrase';
30
+ commitment?: ContentCommitment;
31
+ commitmentVerified: boolean;
32
+ contentIssuer: Address;
33
+ validFrom: string;
34
+ /** Agentic provenance (which run/output produced the citation). */
35
+ agentRunId?: string;
36
+ outputId?: string;
37
+ /** Optional hash of the specific quoted span + the normalization spec used. */
38
+ quoteSpanHash?: Hex;
39
+ normalizationSpec?: string;
40
+ underEntitlement?: string;
41
+ }
42
+ /**
43
+ * Build an UNSIGNED citation credential — the AI-safe citation record. The
44
+ * caller signs it via `verifiable-credentials.signCredential` and emits it to
45
+ * the audit/provenance package (spec 266 §audit; do NOT invent a parallel audit
46
+ * model). Carries the commitment + verification result + agentic provenance,
47
+ * NEVER the rendering text (ADR-0033 R3).
48
+ */
49
+ export declare function buildCitationAssertion(input: CitationInput): UnsignedCredential<{
50
+ id: string;
51
+ agentRunId?: string;
52
+ outputId?: string;
53
+ citationKind: 'quote' | 'reference' | 'summary' | 'paraphrase';
54
+ canonicalId: Hex;
55
+ descriptorId: string;
56
+ contentType: string;
57
+ commitment?: ContentCommitment;
58
+ commitmentVerified: boolean;
59
+ quoteSpanHash?: Hex;
60
+ normalizationSpec?: string;
61
+ issuer: Address;
62
+ underEntitlement?: string;
63
+ }>;
64
+ //# sourceMappingURL=entitlement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entitlement.d.ts","sourceRoot":"","sources":["../src/entitlement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AACpF,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE/E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,YAAY,EAC1B,SAAS,EAAE,GAAG,EACd,WAAW,CAAC,EAAE,WAAW,EACzB,UAAU,GAAE,MAAsC,GACjD,mBAAmB,CAkBrB;AAED,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,GAAG,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,GAAG,WAAW,GAAG,SAAS,GAAG,YAAY,CAAC;IAC/D,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,aAAa,CAAC,EAAE,GAAG,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,aAAa,GAAG,kBAAkB,CAAC;IAC/E,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,OAAO,GAAG,WAAW,GAAG,SAAS,GAAG,YAAY,CAAC;IAC/D,WAAW,EAAE,GAAG,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,aAAa,CAAC,EAAE,GAAG,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC,CAsBD"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Gate retrieval against a corpus's access policy (spec 266 §3 step 5).
3
+ * Deterministic, fail-closed (spec 266 §7). An accessPolicy is a POLICY INPUT,
4
+ * not a legal grant (ADR-0033 R5): the platform still decides here.
5
+ * - `public` → allow.
6
+ * - `licensed`/`private` → require a presented {@link Entitlement} whose subject
7
+ * corpusRef matches and which has not expired.
8
+ * - unknown policy → deny.
9
+ *
10
+ * Cryptographic verification of the entitlement VC (issuer signature,
11
+ * revocation) is the caller's job via the `verifiable-credentials` verifier —
12
+ * pass an already-verified credential (ADR-0013: one mechanism, no fallback).
13
+ */
14
+ export function evaluateEntitlement(accessPolicy, corpusRef, entitlement, nowSeconds = Math.floor(Date.now() / 1000)) {
15
+ if (accessPolicy === 'public')
16
+ return { decision: 'allow' };
17
+ if (accessPolicy !== 'licensed' && accessPolicy !== 'private') {
18
+ return { decision: 'deny', reason: `unknown accessPolicy: ${String(accessPolicy)}` };
19
+ }
20
+ if (!entitlement) {
21
+ return { decision: 'deny', reason: `${accessPolicy} corpus requires an entitlement` };
22
+ }
23
+ if (entitlement.credentialSubject.corpusRef.toLowerCase() !== corpusRef.toLowerCase()) {
24
+ return { decision: 'deny', reason: 'entitlement is for a different corpus' };
25
+ }
26
+ if (entitlement.validUntil) {
27
+ const exp = Math.floor(new Date(entitlement.validUntil).getTime() / 1000);
28
+ if (Number.isFinite(exp) && exp < nowSeconds) {
29
+ return { decision: 'deny', reason: 'entitlement expired' };
30
+ }
31
+ }
32
+ return { decision: 'allow' };
33
+ }
34
+ /**
35
+ * Build an UNSIGNED citation credential — the AI-safe citation record. The
36
+ * caller signs it via `verifiable-credentials.signCredential` and emits it to
37
+ * the audit/provenance package (spec 266 §audit; do NOT invent a parallel audit
38
+ * model). Carries the commitment + verification result + agentic provenance,
39
+ * NEVER the rendering text (ADR-0033 R3).
40
+ */
41
+ export function buildCitationAssertion(input) {
42
+ return {
43
+ '@context': ['https://www.w3.org/ns/credentials/v2'],
44
+ type: ['VerifiableCredential', 'CitationAssertion'],
45
+ issuer: input.issuer,
46
+ validFrom: input.validFrom,
47
+ credentialSubject: {
48
+ id: input.subjectId,
49
+ ...(input.agentRunId ? { agentRunId: input.agentRunId } : {}),
50
+ ...(input.outputId ? { outputId: input.outputId } : {}),
51
+ citationKind: input.citationKind,
52
+ canonicalId: input.canonicalId,
53
+ descriptorId: input.descriptorId,
54
+ contentType: input.contentType,
55
+ ...(input.commitment ? { commitment: input.commitment } : {}),
56
+ commitmentVerified: input.commitmentVerified,
57
+ ...(input.quoteSpanHash ? { quoteSpanHash: input.quoteSpanHash } : {}),
58
+ ...(input.normalizationSpec ? { normalizationSpec: input.normalizationSpec } : {}),
59
+ issuer: input.contentIssuer,
60
+ ...(input.underEntitlement ? { underEntitlement: input.underEntitlement } : {}),
61
+ },
62
+ };
63
+ }
64
+ //# sourceMappingURL=entitlement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entitlement.js","sourceRoot":"","sources":["../src/entitlement.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,mBAAmB,CACjC,YAA0B,EAC1B,SAAc,EACd,WAAyB,EACzB,aAAqB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IAElD,IAAI,YAAY,KAAK,QAAQ;QAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAC5D,IAAI,YAAY,KAAK,UAAU,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,yBAAyB,MAAM,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC;IACvF,CAAC;IACD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,YAAY,iCAAiC,EAAE,CAAC;IACxF,CAAC;IACD,IAAI,WAAW,CAAC,iBAAiB,CAAC,SAAS,CAAC,WAAW,EAAE,KAAK,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC;QACtF,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,uCAAuC,EAAE,CAAC;IAC/E,CAAC;IACD,IAAI,WAAW,CAAC,UAAU,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;QAC1E,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,UAAU,EAAE,CAAC;YAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC;QAC7D,CAAC;IACH,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAC/B,CAAC;AAuBD;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAoB;IAezD,OAAO;QACL,UAAU,EAAE,CAAC,sCAAsC,CAAC;QACpD,IAAI,EAAE,CAAC,sBAAsB,EAAE,mBAAmB,CAAC;QACnD,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,iBAAiB,EAAE;YACjB,EAAE,EAAE,KAAK,CAAC,SAAS;YACnB,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;YAC5C,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtE,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClF,MAAM,EAAE,KAAK,CAAC,aAAa;YAC3B,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,KAAK,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAChF;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ /** A reference path failed its scheme's normalization. */
2
+ export declare class InvalidReferenceError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ /** A rendering's keccak commitment did not match its descriptor. */
6
+ export declare class CommitmentMismatchError extends Error {
7
+ constructor(message: string);
8
+ }
9
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED,oEAAoE;AACpE,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,EAAE,MAAM;CAI5B"}
package/dist/errors.js ADDED
@@ -0,0 +1,15 @@
1
+ /** A reference path failed its scheme's normalization. */
2
+ export class InvalidReferenceError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = 'InvalidReferenceError';
6
+ }
7
+ }
8
+ /** A rendering's keccak commitment did not match its descriptor. */
9
+ export class CommitmentMismatchError extends Error {
10
+ constructor(message) {
11
+ super(message);
12
+ this.name = 'CommitmentMismatchError';
13
+ }
14
+ }
15
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC9C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAED,oEAAoE;AACpE,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAChD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ export declare const PACKAGE_NAME = "@agenticprimitives/content-primitives";
2
+ export declare const PACKAGE_STATUS: "phase-1";
3
+ export declare const SPEC_REF = "specs/266-verifiable-content-substrate.md";
4
+ export type { AccessPolicy, ProofPolicy, DescriptorStatus, RightsStatus, TrustProfile, CanonicalLocus, CanonicalLocusEnvelope, CanonicalReference, ContentCommitment, CorpusManifest, WorkMeta, IssuerIdentityRef, ContentDescriptor, BuildDescriptorInput, SignatureVerifier, DelegatingSigner, DelegatedAuthorityVerifier, Entitlement, CitationAssertion, } from './types.js';
5
+ export { computeCanonicalId, canonicalReference, corpusRef, LOCUS_ID_SCHEME } from './reference.js';
6
+ export { jcsCanonicalize, canonicalHash } from '@agenticprimitives/verifiable-credentials';
7
+ export { hashPair, leafHash, buildCorpusTree, merkleRoot, merkleProof, verifyInclusion, type CorpusTree, } from './merkle.js';
8
+ export { NORMALIZATION_V1, canonicalizeRendering, contentCommitment, verifyCommitment, assertCommitment, descriptorHash, buildContentDescriptor, verifyContentDescriptor, type VerifyDescriptorOpts, type VerificationResult, } from './descriptor.js';
9
+ export { resolveCandidates, type ResolutionConstraints, type Candidate, type ResolutionResult, type TrustProfileConfig, } from './resolution.js';
10
+ export { evaluateEntitlement, buildCitationAssertion, type EntitlementDecision, type CitationInput, } from './entitlement.js';
11
+ export { InvalidReferenceError, CommitmentMismatchError } from './errors.js';
12
+ export { buildInclusionZkProof, bindPaymentMandate } from './reserved.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,YAAY,0CAA0C,CAAC;AACpE,eAAO,MAAM,cAAc,EAAG,SAAkB,CAAC;AACjD,eAAO,MAAM,QAAQ,8CAA8C,CAAC;AAEpE,YAAY,EACV,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,QAAQ,EACR,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,0BAA0B,EAC1B,WAAW,EACX,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGpG,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAE3F,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,UAAU,EACV,WAAW,EACX,eAAe,EACf,KAAK,UAAU,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EACvB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,GACxB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,iBAAiB,EACjB,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,GACxB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,KAAK,mBAAmB,EACxB,KAAK,aAAa,GACnB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAG7E,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ // @agenticprimitives/content-primitives — the Verifiable Content Substrate SDK.
2
+ //
3
+ // Name → resolve → verify → retrieve → cite → audit, for content that lives
4
+ // off-platform and is controlled by third-party rights holders. Content-
5
+ // agnostic (ADR-0033): a verse is content, not an Agent; a canonical locus is a
6
+ // deterministic hash of a scheme-INDEPENDENT structured form (registry-free, no
7
+ // allocator), never a Smart Agent facet. No vertical/faith vocabulary, no
8
+ // rendering text — descriptors carry a retrievalPointer + a SHA-256 commitment.
9
+ //
10
+ // See: ../../specs/266-verifiable-content-substrate.md
11
+ // ../../docs/architecture/decisions/0033-content-agnostic-verifiable-content-firewall.md
12
+ export const PACKAGE_NAME = '@agenticprimitives/content-primitives';
13
+ export const PACKAGE_STATUS = 'phase-1';
14
+ export const SPEC_REF = 'specs/266-verifiable-content-substrate.md';
15
+ export { computeCanonicalId, canonicalReference, corpusRef, LOCUS_ID_SCHEME } from './reference.js';
16
+ // Re-export the ONE canonicalization stack (RFC 8785) — shared with credential
17
+ // hashing so descriptor/locus ids and VC hashes never drift.
18
+ export { jcsCanonicalize, canonicalHash } from '@agenticprimitives/verifiable-credentials';
19
+ export { hashPair, leafHash, buildCorpusTree, merkleRoot, merkleProof, verifyInclusion, } from './merkle.js';
20
+ export { NORMALIZATION_V1, canonicalizeRendering, contentCommitment, verifyCommitment, assertCommitment, descriptorHash, buildContentDescriptor, verifyContentDescriptor, } from './descriptor.js';
21
+ export { resolveCandidates, } from './resolution.js';
22
+ export { evaluateEntitlement, buildCitationAssertion, } from './entitlement.js';
23
+ export { InvalidReferenceError, CommitmentMismatchError } from './errors.js';
24
+ // Reserved for later phases (throw until implemented; spec 266 §6).
25
+ export { buildInclusionZkProof, bindPaymentMandate } from './reserved.js';
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,EAAE;AACF,4EAA4E;AAC5E,yEAAyE;AACzE,gFAAgF;AAChF,gFAAgF;AAChF,0EAA0E;AAC1E,gFAAgF;AAChF,EAAE;AACF,uDAAuD;AACvD,8FAA8F;AAE9F,MAAM,CAAC,MAAM,YAAY,GAAG,uCAAuC,CAAC;AACpE,MAAM,CAAC,MAAM,cAAc,GAAG,SAAkB,CAAC;AACjD,MAAM,CAAC,MAAM,QAAQ,GAAG,2CAA2C,CAAC;AAwBpE,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACpG,+EAA+E;AAC/E,6DAA6D;AAC7D,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAE3F,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,UAAU,EACV,WAAW,EACX,eAAe,GAEhB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,sBAAsB,EACtB,uBAAuB,GAGxB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,iBAAiB,GAKlB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,mBAAmB,EACnB,sBAAsB,GAGvB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE7E,oEAAoE;AACpE,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC"}
package/dist/jcs.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export declare function canonicalize(value: unknown): unknown;
2
+ /** Canonical JSON string of `value` (sorted keys, undefined omitted). */
3
+ export declare function jcsString(value: unknown): string;
4
+ //# sourceMappingURL=jcs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jcs.d.ts","sourceRoot":"","sources":["../src/jcs.ts"],"names":[],"mappings":"AAMA,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAYpD;AAED,yEAAyE;AACzE,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEhD"}
package/dist/jcs.js ADDED
@@ -0,0 +1,25 @@
1
+ // Deterministic, sorted-key canonical JSON (JCS-style). Sufficient for our
2
+ // records (string/hex/number/bool fields); not a full RFC 8785 number
3
+ // normalizer — keep numeric fields integer-valued. Used for both the canonical
4
+ // locus id and the descriptor signing digest so hashing is stable regardless of
5
+ // key insertion order.
6
+ export function canonicalize(value) {
7
+ if (Array.isArray(value))
8
+ return value.map(canonicalize);
9
+ if (value && typeof value === 'object') {
10
+ const out = {};
11
+ for (const k of Object.keys(value).sort()) {
12
+ const v = value[k];
13
+ if (v === undefined)
14
+ continue; // omit undefined so optional fields don't shift the hash
15
+ out[k] = canonicalize(v);
16
+ }
17
+ return out;
18
+ }
19
+ return value;
20
+ }
21
+ /** Canonical JSON string of `value` (sorted keys, undefined omitted). */
22
+ export function jcsString(value) {
23
+ return JSON.stringify(canonicalize(value));
24
+ }
25
+ //# sourceMappingURL=jcs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jcs.js","sourceRoot":"","sources":["../src/jcs.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,sEAAsE;AACtE,+EAA+E;AAC/E,gFAAgF;AAChF,uBAAuB;AAEvB,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACzD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,GAAG,GAA4B,EAAE,CAAC;QACxC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,KAAgC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACrE,MAAM,CAAC,GAAI,KAAiC,CAAC,CAAC,CAAC,CAAC;YAChD,IAAI,CAAC,KAAK,SAAS;gBAAE,SAAS,CAAC,yDAAyD;YACxF,GAAG,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;AAC7C,CAAC"}