@agenticprimitives/content-primitives 1.0.0-alpha.6

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 +49 -0
  4. package/dist/descriptor.d.ts +62 -0
  5. package/dist/descriptor.d.ts.map +1 -0
  6. package/dist/descriptor.js +100 -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 +172 -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,49 @@
1
+ # @agenticprimitives/content-primitives
2
+
3
+ Verifiable Content Substrate — name, resolve, commit, entitlement-gate, and cite
4
+ content that lives off-platform and is controlled by third-party rights holders.
5
+
6
+ It is **content-agnostic** ([ADR-0033](../../docs/architecture/decisions/0033-content-agnostic-verifiable-content-firewall.md)):
7
+ a referenced unit of content (e.g. a Bible verse) is **not** a Smart Agent, and
8
+ this package never embeds a translation, a faith term, or any rendering text.
9
+ Bible verses are its first usage domain ([spec 267](../../specs/267-scripture-demo-vertical.md)),
10
+ not its vocabulary.
11
+
12
+ ## Model (FRBR)
13
+
14
+ | FRBR | Type | Notes |
15
+ | --- | --- | --- |
16
+ | Work | `CanonicalLocus` | scheme-anchored deterministic `locusId`; never registered |
17
+ | Manifestation | `CorpusManifest` | issuer-owned, Merkle `corpusRoot`, signed |
18
+ | Item | `ContentDescriptor` | commitment + `retrievalPointer` + issuer signature — **never text** |
19
+ | — | `Entitlement` / `CitationAssertion` | W3C VC 2.0 subjects |
20
+
21
+ ## Quick start
22
+
23
+ ```ts
24
+ import {
25
+ buildCanonicalLocus, corpusRef, contentCommitment,
26
+ buildContentDescriptor, verifyContentDescriptor,
27
+ evaluateEntitlement, buildCitationAssertion,
28
+ } from '@agenticprimitives/content-primitives';
29
+
30
+ // 1. App supplies the reference grammar (kept out of the package — R4).
31
+ const bibleVerse = { id: 'bible-verse', normalize: (p: string) => /* OSIS */ p };
32
+ const locus = buildCanonicalLocus(bibleVerse, 'John 3:16'); // -> { locusId, path: 'John.3.16' }
33
+
34
+ // 2. Issuer commits to off-platform text + signs a descriptor (no text on-chain — R3).
35
+ const commitment = contentCommitment(renderingText); // keccak256, off-platform
36
+ const descriptor = await buildContentDescriptor(
37
+ { locusId: locus.locusId, corpusRef: ref, contentType: 'bible-verse',
38
+ commitment, proofPolicy: 'signature', accessPolicy: 'public',
39
+ retrievalPointer: 'content://bible-verse/bsb/John.3.16', issuer },
40
+ issuerSign, // signs descriptorHash via the issuer SA (ERC-1271)
41
+ );
42
+
43
+ // 3. Reader verifies (signature injected — ADR-0006) + gates + cites.
44
+ const ok = await verifyContentDescriptor(descriptor, { verifySignature });
45
+ const gate = evaluateEntitlement(descriptor.accessPolicy, descriptor.corpusRef);
46
+ ```
47
+
48
+ Full SDK + phased roadmap: [spec 266](../../specs/266-verifiable-content-substrate.md).
49
+ ZK proofs and paid access are reserved (Phase 4/5) and throw until implemented.
@@ -0,0 +1,62 @@
1
+ import { type Hex } from 'viem';
2
+ import type { BuildDescriptorInput, ContentCommitment, ContentDescriptor, 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` is the issuer's signer over
34
+ * {@link descriptorHash} (its Smart Agent's ERC-1271 path).
35
+ */
36
+ export declare function buildContentDescriptor(input: BuildDescriptorInput, sign: (hash: Hex) => Promise<Hex> | Hex): Promise<ContentDescriptor>;
37
+ export interface VerifyDescriptorOpts {
38
+ /** Verifies the issuer's ERC-1271 signature (injected; ADR-0006). */
39
+ verifySignature: SignatureVerifier;
40
+ /** Required when proofPolicy is `merkle-membership-v1`. */
41
+ corpusRoot?: Hex;
42
+ inclusionProof?: Hex[];
43
+ /** Current time (seconds) for validity/status checks; defaults to now. */
44
+ nowSeconds?: number;
45
+ }
46
+ /** Result of {@link verifyContentDescriptor} — an auditable VerificationResult. */
47
+ export interface VerificationResult {
48
+ ok: boolean;
49
+ reason?: string;
50
+ signatureVerified: boolean;
51
+ statusOk: boolean;
52
+ withinValidity: boolean;
53
+ inclusionVerified?: boolean;
54
+ }
55
+ /**
56
+ * Verify a descriptor fail-closed (spec 266 §7): status must be `active`, the
57
+ * validity window must contain `now`, the issuer ERC-1271 signature over the
58
+ * canonical descriptor hash must verify, and — for `merkle-membership-v1` — the
59
+ * commitment must prove under `corpusRoot`. Reserved proof policies are rejected.
60
+ */
61
+ export declare function verifyContentDescriptor(d: ContentDescriptor, opts: VerifyDescriptorOpts): Promise<VerificationResult>;
62
+ //# 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,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAIhH;;;;;;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;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,oBAAoB,EAC3B,IAAI,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,GACtC,OAAO,CAAC,iBAAiB,CAAC,CAG5B;AAED,MAAM,WAAW,oBAAoB;IACnC,qEAAqE;IACrE,eAAe,EAAE,iBAAiB,CAAC;IACnC,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,CA8B7B"}
@@ -0,0 +1,100 @@
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` is the issuer's signer over
57
+ * {@link descriptorHash} (its Smart Agent's ERC-1271 path).
58
+ */
59
+ export async function buildContentDescriptor(input, sign) {
60
+ const signature = await sign(descriptorHash(input));
61
+ return { ...input, signature };
62
+ }
63
+ /**
64
+ * Verify a descriptor fail-closed (spec 266 §7): status must be `active`, the
65
+ * validity window must contain `now`, the issuer ERC-1271 signature over the
66
+ * canonical descriptor hash must verify, and — for `merkle-membership-v1` — the
67
+ * commitment must prove under `corpusRoot`. Reserved proof policies are rejected.
68
+ */
69
+ export async function verifyContentDescriptor(d, opts) {
70
+ const now = opts.nowSeconds ?? Math.floor(Date.now() / 1000);
71
+ const statusOk = d.status === 'active';
72
+ const fromOk = !d.validFrom || Math.floor(new Date(d.validFrom).getTime() / 1000) <= now;
73
+ const untilOk = !d.validUntil || Math.floor(new Date(d.validUntil).getTime() / 1000) >= now;
74
+ const withinValidity = fromOk && untilOk;
75
+ const { signature, ...unsigned } = d;
76
+ const hash = descriptorHash(unsigned);
77
+ const signatureVerified = await opts.verifySignature({ signer: d.issuer.address, hash, signature });
78
+ const base = { ok: false, signatureVerified, statusOk, withinValidity };
79
+ if (!statusOk)
80
+ return { ...base, reason: `descriptor status is ${d.status}` };
81
+ if (!withinValidity)
82
+ return { ...base, reason: 'descriptor outside its validity window' };
83
+ if (!signatureVerified)
84
+ return { ...base, reason: 'issuer signature did not verify' };
85
+ switch (d.proofPolicy) {
86
+ case 'issuer-signature-v1':
87
+ case 'issuer-signature-and-hash-v1':
88
+ return { ...base, ok: true };
89
+ case 'merkle-membership-v1': {
90
+ if (!d.commitment || !opts.corpusRoot || !opts.inclusionProof) {
91
+ return { ...base, reason: 'merkle-membership-v1 requires commitment + corpusRoot + inclusionProof' };
92
+ }
93
+ const inclusionVerified = verifyInclusion(leafHash(d.commitment.value), opts.inclusionProof, opts.corpusRoot);
94
+ return { ...base, ok: inclusionVerified, inclusionVerified, reason: inclusionVerified ? undefined : 'commitment not included under corpusRoot' };
95
+ }
96
+ default:
97
+ return { ...base, reason: `proofPolicy ${d.proofPolicy} is reserved (spec 266 §6/§8)` };
98
+ }
99
+ }
100
+ //# 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;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,KAA2B,EAC3B,IAAuC;IAEvC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;IACpD,OAAO,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,CAAC;AACjC,CAAC;AAsBD;;;;;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,GAAG,QAAQ,EAAE,GAAG,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,iBAAiB,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IAEpG,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,iCAAiC,EAAE,CAAC;IAEtF,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":"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"}
@@ -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, 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,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;AAsBpE,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"}
@@ -0,0 +1,29 @@
1
+ import { type Hex } from 'viem';
2
+ /** Hash an ordered pair after sorting: keccak256(min || max). */
3
+ export declare function hashPair(a: Hex, b: Hex): Hex;
4
+ /**
5
+ * Leaf hash for a descriptor commitment. Double-hash (`keccak256(keccak256(c))`)
6
+ * to domain-separate leaves from internal nodes (second-preimage resistance).
7
+ */
8
+ export declare function leafHash(descriptorCommitment: Hex): Hex;
9
+ export interface CorpusTree {
10
+ root: Hex;
11
+ /** layers[0] = leaves, layers[n] = [root]. */
12
+ layers: Hex[][];
13
+ }
14
+ /**
15
+ * Build a Merkle tree over already-hashed leaves (see {@link leafHash}). An odd
16
+ * node at any level is promoted unchanged to the next level. Empty input yields
17
+ * the zero root.
18
+ */
19
+ export declare function buildCorpusTree(leaves: Hex[]): CorpusTree;
20
+ /** Convenience: root of a fresh tree over `leaves`. */
21
+ export declare function merkleRoot(leaves: Hex[]): Hex;
22
+ /**
23
+ * Inclusion proof (sibling path) for the leaf at `index`. Promoted (odd) nodes
24
+ * contribute no sibling at that level — matching {@link buildCorpusTree}.
25
+ */
26
+ export declare function merkleProof(tree: CorpusTree, index: number): Hex[];
27
+ /** Fold a leaf with its proof and compare against the root. */
28
+ export declare function verifyInclusion(leaf: Hex, proof: Hex[], root: Hex): boolean;
29
+ //# sourceMappingURL=merkle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merkle.d.ts","sourceRoot":"","sources":["../src/merkle.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AAa5D,iEAAiE;AACjE,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,GAAG,CAG5C;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,oBAAoB,EAAE,GAAG,GAAG,GAAG,CAEvD;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,GAAG,CAAC;IACV,8CAA8C;IAC9C,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,UAAU,CAezD;AAED,uDAAuD;AACvD,wBAAgB,UAAU,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,CAE7C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE,CAWlE;AAED,+DAA+D;AAC/D,wBAAgB,eAAe,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAI3E"}
package/dist/merkle.js ADDED
@@ -0,0 +1,74 @@
1
+ import { keccak256, concat, toBytes } from 'viem';
2
+ // Generic Merkle commitment over a corpus of descriptor commitments (spec 266
3
+ // §4). Net-new to the monorepo (the repo previously had only flat keccak
4
+ // commitments in `agreements`). Sorted-pair hashing (OpenZeppelin-compatible)
5
+ // so inclusion proofs are sibling-order-independent and verifiable on-chain in
6
+ // a future ContentCorpusRegistry (spec 266 Phase 3).
7
+ /** Order two hashes ascending (sorted-pair convention). */
8
+ function sortPair(a, b) {
9
+ return a.toLowerCase() <= b.toLowerCase() ? [a, b] : [b, a];
10
+ }
11
+ /** Hash an ordered pair after sorting: keccak256(min || max). */
12
+ export function hashPair(a, b) {
13
+ const [lo, hi] = sortPair(a, b);
14
+ return keccak256(concat([lo, hi]));
15
+ }
16
+ /**
17
+ * Leaf hash for a descriptor commitment. Double-hash (`keccak256(keccak256(c))`)
18
+ * to domain-separate leaves from internal nodes (second-preimage resistance).
19
+ */
20
+ export function leafHash(descriptorCommitment) {
21
+ return keccak256(toBytes(keccak256(toBytes(descriptorCommitment))));
22
+ }
23
+ /**
24
+ * Build a Merkle tree over already-hashed leaves (see {@link leafHash}). An odd
25
+ * node at any level is promoted unchanged to the next level. Empty input yields
26
+ * the zero root.
27
+ */
28
+ export function buildCorpusTree(leaves) {
29
+ if (leaves.length === 0) {
30
+ return { root: ('0x' + '0'.repeat(64)), layers: [[]] };
31
+ }
32
+ const layers = [leaves.slice()];
33
+ while (layers[layers.length - 1].length > 1) {
34
+ const prev = layers[layers.length - 1];
35
+ const next = [];
36
+ for (let i = 0; i < prev.length; i += 2) {
37
+ if (i + 1 === prev.length)
38
+ next.push(prev[i]);
39
+ else
40
+ next.push(hashPair(prev[i], prev[i + 1]));
41
+ }
42
+ layers.push(next);
43
+ }
44
+ return { root: layers[layers.length - 1][0], layers };
45
+ }
46
+ /** Convenience: root of a fresh tree over `leaves`. */
47
+ export function merkleRoot(leaves) {
48
+ return buildCorpusTree(leaves).root;
49
+ }
50
+ /**
51
+ * Inclusion proof (sibling path) for the leaf at `index`. Promoted (odd) nodes
52
+ * contribute no sibling at that level — matching {@link buildCorpusTree}.
53
+ */
54
+ export function merkleProof(tree, index) {
55
+ const proof = [];
56
+ let idx = index;
57
+ for (let level = 0; level < tree.layers.length - 1; level++) {
58
+ const nodes = tree.layers[level];
59
+ const isRight = idx % 2 === 1;
60
+ const siblingIdx = isRight ? idx - 1 : idx + 1;
61
+ if (siblingIdx < nodes.length)
62
+ proof.push(nodes[siblingIdx]);
63
+ idx = Math.floor(idx / 2);
64
+ }
65
+ return proof;
66
+ }
67
+ /** Fold a leaf with its proof and compare against the root. */
68
+ export function verifyInclusion(leaf, proof, root) {
69
+ let computed = leaf;
70
+ for (const sibling of proof)
71
+ computed = hashPair(computed, sibling);
72
+ return computed.toLowerCase() === root.toLowerCase();
73
+ }
74
+ //# sourceMappingURL=merkle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merkle.js","sourceRoot":"","sources":["../src/merkle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { type Hex } from 'viem';
2
+ import type { Address } from '@agenticprimitives/types';
3
+ import type { CanonicalLocusEnvelope, CanonicalReference } from './types.js';
4
+ /** The single canonical-locus id construction (pick-one; spec 266 §2.1). */
5
+ export declare const LOCUS_ID_SCHEME: "ap-locus-id-v1";
6
+ /**
7
+ * Deterministic, scheme-independent canonical-locus id (spec 266 §2.1):
8
+ * `keccak256(utf8(DOMAIN_SEP) || utf8(JCS(envelope)))`.
9
+ *
10
+ * The CORE treats `envelope.canonicalLocus` as opaque controlled-token bytes;
11
+ * the vertical extension owns its meaning + validates it before this call.
12
+ * Because the id hashes a *normalized structured envelope* (not a surface
13
+ * string) under an explicit `locusProfile`, all surface grammars that denote the
14
+ * same locus collide to the same id, and only a deliberate profile/versification
15
+ * change moves it. Registry-free + reproducible — no allocator, no Smart Agent
16
+ * (ADR-0033). keccak keeps it EVM-anchorable for the Phase-3 registry. JCS does
17
+ * NOT Unicode-normalize strings, so callers MUST pass controlled tokens only.
18
+ */
19
+ export declare function computeCanonicalId(envelope: CanonicalLocusEnvelope): Hex;
20
+ /** Build a {@link CanonicalReference} from an envelope (+ optional human alias). */
21
+ export declare function canonicalReference(envelope: CanonicalLocusEnvelope, alias?: string): CanonicalReference;
22
+ /**
23
+ * Deterministic corpus reference (spec 266 §2.2).
24
+ * `corpusRef = keccak256(utf8(`${issuer}/${edition}/${version}`))`. Issuer
25
+ * address is lowercased so the id is independent of checksum casing.
26
+ */
27
+ export declare function corpusRef(issuer: Address, edition: string, version: string): Hex;
28
+ //# sourceMappingURL=reference.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reference.d.ts","sourceRoot":"","sources":["../src/reference.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAExD,OAAO,KAAK,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAE7E,4EAA4E;AAC5E,eAAO,MAAM,eAAe,EAAG,gBAAyB,CAAC;AAKzD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,GAAG,CAExE;AAED,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,sBAAsB,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAEvG;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,GAAG,CAEhF"}
@@ -0,0 +1,35 @@
1
+ import { keccak256, concat, toBytes } from 'viem';
2
+ import { jcsCanonicalize } from '@agenticprimitives/verifiable-credentials';
3
+ /** The single canonical-locus id construction (pick-one; spec 266 §2.1). */
4
+ export const LOCUS_ID_SCHEME = 'ap-locus-id-v1';
5
+ /** Domain separator — prevents cross-primitive / cross-version hash collisions. */
6
+ const LOCUS_ID_DOMAIN_SEP = 'ap:canonical-locus-id:v1\0';
7
+ /**
8
+ * Deterministic, scheme-independent canonical-locus id (spec 266 §2.1):
9
+ * `keccak256(utf8(DOMAIN_SEP) || utf8(JCS(envelope)))`.
10
+ *
11
+ * The CORE treats `envelope.canonicalLocus` as opaque controlled-token bytes;
12
+ * the vertical extension owns its meaning + validates it before this call.
13
+ * Because the id hashes a *normalized structured envelope* (not a surface
14
+ * string) under an explicit `locusProfile`, all surface grammars that denote the
15
+ * same locus collide to the same id, and only a deliberate profile/versification
16
+ * change moves it. Registry-free + reproducible — no allocator, no Smart Agent
17
+ * (ADR-0033). keccak keeps it EVM-anchorable for the Phase-3 registry. JCS does
18
+ * NOT Unicode-normalize strings, so callers MUST pass controlled tokens only.
19
+ */
20
+ export function computeCanonicalId(envelope) {
21
+ return keccak256(concat([toBytes(LOCUS_ID_DOMAIN_SEP), toBytes(jcsCanonicalize(envelope))]));
22
+ }
23
+ /** Build a {@link CanonicalReference} from an envelope (+ optional human alias). */
24
+ export function canonicalReference(envelope, alias) {
25
+ return { id: computeCanonicalId(envelope), envelope, ...(alias ? { alias } : {}) };
26
+ }
27
+ /**
28
+ * Deterministic corpus reference (spec 266 §2.2).
29
+ * `corpusRef = keccak256(utf8(`${issuer}/${edition}/${version}`))`. Issuer
30
+ * address is lowercased so the id is independent of checksum casing.
31
+ */
32
+ export function corpusRef(issuer, edition, version) {
33
+ return keccak256(toBytes(`${issuer.toLowerCase()}/${edition}/${version}`));
34
+ }
35
+ //# sourceMappingURL=reference.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reference.js","sourceRoot":"","sources":["../src/reference.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAY,MAAM,MAAM,CAAC;AAE5D,OAAO,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAC;AAG5E,4EAA4E;AAC5E,MAAM,CAAC,MAAM,eAAe,GAAG,gBAAyB,CAAC;AAEzD,mFAAmF;AACnF,MAAM,mBAAmB,GAAG,4BAA4B,CAAC;AAEzD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgC;IACjE,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/F,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,kBAAkB,CAAC,QAAgC,EAAE,KAAc;IACjF,OAAO,EAAE,EAAE,EAAE,kBAAkB,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AACrF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,MAAe,EAAE,OAAe,EAAE,OAAe;IACzE,OAAO,SAAS,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,WAAW,EAAE,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC;AAC7E,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Zero-knowledge inclusion / "AI-cited-correctly" proof (spec 266 Phase 4).
3
+ * Reserved — proves a commitment is in a corpus (or that a citation is
4
+ * faithful) without revealing the rendering.
5
+ */
6
+ export declare function buildInclusionZkProof(): Promise<never>;
7
+ /**
8
+ * Bind a payment mandate to entitlement issuance for paid access (spec 266
9
+ * Phase 5). Reserved.
10
+ */
11
+ export declare function bindPaymentMandate(): never;
12
+ //# sourceMappingURL=reserved.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reserved.d.ts","sourceRoot":"","sources":["../src/reserved.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,KAAK,CAAC,CAE5D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,KAAK,CAE1C"}
@@ -0,0 +1,19 @@
1
+ // Reserved API surface for later phases (spec 266 §6). These lock the shape so
2
+ // apps can be written against them, and throw until implemented — mirroring the
3
+ // agent-naming Phase-1 skeleton discipline. NO silent no-ops (ADR-0013).
4
+ /**
5
+ * Zero-knowledge inclusion / "AI-cited-correctly" proof (spec 266 Phase 4).
6
+ * Reserved — proves a commitment is in a corpus (or that a citation is
7
+ * faithful) without revealing the rendering.
8
+ */
9
+ export async function buildInclusionZkProof() {
10
+ throw new Error('verifiable-content: ZK proofs are reserved (spec 266 Phase 4)');
11
+ }
12
+ /**
13
+ * Bind a payment mandate to entitlement issuance for paid access (spec 266
14
+ * Phase 5). Reserved.
15
+ */
16
+ export function bindPaymentMandate() {
17
+ throw new Error('verifiable-content: paid access is reserved (spec 266 Phase 5)');
18
+ }
19
+ //# sourceMappingURL=reserved.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reserved.js","sourceRoot":"","sources":["../src/reserved.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,gFAAgF;AAChF,yEAAyE;AAEzE;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;AACnF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;AACpF,CAAC"}
@@ -0,0 +1,41 @@
1
+ import type { Address } from '@agenticprimitives/types';
2
+ import type { ContentDescriptor, CanonicalReference, RightsStatus, TrustProfile } from './types.js';
3
+ export interface ResolutionConstraints {
4
+ contentType?: string;
5
+ language?: string;
6
+ /** Acceptable rights postures (e.g. ['public-domain']). */
7
+ rightsStatus?: RightsStatus[];
8
+ trustProfile?: TrustProfile;
9
+ }
10
+ /** A descriptor plus the profile/constraint screening outcome (pre-verification). */
11
+ export interface Candidate {
12
+ descriptor: ContentDescriptor;
13
+ /** True iff the descriptor's issuer is in the active trust profile's allowlist. */
14
+ issuerTrusted: boolean;
15
+ /** True iff the descriptor passed all constraint filters. */
16
+ admitted: boolean;
17
+ /** Why a candidate was screened out (when !admitted). */
18
+ reason?: string;
19
+ }
20
+ export interface ResolutionResult {
21
+ canonicalReference: CanonicalReference;
22
+ candidates: Candidate[];
23
+ }
24
+ /** A trust profile = an issuer allowlist + posture flags. Phase 1 wires
25
+ * `public-domain-demo` only; the rest are reserved shapes (spec 266 §policy). */
26
+ export interface TrustProfileConfig {
27
+ profile: TrustProfile;
28
+ /** Issuer Smart Agent addresses trusted under this profile. Empty = trust none. */
29
+ trustedIssuers: Address[];
30
+ /** If set, only these rights postures are admitted. */
31
+ allowedRightsStatus?: RightsStatus[];
32
+ /** If true, an untrusted issuer is screened out (admitted=false). */
33
+ requireTrustedIssuer: boolean;
34
+ }
35
+ /**
36
+ * Screen descriptors for a canonical reference into a candidate set under a
37
+ * trust profile + constraints. Pure + deterministic. Does NOT verify signatures
38
+ * (that is the caller's per-candidate step) — it screens *eligibility*.
39
+ */
40
+ export declare function resolveCandidates(reference: CanonicalReference, descriptors: ContentDescriptor[], profile: TrustProfileConfig, constraints?: ResolutionConstraints): ResolutionResult;
41
+ //# sourceMappingURL=resolution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolution.d.ts","sourceRoot":"","sources":["../src/resolution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,EACZ,YAAY,EACb,MAAM,YAAY,CAAC;AAQpB,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,YAAY,EAAE,CAAC;IAC9B,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED,qFAAqF;AACrF,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,mFAAmF;IACnF,aAAa,EAAE,OAAO,CAAC;IACvB,6DAA6D;IAC7D,QAAQ,EAAE,OAAO,CAAC;IAClB,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,UAAU,EAAE,SAAS,EAAE,CAAC;CACzB;AAED;kFACkF;AAClF,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,YAAY,CAAC;IACtB,mFAAmF;IACnF,cAAc,EAAE,OAAO,EAAE,CAAC;IAC1B,uDAAuD;IACvD,mBAAmB,CAAC,EAAE,YAAY,EAAE,CAAC;IACrC,qEAAqE;IACrE,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAMD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,kBAAkB,EAC7B,WAAW,EAAE,iBAAiB,EAAE,EAChC,OAAO,EAAE,kBAAkB,EAC3B,WAAW,GAAE,qBAA0B,GACtC,gBAAgB,CAsBlB"}
@@ -0,0 +1,35 @@
1
+ function issuerIn(list, issuer) {
2
+ return list.some((a) => a.toLowerCase() === issuer.toLowerCase());
3
+ }
4
+ /**
5
+ * Screen descriptors for a canonical reference into a candidate set under a
6
+ * trust profile + constraints. Pure + deterministic. Does NOT verify signatures
7
+ * (that is the caller's per-candidate step) — it screens *eligibility*.
8
+ */
9
+ export function resolveCandidates(reference, descriptors, profile, constraints = {}) {
10
+ const candidates = descriptors
11
+ .filter((d) => d.canonicalId.toLowerCase() === reference.id.toLowerCase())
12
+ .map((descriptor) => {
13
+ const issuerTrusted = issuerIn(profile.trustedIssuers, descriptor.issuer.address);
14
+ let reason;
15
+ if (descriptor.status !== 'active')
16
+ reason = `status ${descriptor.status}`;
17
+ else if (profile.requireTrustedIssuer && !issuerTrusted)
18
+ reason = 'issuer not in trust profile allowlist';
19
+ else if (constraints.contentType && descriptor.contentType !== constraints.contentType)
20
+ reason = 'contentType mismatch';
21
+ else if (constraints.language && descriptor.work?.language && descriptor.work.language !== constraints.language)
22
+ reason = 'language mismatch';
23
+ else {
24
+ const allowedRights = constraints.rightsStatus ?? profile.allowedRightsStatus;
25
+ if (allowedRights && allowedRights.length > 0) {
26
+ const rs = descriptor.work?.rightsStatus ?? 'unknown';
27
+ if (!allowedRights.includes(rs))
28
+ reason = `rightsStatus ${rs} not permitted`;
29
+ }
30
+ }
31
+ return { descriptor, issuerTrusted, admitted: reason === undefined, reason };
32
+ });
33
+ return { canonicalReference: reference, candidates };
34
+ }
35
+ //# sourceMappingURL=resolution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolution.js","sourceRoot":"","sources":["../src/resolution.ts"],"names":[],"mappings":"AAkDA,SAAS,QAAQ,CAAC,IAAe,EAAE,MAAe;IAChD,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;AACpE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,SAA6B,EAC7B,WAAgC,EAChC,OAA2B,EAC3B,cAAqC,EAAE;IAEvC,MAAM,UAAU,GAAgB,WAAW;SACxC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,WAAW,EAAE,KAAK,SAAS,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC;SACzE,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE;QAClB,MAAM,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAC,cAAc,EAAE,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAClF,IAAI,MAA0B,CAAC;QAE/B,IAAI,UAAU,CAAC,MAAM,KAAK,QAAQ;YAAE,MAAM,GAAG,UAAU,UAAU,CAAC,MAAM,EAAE,CAAC;aACtE,IAAI,OAAO,CAAC,oBAAoB,IAAI,CAAC,aAAa;YAAE,MAAM,GAAG,uCAAuC,CAAC;aACrG,IAAI,WAAW,CAAC,WAAW,IAAI,UAAU,CAAC,WAAW,KAAK,WAAW,CAAC,WAAW;YAAE,MAAM,GAAG,sBAAsB,CAAC;aACnH,IAAI,WAAW,CAAC,QAAQ,IAAI,UAAU,CAAC,IAAI,EAAE,QAAQ,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,KAAK,WAAW,CAAC,QAAQ;YAAE,MAAM,GAAG,mBAAmB,CAAC;aACzI,CAAC;YACJ,MAAM,aAAa,GAAG,WAAW,CAAC,YAAY,IAAI,OAAO,CAAC,mBAAmB,CAAC;YAC9E,IAAI,aAAa,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9C,MAAM,EAAE,GAAG,UAAU,CAAC,IAAI,EAAE,YAAY,IAAI,SAAS,CAAC;gBACtD,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAAE,MAAM,GAAG,gBAAgB,EAAE,gBAAgB,CAAC;YAC/E,CAAC;QACH,CAAC;QACD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,KAAK,SAAS,EAAE,MAAM,EAAE,CAAC;IAC/E,CAAC,CAAC,CAAC;IAEL,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;AACvD,CAAC"}
@@ -0,0 +1,172 @@
1
+ import type { Address, Hex } from '@agenticprimitives/types';
2
+ import type { VerifiableCredential } from '@agenticprimitives/verifiable-credentials';
3
+ /**
4
+ * Who may retrieve a rendering (apcnt:accessPolicy codelist; spec 266 §2.2).
5
+ * `public` needs no entitlement; `licensed`/`private` are gated. An accessPolicy
6
+ * is a POLICY INPUT, never a legal grant (ADR-0033 R5; spec 266 §threat-model).
7
+ */
8
+ export type AccessPolicy = 'public' | 'licensed' | 'private';
9
+ /**
10
+ * How a descriptor's authenticity/inclusion is proven (apcnt:proofPolicy). The
11
+ * enum is fixed now so apps can target it; Phase 1 implements the `*-v1`
12
+ * signature/hash/merkle paths — the rest are reserved (spec 266 §6/§8).
13
+ */
14
+ export type ProofPolicy = 'issuer-signature-v1' | 'issuer-signature-and-hash-v1' | 'merkle-membership-v1' | 'signed-api-response-v1' | 'entitlement-attestation-v1' | 'zk-membership-v1';
15
+ /** Lifecycle of a descriptor. Verification is fail-closed on non-`active`. */
16
+ export type DescriptorStatus = 'active' | 'revoked' | 'superseded';
17
+ /** Rights posture of the underlying work (a policy input, not a grant). */
18
+ export type RightsStatus = 'public-domain' | 'open-license' | 'licensed' | 'unknown';
19
+ /** Phase-1 trust profiles (spec 266 §policy). Only `public-domain-demo` is wired.
20
+ * Generic, vertical-agnostic names — an app may map them to domain labels. */
21
+ export type TrustProfile = 'public-domain-demo' | 'strict-verified-issuer' | 'community-experimental' | 'restricted-high-assurance';
22
+ /**
23
+ * A scheme-independent, structured canonical locus. The CORE treats this as an
24
+ * OPAQUE record. Its keys MUST be controlled tokens (never user strings, display
25
+ * labels, or surface-grammar strings) supplied by a vertical-extension package,
26
+ * because JCS does NOT Unicode-normalize strings — the extension normalizes all
27
+ * surface forms to controlled tokens BEFORE they reach the hash. Two surface
28
+ * grammars that denote the same locus MUST produce an equal canonical locus.
29
+ */
30
+ export type CanonicalLocus = Record<string, unknown>;
31
+ /**
32
+ * The hashed envelope (spec 266 §2.1). The id commits not just to the locus
33
+ * fields but to the PROFILE that defines their meaning + the domain — so the
34
+ * same JSON can never conceptually collide across primitives or versions.
35
+ */
36
+ export interface CanonicalLocusEnvelope {
37
+ /** Fixed id construction scheme, e.g. 'ap-locus-id-v1'. */
38
+ idScheme: string;
39
+ /** Vertical domain tag, e.g. 'lyrics' / 'legal-code' / 'doc'. */
40
+ contentDomain: string;
41
+ /** Versioned locus profile (the governance seam), e.g. 'ap.<domain>.locus.v1'. */
42
+ locusProfile: string;
43
+ /** The controlled-token canonical locus (opaque to the core). */
44
+ canonicalLocus: CanonicalLocus;
45
+ }
46
+ /** FRBR Work locus: the deterministic, domain-separated id of an envelope. */
47
+ export interface CanonicalReference {
48
+ /** keccak256("ap:canonical-locus-id:v1\0" || JCS(envelope)) — registry-free. */
49
+ id: Hex;
50
+ /** The envelope the id was computed from. */
51
+ envelope: CanonicalLocusEnvelope;
52
+ /** Optional human alias that resolved to this reference (e.g. 'doc:section-1.2'). */
53
+ alias?: string;
54
+ }
55
+ /** Commitment to off-platform rendering text (structured + versioned; spec 266 §7). */
56
+ export interface ContentCommitment {
57
+ type: 'canonicalTextCommitment';
58
+ /** The frozen normalization profile id, e.g. 'ap:normalization:canonical-text-v1'. */
59
+ normalization: string;
60
+ /** Digest algorithm of the normalized text. */
61
+ algorithm: 'sha-256';
62
+ /** Digest value (hex). NEVER the text (ADR-0033 R3). */
63
+ value: Hex;
64
+ }
65
+ /**
66
+ * FRBR Expression/Manifestation — a versioned body of renderings published by an
67
+ * issuer Smart Agent, committed by a Merkle `corpusRoot` + signed manifest.
68
+ * Carries NO rendering text (ADR-0033 R3).
69
+ */
70
+ export interface CorpusManifest {
71
+ /** keccak256(utf8(`${issuer}/${edition}/${version}`)). */
72
+ corpusRef: Hex;
73
+ issuer: Address;
74
+ edition: string;
75
+ version: string;
76
+ /** The content type this corpus renders (e.g. 'text.passage'). */
77
+ scheme: string;
78
+ /** Merkle root over the per-locus descriptor commitments. */
79
+ corpusRoot: Hex;
80
+ accessPolicy: AccessPolicy;
81
+ proofPolicy: ProofPolicy;
82
+ /** keccak/sha digest of the off-chain license-terms doc (R5). Never the terms. */
83
+ licenseTermsHash: Hex;
84
+ metadataUri?: string;
85
+ }
86
+ /** Bibliographic metadata about the underlying work (policy inputs). */
87
+ export interface WorkMeta {
88
+ title?: string;
89
+ abbreviation?: string;
90
+ language?: string;
91
+ edition?: string;
92
+ rightsStatus?: RightsStatus;
93
+ }
94
+ /** Issuer reference — a Smart Agent address plus an optional DID/CAIP-10 label. */
95
+ export interface IssuerIdentityRef {
96
+ address: Address;
97
+ /** Optional CAIP-10 / DID label for display + verificationMethod. */
98
+ did?: string;
99
+ }
100
+ /**
101
+ * FRBR Item — an issuer's signed claim about a rendering of a canonical locus.
102
+ * Points AT off-chain text via `retrievalPointer`; NEVER contains it (R3).
103
+ * Trust flows from `signature` (issuer ERC-1271), not the platform (R5).
104
+ */
105
+ export interface ContentDescriptor {
106
+ /** Stable descriptor id (issuer-scoped), e.g. 'desc_bsb_<canonicalIdShort>'. */
107
+ id: string;
108
+ /** The scheme-independent canonical locus this describes. */
109
+ canonicalId: Hex;
110
+ /** Opaque app content type, e.g. 'text.passage'. */
111
+ contentType: string;
112
+ issuer: IssuerIdentityRef;
113
+ issuedAt: string;
114
+ status: DescriptorStatus;
115
+ version?: string;
116
+ validFrom?: string;
117
+ validUntil?: string;
118
+ revocationRef?: string;
119
+ /** Bibliographic metadata (title/language/edition/rightsStatus). */
120
+ work?: WorkMeta;
121
+ /** Structured domain semantics supplied by the vertical (e.g. section/line/edition). */
122
+ selector?: Record<string, unknown>;
123
+ /** Commitment to the off-platform rendering (optional for signature-only proofs). */
124
+ commitment?: ContentCommitment;
125
+ /** URI/locator for the off-chain text. NEVER the text itself (R3). */
126
+ retrievalPointer: string;
127
+ proofPolicy: ProofPolicy;
128
+ accessPolicy: AccessPolicy;
129
+ /** Membership corpus (when proofPolicy is merkle-membership-v1). */
130
+ corpusRef?: Hex;
131
+ /** Issuer ERC-1271 signature over descriptorHash(unsigned). */
132
+ signature: Hex;
133
+ }
134
+ /** Input to {@link buildContentDescriptor} (everything but the signature). */
135
+ export type BuildDescriptorInput = Omit<ContentDescriptor, 'signature'>;
136
+ /**
137
+ * Verifies an issuer signature. Apps inject one backed by an
138
+ * `AgentAccountClient.isValidSignature` (ERC-1271/6492); tests inject a fake.
139
+ * Decoupled per ADR-0006's injected-context pattern.
140
+ */
141
+ export type SignatureVerifier = (args: {
142
+ signer: Address;
143
+ hash: Hex;
144
+ signature: Hex;
145
+ }) => Promise<boolean> | boolean;
146
+ /** A credential asserting a subject may access a corpus (apcnt:Entitlement). */
147
+ export type Entitlement = VerifiableCredential<{
148
+ id: string;
149
+ corpusRef: Hex;
150
+ accessPolicy: AccessPolicy;
151
+ terms?: string;
152
+ }>;
153
+ /** The AI-safe citation record (apcnt:CitationAssertion). Carries provenance,
154
+ * never rendering text. */
155
+ export type CitationAssertion = VerifiableCredential<{
156
+ id: string;
157
+ /** Agentic provenance — which run/output cited this. */
158
+ agentRunId?: string;
159
+ outputId?: string;
160
+ citationKind: 'quote' | 'reference' | 'summary' | 'paraphrase';
161
+ canonicalId: Hex;
162
+ descriptorId: string;
163
+ contentType: string;
164
+ commitment?: ContentCommitment;
165
+ commitmentVerified: boolean;
166
+ /** Optional hash of the specific quoted span + the normalization used. */
167
+ quoteSpanHash?: Hex;
168
+ normalizationSpec?: string;
169
+ issuer: Address;
170
+ underEntitlement?: string;
171
+ }>;
172
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@agenticprimitives/content-primitives",
3
+ "version": "1.0.0-alpha.6",
4
+ "description": "Verifiable Content Substrate SDK: name, resolve, commit, entitlement-gate, and cite off-platform content controlled by third-party rights holders. Owns CanonicalLocus / CorpusManifest / ContentDescriptor / CitationAssertion / Entitlement (FRBR-aligned), deterministic locusId, Merkle corpus commitments, and issuer-signature verification. Content-agnostic — no vertical/faith vocabulary, no content text (ADR-0033).",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/agentictrustlabs/agenticprimitives.git",
9
+ "directory": "packages/content-primitives"
10
+ },
11
+ "homepage": "https://github.com/agentictrustlabs/agenticprimitives/tree/master/packages/content-primitives",
12
+ "bugs": {
13
+ "url": "https://github.com/agentictrustlabs/agenticprimitives/issues"
14
+ },
15
+ "type": "module",
16
+ "main": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ },
23
+ "./merkle": {
24
+ "types": "./dist/merkle.d.ts",
25
+ "import": "./dist/merkle.js"
26
+ }
27
+ },
28
+ "files": [
29
+ "LICENSE",
30
+ "dist",
31
+ "spec.md",
32
+ "README.md",
33
+ "CLAUDE.md"
34
+ ],
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "peerDependencies": {
39
+ "viem": "^2.52.2",
40
+ "@agenticprimitives/types": "1.0.0-alpha.6",
41
+ "@agenticprimitives/verifiable-credentials": "0.0.0-alpha.2"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^22.7.0",
45
+ "vitest": "^4.1.8"
46
+ },
47
+ "keywords": [
48
+ "content",
49
+ "commitment",
50
+ "merkle",
51
+ "provenance",
52
+ "citation",
53
+ "agentic"
54
+ ],
55
+ "scripts": {
56
+ "build": "tsc -p tsconfig.build.json",
57
+ "typecheck": "tsc -p tsconfig.json --noEmit",
58
+ "test": "vitest run",
59
+ "test:unit": "vitest run test/reference.test.ts test/merkle.test.ts test/descriptor.test.ts test/entitlement.test.ts",
60
+ "test:integration": "vitest run test/integration.test.ts",
61
+ "test:watch": "vitest",
62
+ "clean": "rm -rf dist"
63
+ }
64
+ }
package/spec.md ADDED
@@ -0,0 +1,16 @@
1
+ # @agenticprimitives/content-primitives — spec
2
+
3
+ The full design lives in
4
+ [`../../specs/266-verifiable-content-substrate.md`](../../specs/266-verifiable-content-substrate.md).
5
+
6
+ Architecture decision:
7
+
8
+ - [ADR-0033](../../docs/architecture/decisions/0033-content-agnostic-verifiable-content-firewall.md)
9
+ — content-agnostic firewall; content loci are scheme-anchored (an ADR-0010
10
+ carve-out); no licensed content (R1), no content text on-chain (R3).
11
+
12
+ First usage domain: the scripture demo vertical
13
+ ([spec 267](../../specs/267-scripture-demo-vertical.md)) — all Bible/faith
14
+ specifics live in `apps/demo-bible-*`, never here.
15
+
16
+ Do not edit a divergent copy here — edit the canonical spec.