@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.
- package/CLAUDE.md +62 -0
- package/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/descriptor.d.ts +62 -0
- package/dist/descriptor.d.ts.map +1 -0
- package/dist/descriptor.js +100 -0
- package/dist/descriptor.js.map +1 -0
- package/dist/entitlement.d.ts +64 -0
- package/dist/entitlement.d.ts.map +1 -0
- package/dist/entitlement.js +64 -0
- package/dist/entitlement.js.map +1 -0
- package/dist/errors.d.ts +9 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +15 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/jcs.d.ts +4 -0
- package/dist/jcs.d.ts.map +1 -0
- package/dist/jcs.js +25 -0
- package/dist/jcs.js.map +1 -0
- package/dist/merkle.d.ts +29 -0
- package/dist/merkle.d.ts.map +1 -0
- package/dist/merkle.js +74 -0
- package/dist/merkle.js.map +1 -0
- package/dist/reference.d.ts +28 -0
- package/dist/reference.d.ts.map +1 -0
- package/dist/reference.js +35 -0
- package/dist/reference.js.map +1 -0
- package/dist/reserved.d.ts +12 -0
- package/dist/reserved.d.ts.map +1 -0
- package/dist/reserved.js +19 -0
- package/dist/reserved.js.map +1 -0
- package/dist/resolution.d.ts +41 -0
- package/dist/resolution.d.ts.map +1 -0
- package/dist/resolution.js +35 -0
- package/dist/resolution.js.map +1 -0
- package/dist/types.d.ts +172 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +64 -0
- 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":"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"}
|
|
@@ -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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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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 @@
|
|
|
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
|
package/dist/jcs.js.map
ADDED
|
@@ -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"}
|
package/dist/merkle.d.ts
ADDED
|
@@ -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"}
|
package/dist/reserved.js
ADDED
|
@@ -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"}
|
package/dist/types.d.ts
ADDED
|
@@ -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 @@
|
|
|
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.
|