@agenticprimitives/types 1.0.0-alpha.4 → 1.0.0-alpha.41

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/README.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # @agenticprimitives/types
2
2
 
3
- Cross-cutting branded types and chain primitives shared across `@agenticprimitives/*` packages. Types-only; no runtime code.
3
+ > Part of **[Agentic Primitives](https://agenticprimitives.dev)** — the open-source trust substrate for agentic applications: identity that can sign, authority checked at act time, evidence the owner carries. [Developer kit](https://github.com/agentictrustlabs/agentic-primitives) · [All packages](https://agenticprimitives.dev/developers)
4
+
5
+ **The shared type vocabulary that keeps thirty packages pointing at one identity.**
6
+
7
+ A trust substrate lives or dies on agreement about what an identity *is*. `types` is where that agreement is written down as the compiler's problem: branded primitives (`Address`, `Hex`, `ChainId`, `Caip10Address`) and the cross-cutting identity shapes (`CanonicalAgentIdentity`, `AgentType`, `AgentSession`, `CredentialPrincipal`, `Assurance`) that every `@agenticprimitives/*` package shares. Because the brands are phantom types, a raw string cannot masquerade as an address and a CAIP-10 subject cannot be confused with a bare EVM address — across package boundaries, at compile time, with zero runtime cost.
8
+
9
+ It is also where the doctrine becomes a type. `CanonicalAgentIdentity` is the ADR-0010 rule — the agent's identity IS its Smart Agent address — as an alias of `Address`, and `AgentSession` deliberately has **no `owner` field** (ADR-0016): the SSO session names the agent itself, never a vendor-side owner. Types-only, zero dependencies, no runtime code; it is the leaf every other package depends on and the reason the dependency graph has no back-edges.
10
+
11
+ > Part of [agenticprimitives](../../README.md) — the trust substrate for the agent economy: one canonical Smart Agent identity with custody, delegation, naming, credentials, and audit evidence designed as one system.
4
12
 
5
13
  ## Install
6
14
 
@@ -18,6 +26,25 @@ const chain: ChainId = 1 as ChainId;
18
26
  const account: Address = '0x...';
19
27
  ```
20
28
 
29
+ Also exported: `CanonicalAgentIdentity` (ADR-0010 alias of `Address`); `Caip10Address`, `CanonicalAgentId`, `Caip10Parts` (CAIP-10 brand — the type lives here, the runtime builder lives in `agent-profile`); `AgentType` (`'person' | 'org' | 'service'`) and `NameContext` (display-only injection shape); and the SSO/session shapes `AgentSession`, `CredentialPrincipal`, `Assurance`, `CredentialKind`, `CredentialRole` (specs 223/224).
30
+
31
+ ## How it's different from a typical `types` package
32
+
33
+ Most monorepo `types` packages are junk drawers that grow until everything depends on everything. This one is governed:
34
+
35
+ - **Admission rule:** a type lands here only when ≥ 2 packages consume it and it cannot live anywhere lower. Single-consumer types stay in their package.
36
+ - **No runtime, ever.** No functions, no constants with behavior, no side effects. Even the CAIP-10 *builder* is excluded — only the brand lives here.
37
+ - **Shared shapes without runtime coupling.** `AgentSession` lives here precisely so `identity-directory`, `connect`, and relying-site SDKs can agree on the token shape without importing each other.
38
+
39
+ The result is a leaf package small enough to audit in one sitting, strong enough to make identity confusion a compile error.
40
+
21
41
  ## Status
22
42
 
23
- Pre-alpha. Minimal by design. Adding a type here requires ≥2 consuming packages.
43
+ Minimal by design — adding a type requires ≥ 2 consuming packages. Testnet/pilot-ready. Production launch is gated on the public checklist in the root [`README.md` Status section](../../README.md#status) — including third-party contract audit and governance key rotation. Track every security finding live in [`docs/audits/findings.yaml`](../../docs/audits/findings.yaml).
44
+
45
+ ## Validate
46
+
47
+ ```bash
48
+ pnpm --filter @agenticprimitives/types typecheck
49
+ pnpm check:forbidden-terms
50
+ ```
@@ -0,0 +1,84 @@
1
+ import type { CanonicalAgentId, Hex32 } from './index.js';
2
+ /**
3
+ * A reference to a subject in any trust domain AP recognizes — a discriminated union, so a web2 identifier
4
+ * (OIDC `sub`, SPIFFE ID, OAuth agent-instance) and a web3 identifier (CAIP-10 Smart Agent) are the same shape
5
+ * but never conflated. **Ring 0 uses `caip10` for authority**; the rest are facets bound by proof.
6
+ */
7
+ export type SubjectRef = {
8
+ scheme: 'caip10';
9
+ id: CanonicalAgentId;
10
+ } | {
11
+ scheme: 'oidc';
12
+ issuer: string;
13
+ subject: string;
14
+ } | {
15
+ scheme: 'did';
16
+ id: string;
17
+ } | {
18
+ scheme: 'spiffe';
19
+ id: string;
20
+ trustDomain: string;
21
+ } | {
22
+ scheme: 'oauth-agent-instance';
23
+ issuer: string;
24
+ id: string;
25
+ };
26
+ /** Proof-of-possession key — proves control of a key, NOT who the agent is (web2: OAuth/OIDC `cnf`, RFC 7800;
27
+ * web3: the session-key / passkey credential). Rotating it must never change agent or instance identity. */
28
+ export interface ConfirmationKey {
29
+ method: 'jkt' | 'x5t#S256' | 'erc1271' | 'erc6492' | 'spiffe-key';
30
+ id: string;
31
+ }
32
+ /**
33
+ * The explicit actor roles carried on a hop (ADR-0052 §2). These roles may overlap in one hop and are
34
+ * INDEPENDENT of `AgentType` (person/org/service). Crucially `accountabilityRoot` ≠ `rootPrincipal`: the anchor
35
+ * is durable while the principal-as-represented may be pairwise/pseudonymous — that gap is the privacy story.
36
+ */
37
+ export interface ActorContextV1 {
38
+ /** The durable AP anchor everything traces back to (web2: accountable party / GDPR controller; web3: the
39
+ * ERC-4337 Smart Agent). Usually a Person or Organization SA. */
40
+ accountabilityRoot: SubjectRef;
41
+ /** The human/org ultimately represented (web2: OAuth/agency-law "principal"); MAY be pairwise/pseudonymous. */
42
+ rootPrincipal?: SubjectRef;
43
+ /** The agent that started the overall task. */
44
+ originatingAgent: SubjectRef;
45
+ /** The agent performing THIS hop — may be a sub-agent (web2: OAuth token-exchange `act` actor). */
46
+ actingAgent: SubjectRef;
47
+ /** The particular task/session/process/container runtime (web2: WIMSE/SPIFFE workload instance). */
48
+ agentInstance?: SubjectRef;
49
+ confirmationKey?: ConfirmationKey;
50
+ /** Pointer to the portable authority-chain projection (the on-chain authority chain, projected — spec 326 W2). */
51
+ authorityChain: {
52
+ profile: string;
53
+ digest: Hex32;
54
+ evidenceRef?: string;
55
+ };
56
+ /** Exact-invocation binding (spec 287) — what is being asked for, on this audience, once. */
57
+ invocation?: {
58
+ audience: string;
59
+ operation: string;
60
+ requestDigest: Hex32;
61
+ requestId: string;
62
+ expiresAt: string;
63
+ };
64
+ }
65
+ /** The typed cross-binding relationships (ADR-0052 §3 / spec 326 §3.3). A `SubjectBinding` is a signed, scoped,
66
+ * revocable RELATIONSHIP between two `SubjectRef`s — NEVER `owl:sameAs` / identifier equality. */
67
+ export type SubjectBindingRelationship = 'accountability-root-of' | 'represents-principal' | 'agent-identity-of' | 'runtime-instance-of' | 'controlled-by' | 'delegated-to' | 'executed-by-workload';
68
+ /** How strongly a binding is attested. Bilateral (`mutually-proven`) is preferred for cross-domain links. */
69
+ export type BindingAssurance = 'self-asserted' | 'mutually-proven' | 'third-party-attested';
70
+ /** A typed cross-binding credential (VC or signed JSON) — the proof that two identifiers in different trust
71
+ * domains refer to the same party, WITHOUT merging them. */
72
+ export interface SubjectBindingV1 {
73
+ type: 'SubjectBindingV1';
74
+ relationship: SubjectBindingRelationship;
75
+ from: SubjectRef;
76
+ to: SubjectRef;
77
+ assurance: BindingAssurance;
78
+ issuedAt?: string;
79
+ expiresAt?: string;
80
+ revocationRef?: string;
81
+ /** Digest both sides sign for a bilateral (`mutually-proven`) binding. */
82
+ bindingDigest?: Hex32;
83
+ }
84
+ //# sourceMappingURL=actor-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actor-context.d.ts","sourceRoot":"","sources":["../src/actor-context.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAE1D;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAClB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,gBAAgB,CAAA;CAAE,GAC1C;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,MAAM,EAAE,sBAAsB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE;6GAC6G;AAC7G,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,KAAK,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,YAAY,CAAC;IAClE,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B;sEACkE;IAClE,kBAAkB,EAAE,UAAU,CAAC;IAC/B,+GAA+G;IAC/G,aAAa,CAAC,EAAE,UAAU,CAAC;IAC3B,+CAA+C;IAC/C,gBAAgB,EAAE,UAAU,CAAC;IAC7B,mGAAmG;IACnG,WAAW,EAAE,UAAU,CAAC;IACxB,oGAAoG;IACpG,aAAa,CAAC,EAAE,UAAU,CAAC;IAC3B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,kHAAkH;IAClH,cAAc,EAAE;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,KAAK,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,6FAA6F;IAC7F,UAAU,CAAC,EAAE;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,KAAK,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED;mGACmG;AACnG,MAAM,MAAM,0BAA0B,GAClC,wBAAwB,GACxB,sBAAsB,GACtB,mBAAmB,GACnB,qBAAqB,GACrB,eAAe,GACf,cAAc,GACd,sBAAsB,CAAC;AAE3B,6GAA6G;AAC7G,MAAM,MAAM,gBAAgB,GAAG,eAAe,GAAG,iBAAiB,GAAG,sBAAsB,CAAC;AAE5F;6DAC6D;AAC7D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,kBAAkB,CAAC;IACzB,YAAY,EAAE,0BAA0B,CAAC;IACzC,IAAI,EAAE,UAAU,CAAC;IACjB,EAAE,EAAE,UAAU,CAAC;IACf,SAAS,EAAE,gBAAgB,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC;CACvB"}
@@ -0,0 +1,9 @@
1
+ // Actor context + portable authority chain — spec 326 W1 (ADR-0052).
2
+ //
3
+ // TERMINOLOGY IS THE EXPLANATION. Every name here is deliberately the term a web2 IAM/security reader AND a
4
+ // web3 reader already recognize, pointing at the SAME concept — the machine-readable groundings live in
5
+ // `@agenticprimitives/ontology` (`GROUNDED_VOCABULARY` + `mappings/actor-context-standards.ttl`). Ring 0 uses
6
+ // the `caip10` SubjectRef for authority; every other scheme appears in bindings/projections only, NEVER as an
7
+ // authority source (ADR-0041) and NEVER as identifier equality with the SA (ADR-0052 §3).
8
+ export {};
9
+ //# sourceMappingURL=actor-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actor-context.js","sourceRoot":"","sources":["../src/actor-context.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,4GAA4G;AAC5G,wGAAwG;AACxG,8GAA8G;AAC9G,8GAA8G;AAC9G,0FAA0F"}
package/dist/index.d.ts CHANGED
@@ -42,7 +42,7 @@ export interface Caip10Parts {
42
42
  /** Assurance ladder, ordered low→high. Threads into SSO step-up (ADR-0017). */
43
43
  export type Assurance = 'unverified' | 'asserted' | 'onchain-read' | 'onchain-confirmed';
44
44
  /** Credential facet kinds that can authenticate a session. */
45
- export type CredentialKind = 'passkey' | 'siwe-eoa' | 'hardware' | 'oidc';
45
+ export type CredentialKind = 'passkey' | 'siwe-eoa' | 'hardware' | 'oidc' | 'email' | 'phone';
46
46
  /** What a credential is trusted for. login-grade ≠ custody-grade (ADR-0017). */
47
47
  export type CredentialRole = 'login-grade' | 'custody-grade';
48
48
  /** The credential that authenticated a session — a facet key, NOT the identity. */
@@ -92,7 +92,57 @@ export interface AgentSession {
92
92
  * (`agentKind: 'service'` + a profile `serviceType` / `ProfileType: 'treasury'`
93
93
  * subtype; specs 217/225 §6). Do not re-add it here.
94
94
  */
95
+ /**
96
+ * What an agent CAN DO, as advertised (ADR-0051, spec 325 §2.2).
97
+ *
98
+ * **Capability** is the canonical noun across the profile, the vault, the on-chain record, discovery and
99
+ * every UI. `skill` without a qualifier means a SKILL.md playbook and nothing else. The word `skills`
100
+ * appears in exactly one place — the A2A wire, where the protocol calls this object `skills[]` — and it
101
+ * is the A2A projector's job to translate. A `skills` field anywhere else is a defect.
102
+ *
103
+ * Lives in `types` because it is shared vocabulary: `agent-profile` carries it as the system of record,
104
+ * `capability-claims` produces candidates of this shape, the indexer projects it, and the apps edit it.
105
+ * Putting it in either owner would have forced a package edge between two leaves.
106
+ */
107
+ export interface AdvertisedCapabilityV1 {
108
+ /** Stable CURIE. The SAME id appears in ARD `capabilities[]` and in the on-chain `atl:capabilities`. */
109
+ id: string;
110
+ name: string;
111
+ description: string;
112
+ tags: string[];
113
+ /** ARD `representativeQueries` — 2 to 5, and only ones the owner actually wrote. Never invented. */
114
+ examples?: string[];
115
+ inputModes?: string[];
116
+ outputModes?: string[];
117
+ }
95
118
  export type AgentType = 'person' | 'org' | 'service';
119
+ /**
120
+ * The DERIVED agent type (ADR-0061 / spec 346 §2). A closed, spec-governed specialization layer UNDER
121
+ * the three PROV-O roots, following the `ap:Treasury ⊑ ap:ServiceAgent` precedent:
122
+ *
123
+ * person → root person (prov:Person)
124
+ * org → root org (prov:Organization)
125
+ * team → root org (ap:TeamAgent ⊑ ap:OrganizationAgent, spec 344 §1.1)
126
+ * service → root service (ap:ServiceAgent ⊑ ap:ApplicationAgent)
127
+ * workspace→ root service (ap:WorkspaceAgent ⊑ ap:ServiceAgent, spec 344 §2.1)
128
+ * treasury → root service (ap:Treasury ⊑ ap:ServiceAgent)
129
+ * registry → root service (ap:RegistryAgent ⊑ ap:ServiceAgent — the Service Agent that OPERATES a registry)
130
+ * church → root org (ap:ChurchAgent ⊑ ap:OrganizationAgent — a gathered-community-shaped organization; ADR-0061 amendment 2026-08-30)
131
+ * circle → root org (ap:CircleAgent ⊑ ap:OrganizationAgent — a small-group-shaped organization)
132
+ *
133
+ * Carried in the profile/kind record (on-chain `atl:agentType` on the SA subject), NEVER in `AgentType`.
134
+ * A name suffix names the derived type (`.me .org .team .svc .workspace .treasury .registry .church .circle`); the record is the
135
+ * authority and a mismatched suffix fails closed. Roles (indexer, relay, assistant, …) are NOT derived
136
+ * types — they stay an open-set `serviceRole` label on a Service agent (ADR-0046).
137
+ */
138
+ export type DerivedAgentType = 'person' | 'org' | 'team' | 'service' | 'workspace' | 'treasury' | 'registry' | 'church' | 'circle' | 'household';
139
+ /** Every derived type, in canonical order (mirrors the on-chain `atl:AgentTypeEnum` set). */
140
+ export declare const DERIVED_AGENT_TYPES: readonly DerivedAgentType[];
141
+ /**
142
+ * Map a derived type DOWN to its closed root (ADR-0046 rule 4: kinds map down, never up). Pure;
143
+ * throws on an unknown value so a typo can never silently become a root.
144
+ */
145
+ export declare function rootClassForDerivedType(t: DerivedAgentType): AgentType;
96
146
  /**
97
147
  * Optional naming context other packages accept as injected
98
148
  * parameter. Apps that don't use naming pass nothing; apps that do
@@ -112,5 +162,110 @@ export interface NameContext {
112
162
  agentName?: string;
113
163
  /** Discriminator for branching: person vs org vs service (treasury ⊂ service — not branched here). */
114
164
  agentType?: AgentType;
165
+ /** The derived type the name's suffix names (spec 346 §2). Display/grouping only — never authority. */
166
+ derivedType?: DerivedAgentType;
167
+ }
168
+ /** 32-byte hash / digest hex (`0x` + 64 hex). Structurally a `Hex`; named for hash-shaped values. */
169
+ export type Hex32 = `0x${string}`;
170
+ /** A signature proof over a canonical digest. Verification is the runtime's job (ERC-1271/ECDSA/session-key);
171
+ * carrying this proof is never itself authorization. */
172
+ export interface SignatureProof {
173
+ signer: CanonicalAgentId;
174
+ scheme: 'erc1271' | 'ecdsa' | 'session-key';
175
+ signature: `0x${string}`;
176
+ }
177
+ /**
178
+ * Deterministic JSON canonicalization: sorted keys, `undefined` members dropped. The shared digest
179
+ * convention used across `messaging` / `verification-receipts` / `key-authorization` so cross-package tooling
180
+ * produces identical hashes. Pure (no clocks, no I/O, no crypto).
181
+ */
182
+ export declare function canonicalizeJson(v: unknown): string;
183
+ export type { SubjectRef, ConfirmationKey, ActorContextV1, SubjectBindingRelationship, BindingAssurance, SubjectBindingV1, } from './actor-context.js';
184
+ export { UNAUTHENTICATED_PEER, isAgentAuthenticatedPeer, isChannelBoundPeer, meetsPeerStrength, validatePeerContext } from './verified-peer-context.js';
185
+ export type { ChannelBinding, PeerAuthMethod, PeerAuthStrength, PeerContextViolation, PeerKeyBinding, VerifiedPeerContextV1, } from './verified-peer-context.js';
186
+ /**
187
+ * ERC-1271 `isValidSignature` success value — `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
188
+ *
189
+ * A PROTOCOL constant, not an implementation detail, which is why it lives in the one package
190
+ * everything may import. It was previously declared in `agent-account`, `connect-auth`, `delegation`,
191
+ * `payments` and five apps — and `connect-auth` had no choice, because `agent-account` imports IT, so
192
+ * reaching the other way would be a cycle. A shared constant in `types` is the only home that does
193
+ * not force somebody to keep a copy.
194
+ */
195
+ export declare const ERC1271_MAGIC_VALUE: "0x1626ba7e";
196
+ export declare class JcsError extends Error {
197
+ readonly path: string;
198
+ constructor(message: string, path: string);
199
+ }
200
+ /**
201
+ * Canonicalize a JSON-compatible value per RFC 8785.
202
+ * Returns the canonical string (UTF-8 text; callers wrap with `utf8ToBytes` to hash).
203
+ */
204
+ export declare function jcsCanonicalize(value: unknown, path?: string): string;
205
+ /** CAIP-10 `namespace:reference:address`. Shape only — says nothing about which namespaces are allowed. */
206
+ export declare const CAIP10_GRAMMAR: RegExp;
207
+ export interface Caip10PartsShape {
208
+ namespace: string;
209
+ reference: string;
210
+ address: string;
211
+ }
212
+ /**
213
+ * Parse a CAIP-10 identifier by GRAMMAR. Returns `null` — never throws, never guesses.
214
+ *
215
+ * NOT a substitute for `agent-profile.parseCaip10`, which additionally enforces the namespace
216
+ * allowlist. Use this where you only need to know "is this shaped like a CAIP-10 id, and what are its
217
+ * parts"; use that one where the answer decides authority.
218
+ */
219
+ export declare function parseCaip10Parts(value: string): Caip10PartsShape | null;
220
+ /** Is this an EVM CAIP-10 id — `eip155:<chainId>:<20-byte address>`? Strict on the address length. */
221
+ export declare function isEvmCaip10(value: string): boolean;
222
+ /**
223
+ * Build an EVM CAIP-10 id.
224
+ *
225
+ * DOES NOT NORMALIZE CASE, deliberately. Callers differ — some emit checksummed addresses and their
226
+ * output is asserted byte-for-byte — and a shared helper that quietly lowercased would change what
227
+ * every one of them produces. A dedup that changes bytes is not a dedup. Lowercase at the call site
228
+ * if that is what you mean.
229
+ */
230
+ export declare function evmCaip10(chainId: number | string, address: string): string;
231
+ /** One validation / projection finding. `evidenceNeeded` means "cannot be decided without evidence", not "warning". */
232
+ export interface ProjectionDiagnosticV1 {
233
+ code: string;
234
+ severity: 'error' | 'warning' | 'info' | 'evidenceNeeded';
235
+ /** RFC 6901 JSON Pointer into the SOURCE document (card / input bundle). */
236
+ sourcePointer?: string;
237
+ /** Target family or JSON Pointer into the target artifact. */
238
+ target?: string;
239
+ message: string;
240
+ explanation?: string;
241
+ suggestedFix?: {
242
+ kind: 'manual' | 'automatic' | 'approvalRequired';
243
+ description: string;
244
+ /** RFC 6902 JSON Patch the caller MAY apply (never applied implicitly). */
245
+ patch?: unknown[];
246
+ };
247
+ }
248
+ /** Pointer to evidence (attestation, receipt, fetched document, test run). Never authority. */
249
+ export interface EvidenceRefV1 {
250
+ kind: 'attestation' | 'verification-receipt' | 'fetched-document' | 'runtime-test' | 'chain-read' | 'other';
251
+ ref: string;
252
+ /** `sha256:<hex>` of the evidence body when content-addressed. */
253
+ digest?: string;
254
+ observedAt?: string;
255
+ }
256
+ /**
257
+ * Pointer to a recorded approval decision (spec 347 §6.3). Names the EXACT digest approved, so a plan whose
258
+ * inputs changed cannot reuse it. Carrying it proves nothing — the publisher re-reads the approval record.
259
+ */
260
+ export interface ApprovalRefV1 {
261
+ approvalId: string;
262
+ /** The approved input digest (`sha256:<hex>`): card release, artifact, or publication plan. */
263
+ approvedDigest: string;
264
+ approver: CanonicalAgentId;
265
+ approvedAt: string;
266
+ expiresAt?: string;
267
+ /** Idempotency key the approved plan carries; a publisher MUST refuse a plan with a different key. */
268
+ idempotencyKey?: string;
269
+ conditions?: string[];
115
270
  }
116
271
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,OAAO,GAAG,KAAK,MAAM,EAAE,CAAC;AACpC,MAAM,MAAM,GAAG,GAAG,KAAK,MAAM,EAAE,CAAC;AAChC,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,SAAS,EAAE,OAAO,MAAM,CAAA;CAAE,CAAC;AACrE,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,MAAM,IAAI,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAA;CAAE,CAAC;AAE3E;;;;;;;;GAQG;AACH,MAAM,MAAM,sBAAsB,GAAG,OAAO,CAAC;AAQ7C;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEpE;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,aAAa,CAAC;AAE7C,gFAAgF;AAChF,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AASD,+EAA+E;AAC/E,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,UAAU,GAAG,cAAc,GAAG,mBAAmB,CAAC;AAEzF,8DAA8D;AAC9D,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;AAE1E,gFAAgF;AAChF,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,eAAe,CAAC;AAE7D,mFAAmF;AACnF,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,cAAc,CAAC;IACrB,8EAA8E;IAC9E,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,SAAS,CAAC;IACrB,mFAAmF;IACnF,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,uEAAuE;IACvE,GAAG,EAAE,gBAAgB,CAAC;IACtB,sDAAsD;IACtD,SAAS,EAAE,mBAAmB,CAAC;IAC/B,oEAAoE;IACpE,SAAS,EAAE,SAAS,CAAC;IACrB,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,iCAAiC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,iBAAiB;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAYD;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAC;AAErD;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sGAAsG;IACtG,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,3 +1,238 @@
1
- // @agenticprimitives/types — cross-cutting branded primitives. Types-only.
2
- export {};
1
+ // @agenticprimitives/types — cross-cutting branded primitives.
2
+ //
3
+ // Near-types-only: the package ships a small number of PURE helpers (`canonicalizeJson`, the
4
+ // peer-context predicates) that are deterministic functions over shapes defined here. No side
5
+ // effects, no I/O, no clocks, no crypto, no state, no imports. See CLAUDE.md for the exact rule.
6
+ /** Every derived type, in canonical order (mirrors the on-chain `atl:AgentTypeEnum` set). */
7
+ export const DERIVED_AGENT_TYPES = [
8
+ 'person',
9
+ 'org',
10
+ 'team',
11
+ 'service',
12
+ 'workspace',
13
+ 'treasury',
14
+ 'registry',
15
+ 'church',
16
+ 'circle',
17
+ ];
18
+ /**
19
+ * Map a derived type DOWN to its closed root (ADR-0046 rule 4: kinds map down, never up). Pure;
20
+ * throws on an unknown value so a typo can never silently become a root.
21
+ */
22
+ export function rootClassForDerivedType(t) {
23
+ switch (t) {
24
+ case 'person':
25
+ return 'person';
26
+ case 'org':
27
+ case 'team':
28
+ case 'church':
29
+ case 'circle':
30
+ case 'household':
31
+ return 'org';
32
+ case 'service':
33
+ case 'workspace':
34
+ case 'treasury':
35
+ case 'registry':
36
+ return 'service';
37
+ default: {
38
+ const never = t;
39
+ throw new Error(`[types] unknown DerivedAgentType "${String(never)}"`);
40
+ }
41
+ }
42
+ }
43
+ /**
44
+ * Deterministic JSON canonicalization: sorted keys, `undefined` members dropped. The shared digest
45
+ * convention used across `messaging` / `verification-receipts` / `key-authorization` so cross-package tooling
46
+ * produces identical hashes. Pure (no clocks, no I/O, no crypto).
47
+ */
48
+ export function canonicalizeJson(v) {
49
+ if (v === null || typeof v !== 'object')
50
+ return JSON.stringify(v) ?? 'null';
51
+ if (Array.isArray(v))
52
+ return `[${v.map(canonicalizeJson).join(',')}]`;
53
+ const o = v;
54
+ return `{${Object.keys(o)
55
+ .sort()
56
+ .filter((k) => o[k] !== undefined)
57
+ .map((k) => `${JSON.stringify(k)}:${canonicalizeJson(o[k])}`)
58
+ .join(',')}}`;
59
+ }
60
+ // Verified peer context — transport-layer peer identity (dntls-comparison §17 P1; spec 338 W5).
61
+ // Placed here for the same reason as `ActorContextV1`: >=2 consumers (`a2a`, `mcp-runtime`, `audit`,
62
+ // edge adapters) must share ONE definition without runtime-coupling to each other.
63
+ //
64
+ // IDENTITY, NEVER AUTHORITY. Knowing who connected never implies what they may do.
65
+ export { UNAUTHENTICATED_PEER, isAgentAuthenticatedPeer, isChannelBoundPeer, meetsPeerStrength, validatePeerContext } from './verified-peer-context.js';
66
+ /**
67
+ * ERC-1271 `isValidSignature` success value — `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
68
+ *
69
+ * A PROTOCOL constant, not an implementation detail, which is why it lives in the one package
70
+ * everything may import. It was previously declared in `agent-account`, `connect-auth`, `delegation`,
71
+ * `payments` and five apps — and `connect-auth` had no choice, because `agent-account` imports IT, so
72
+ * reaching the other way would be a cycle. A shared constant in `types` is the only home that does
73
+ * not force somebody to keep a copy.
74
+ */
75
+ export const ERC1271_MAGIC_VALUE = '0x1626ba7e';
76
+ // ─── RFC 8785 JSON Canonicalization Scheme ──────────────────────────────────
77
+ //
78
+ // WHY THIS LIVES IN `types` AND NOT IN `verifiable-credentials`, WHERE IT WAS WRITTEN.
79
+ // `situations` carried a BYTE-IDENTICAL copy — ~100 lines including the number-formatting rules,
80
+ // duplicated. The obvious fix (situations re-exports from verifiable-credentials) is impossible:
81
+ // `verifiable-credentials` IMPORTS `situations`, so that edge is a cycle. Like `ERC1271_MAGIC_VALUE`,
82
+ // the only home that does not force somebody to keep a copy is the one both can reach.
83
+ //
84
+ // It is PURE — no hashing, no dependency — so `types` stays dependency-free. The keccak wrapper
85
+ // (`canonicalHash`) stays in each consumer, where the hash function it needs already lives.
86
+ //
87
+ // NOT interchangeable with `canonicalizeJson` above. That one is sorted-key JSON.stringify; THIS one
88
+ // implements RFC 8785's number formatting, escaping and code-unit ordering. Swapping one for the
89
+ // other changes bytes, which changes digests, which breaks signatures. Pick deliberately.
90
+ /** UTF-16 code unit comparison — exactly what RFC 8785 §3.2.3 requires. */
91
+ function sortByCodeUnit(a, b) {
92
+ const len = Math.min(a.length, b.length);
93
+ for (let i = 0; i < len; i++) {
94
+ const av = a.charCodeAt(i);
95
+ const bv = b.charCodeAt(i);
96
+ if (av !== bv)
97
+ return av - bv;
98
+ }
99
+ return a.length - b.length;
100
+ }
101
+ /** RFC 8259 string serialisation with JCS-compatible escaping (RFC 8785 §3.2.2.2). */
102
+ function serializeString(s) {
103
+ let out = '"';
104
+ for (let i = 0; i < s.length; i++) {
105
+ const code = s.charCodeAt(i);
106
+ if (code === 0x22) {
107
+ out += '\\"';
108
+ }
109
+ else if (code === 0x5c) {
110
+ out += '\\\\';
111
+ }
112
+ else if (code < 0x20) {
113
+ // Control characters
114
+ switch (code) {
115
+ case 0x08:
116
+ out += '\\b';
117
+ break;
118
+ case 0x09:
119
+ out += '\\t';
120
+ break;
121
+ case 0x0a:
122
+ out += '\\n';
123
+ break;
124
+ case 0x0c:
125
+ out += '\\f';
126
+ break;
127
+ case 0x0d:
128
+ out += '\\r';
129
+ break;
130
+ default:
131
+ out += `\\u${code.toString(16).padStart(4, '0')}`;
132
+ }
133
+ }
134
+ else {
135
+ out += s[i];
136
+ }
137
+ }
138
+ out += '"';
139
+ return out;
140
+ }
141
+ /** RFC 8785 §3.2.2.3 — shortest round-tripping IEEE 754 representation. */
142
+ function serializeNumber(n, path) {
143
+ if (!Number.isFinite(n)) {
144
+ throw new JcsError(`non-finite number (${n})`, path);
145
+ }
146
+ if (Object.is(n, -0))
147
+ return '0';
148
+ if (n === 0)
149
+ return '0';
150
+ if (Number.isInteger(n) && Math.abs(n) < 1e21) {
151
+ return n.toString();
152
+ }
153
+ // Browsers + Node give us the shortest round-trip via `toString()`
154
+ // (per ECMA-262 §6.1.6.1.13). RFC 8785 expects the ES round-trip form.
155
+ return n.toString();
156
+ }
157
+ export class JcsError extends Error {
158
+ path;
159
+ constructor(message, path) {
160
+ super(`[JCS] ${message} at ${path}`);
161
+ this.path = path;
162
+ }
163
+ }
164
+ /**
165
+ * Canonicalize a JSON-compatible value per RFC 8785.
166
+ * Returns the canonical string (UTF-8 text; callers wrap with `utf8ToBytes` to hash).
167
+ */
168
+ export function jcsCanonicalize(value, path = '$') {
169
+ if (value === null)
170
+ return 'null';
171
+ if (value === undefined) {
172
+ throw new JcsError('undefined is not JSON', path);
173
+ }
174
+ switch (typeof value) {
175
+ case 'boolean':
176
+ return value ? 'true' : 'false';
177
+ case 'string':
178
+ return serializeString(value);
179
+ case 'number':
180
+ return serializeNumber(value, path);
181
+ case 'object': {
182
+ if (Array.isArray(value)) {
183
+ const items = value.map((v, i) => jcsCanonicalize(v, `${path}[${i}]`));
184
+ return `[${items.join(',')}]`;
185
+ }
186
+ // Plain object
187
+ const entries = Object.entries(value)
188
+ .filter(([, v]) => v !== undefined)
189
+ .sort(([a], [b]) => sortByCodeUnit(a, b));
190
+ const items = entries.map(([k, v]) => `${serializeString(k)}:${jcsCanonicalize(v, `${path}.${k}`)}`);
191
+ return `{${items.join(',')}}`;
192
+ }
193
+ default:
194
+ throw new JcsError(`unsupported JSON type: ${typeof value}`, path);
195
+ }
196
+ }
197
+ // ─── CAIP-10 grammar (ADR-0008, promoted per its own §"ADR-0016 promotes…") ──
198
+ //
199
+ // WHY HERE AND NOT IN `agent-profile`, WHERE THE BUILDER LIVES. Five packages —
200
+ // `edge-runtime`, `geo-features`, `capability-claims`, `rate-control`, `verifiable-credentials` —
201
+ // each re-derived this, and NONE of them may import `agent-profile`. Every copy was forced by the
202
+ // dependency graph, not written out of laziness, and the copies did NOT agree: some accepted any
203
+ // `eip155:<digits>:0x…`, one accepted a SHORT address (`0x[0-9a-fA-F]+`, no length bound), and one
204
+ // was a bare `split(':')`.
205
+ //
206
+ // The split that matters: GRAMMAR is a protocol fact and lives here; the NAMESPACE ALLOWLIST is
207
+ // policy and stays in `agent-profile`, so nothing can bypass it by reaching for the loose parser.
208
+ // `parseCaip10Parts` therefore validates SHAPE only and says so.
209
+ /** CAIP-10 `namespace:reference:address`. Shape only — says nothing about which namespaces are allowed. */
210
+ export const CAIP10_GRAMMAR = /^([-a-z0-9]{3,8}):([-_a-zA-Z0-9]{1,32}):([-.%a-zA-Z0-9]{1,128})$/;
211
+ /**
212
+ * Parse a CAIP-10 identifier by GRAMMAR. Returns `null` — never throws, never guesses.
213
+ *
214
+ * NOT a substitute for `agent-profile.parseCaip10`, which additionally enforces the namespace
215
+ * allowlist. Use this where you only need to know "is this shaped like a CAIP-10 id, and what are its
216
+ * parts"; use that one where the answer decides authority.
217
+ */
218
+ export function parseCaip10Parts(value) {
219
+ const m = CAIP10_GRAMMAR.exec(value);
220
+ return m ? { namespace: m[1], reference: m[2], address: m[3] } : null;
221
+ }
222
+ /** Is this an EVM CAIP-10 id — `eip155:<chainId>:<20-byte address>`? Strict on the address length. */
223
+ export function isEvmCaip10(value) {
224
+ const p = parseCaip10Parts(value);
225
+ return !!p && p.namespace === 'eip155' && /^\d+$/.test(p.reference) && /^0x[0-9a-fA-F]{40}$/.test(p.address);
226
+ }
227
+ /**
228
+ * Build an EVM CAIP-10 id.
229
+ *
230
+ * DOES NOT NORMALIZE CASE, deliberately. Callers differ — some emit checksummed addresses and their
231
+ * output is asserted byte-for-byte — and a shared helper that quietly lowercased would change what
232
+ * every one of them produces. A dedup that changes bytes is not a dedup. Lowercase at the call site
233
+ * if that is what you mean.
234
+ */
235
+ export function evmCaip10(chainId, address) {
236
+ return `eip155:${chainId}:${address}`;
237
+ }
3
238
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2EAA2E"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,126 @@
1
+ import type { CanonicalAgentId, Hex32 } from './index.js';
2
+ import type { SubjectRef } from './actor-context.js';
3
+ /** How the peer's identity was established. Open-ended: a new transport is an adapter, not a core change. */
4
+ export type PeerAuthMethod =
5
+ /** Web PKI server certificate. Authenticates a HOSTNAME, not an agent. */
6
+ 'web-pki'
7
+ /** Mutual TLS with a client certificate. */
8
+ | 'mtls'
9
+ /** SPIFFE/SPIRE workload identity. */
10
+ | 'spiffe'
11
+ /** An OAuth/OIDC bearer presented at the transport edge. An envelope, never authority (ADR-0041). */
12
+ | 'oauth'
13
+ /** A shared MAC between internal services. Authenticates a DEPLOYMENT, not a principal. */
14
+ | 'service-mac'
15
+ /** DIDComm peer authentication. */
16
+ | 'didcomm'
17
+ /** DNTLS transport peer authentication (not implemented; reserved so adapters can report it). */
18
+ | 'dntls'
19
+ /** An AP challenge signed by the peer's Smart Agent — the only method that authenticates an SA. */
20
+ | 'ap-signed-challenge' | (string & {});
21
+ /**
22
+ * How strongly the peer is authenticated — deliberately NOT a single boolean.
23
+ *
24
+ * The distinction that matters: `host` means "a hostname was verified" (Web PKI), which is what most
25
+ * deployments actually have and is a much weaker claim than "this Smart Agent is on the other end".
26
+ * Collapsing those into `verified: true` is how a TLS certificate ends up being treated as agent
27
+ * identity.
28
+ */
29
+ export type PeerAuthStrength =
30
+ /** Nothing was verified. The default, and what every unconfigured path must report. */
31
+ 'none'
32
+ /** A hostname/deployment was verified. Says nothing about WHICH agent is behind it. */
33
+ | 'host'
34
+ /** A workload/instance identity was verified (SPIFFE, mTLS client cert). */
35
+ | 'workload'
36
+ /** The peer proved control of its canonical Smart Agent. */
37
+ | 'agent';
38
+ /**
39
+ * Binds an application-layer proof to the channel it arrived on.
40
+ *
41
+ * Without this, a signature captured from one connection can be replayed on another — which is the
42
+ * substantive half of the DNTLS thesis. Presence of a binding is what lets a verifier say "this proof
43
+ * was made FOR this channel", not merely "this proof is valid somewhere".
44
+ */
45
+ export interface ChannelBinding {
46
+ /** e.g. `tls-exporter` (RFC 9266), `tls-server-end-point`, `dntls-session`. */
47
+ method: 'tls-exporter' | 'tls-server-end-point' | 'dntls-session' | (string & {});
48
+ /** The binding value the application proof must commit to. */
49
+ value: Hex32 | string;
50
+ }
51
+ /** A key the peer proved control of on this channel. */
52
+ export interface PeerKeyBinding {
53
+ keyId?: string;
54
+ algorithm?: string;
55
+ /** Thumbprint (e.g. JWK `jkt`, cert `x5t#S256`). */
56
+ thumbprint: string;
57
+ }
58
+ /**
59
+ * What a transport adapter verified about the peer.
60
+ *
61
+ * Produced at Ring 1 (a Worker, a gateway, a mesh sidecar); consumed by `a2a` / `mcp-runtime` /
62
+ * `audit` without knowing the producer.
63
+ */
64
+ export interface VerifiedPeerContextV1 {
65
+ specVersion: 'ap.verified-peer-context/1';
66
+ method: PeerAuthMethod;
67
+ strength: PeerAuthStrength;
68
+ /**
69
+ * The peer as identified by the transport. `caip10` ONLY when `strength: 'agent'` — a hostname or
70
+ * workload id must not be reported as a Smart Agent, which is precisely the conflation this type
71
+ * exists to prevent.
72
+ */
73
+ peer?: SubjectRef;
74
+ /** Present only when the transport authenticated the canonical Smart Agent itself. */
75
+ canonicalAgentId?: CanonicalAgentId;
76
+ keyBinding?: PeerKeyBinding;
77
+ channelBinding?: ChannelBinding;
78
+ /** Where the underlying evidence lives (cert chain, SVID, resolution receipt). Never inlined. */
79
+ evidenceRefs?: readonly string[];
80
+ observedAt: string;
81
+ /** When this context stops being usable. A long-lived connection MUST be re-evaluated. */
82
+ expiresAt?: string;
83
+ }
84
+ /** The context an unconfigured or unauthenticated path MUST report. Never omit the field instead. */
85
+ export declare const UNAUTHENTICATED_PEER: Omit<VerifiedPeerContextV1, 'observedAt'>;
86
+ /** True when the peer context meets a minimum strength. Use this rather than comparing strings. */
87
+ export declare function meetsPeerStrength(actual: PeerAuthStrength, minimum: PeerAuthStrength): boolean;
88
+ /**
89
+ * True only when the transport authenticated the CANONICAL SMART AGENT — the one condition under
90
+ * which peer context may be treated as agent identity at all.
91
+ *
92
+ * Even then it is identity, not authority: an authenticated peer must still be separately authorized
93
+ * to act, by the authority chain re-run at the origin.
94
+ */
95
+ export declare function isAgentAuthenticatedPeer(ctx: VerifiedPeerContextV1): ctx is VerifiedPeerContextV1 & {
96
+ canonicalAgentId: CanonicalAgentId;
97
+ };
98
+ /**
99
+ * True when the peer proof is bound to THIS channel — i.e. it cannot be replayed on another
100
+ * connection by a relay that holds a valid certificate for the host.
101
+ *
102
+ * SEPARATE FROM `isAgentAuthenticatedPeer` ON PURPOSE. Those answer different questions:
103
+ * - `isAgentAuthenticatedPeer` → WHO is at the other end.
104
+ * - `isChannelBoundPeer` → is that answer tied to THIS connection.
105
+ *
106
+ * A nonce-signed challenge proves control of a Smart Agent, so it earns `strength: 'agent'`. It does
107
+ * NOT, on its own, stop an active relay: a party that terminates TLS for the host can forward the
108
+ * challenge and the signature. Only a channel binding closes that, which is the substantive half of
109
+ * the DNTLS thesis (dntls-comparison.md §0.3 item 1).
110
+ *
111
+ * A consumer that cares about relay resistance MUST check this, not just strength.
112
+ */
113
+ export declare function isChannelBoundPeer(ctx: VerifiedPeerContextV1): boolean;
114
+ /** Structural coherence problems — combinations that would misreport what was verified. */
115
+ export interface PeerContextViolation {
116
+ field: string;
117
+ message: string;
118
+ }
119
+ /**
120
+ * Validate a peer context.
121
+ *
122
+ * Every rule here guards the same failure: a transport reporting a stronger claim than it actually
123
+ * verified, which downstream code would then trust as agent identity.
124
+ */
125
+ export declare function validatePeerContext(ctx: VerifiedPeerContextV1): PeerContextViolation[];
126
+ //# sourceMappingURL=verified-peer-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verified-peer-context.d.ts","sourceRoot":"","sources":["../src/verified-peer-context.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,6GAA6G;AAC7G,MAAM,MAAM,cAAc;AACxB,0EAA0E;AACxE,SAAS;AACX,4CAA4C;GAC1C,MAAM;AACR,sCAAsC;GACpC,QAAQ;AACV,qGAAqG;GACnG,OAAO;AACT,2FAA2F;GACzF,aAAa;AACf,mCAAmC;GACjC,SAAS;AACX,iGAAiG;GAC/F,OAAO;AACT,mGAAmG;GACjG,qBAAqB,GACrB,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB;AAC1B,uFAAuF;AACrF,MAAM;AACR,uFAAuF;GACrF,MAAM;AACR,4EAA4E;GAC1E,UAAU;AACZ,4DAA4D;GAC1D,OAAO,CAAC;AAEZ;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,+EAA+E;IAC/E,MAAM,EAAE,cAAc,GAAG,sBAAsB,GAAG,eAAe,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAClF,8DAA8D;IAC9D,KAAK,EAAE,KAAK,GAAG,MAAM,CAAC;CACvB;AAED,wDAAwD;AACxD,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,4BAA4B,CAAC;IAE1C,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,gBAAgB,CAAC;IAE3B;;;;OAIG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAElB,sFAAsF;IACtF,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAEpC,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC,iGAAiG;IACjG,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEjC,UAAU,EAAE,MAAM,CAAC;IACnB,0FAA0F;IAC1F,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qGAAqG;AACrG,eAAO,MAAM,oBAAoB,EAAE,IAAI,CAAC,qBAAqB,EAAE,YAAY,CAI1E,CAAC;AAIF,mGAAmG;AACnG,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAE9F;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,qBAAqB,GACzB,GAAG,IAAI,qBAAqB,GAAG;IAAE,gBAAgB,EAAE,gBAAgB,CAAA;CAAE,CAOvE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAEtE;AAED,2FAA2F;AAC3F,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,qBAAqB,GAAG,oBAAoB,EAAE,CAkCtF"}
@@ -0,0 +1,105 @@
1
+ // Verified peer context — the transport-layer "who is at the other end of this connection?"
2
+ // (dntls-comparison.md §17 P1; spec 338 W5).
3
+ //
4
+ // THE GAP THIS NAMES: before A2A/MCP parse a byte, peer trust in this substrate has usually collapsed
5
+ // to Web PKI, a hosting provider, an OAuth bearer, or a service MAC (dntls-comparison.md §0.3 item 1).
6
+ // App-layer signatures are NOT channel binding — they prove a message was authored, not that the
7
+ // party you are speaking to is the party that authored it.
8
+ //
9
+ // This type does not close that gap. It gives the gap a SHAPE, so a transport adapter can report what
10
+ // it actually verified, and so `a2a`/`mcp-runtime` can consume peer identity WITHOUT knowing which
11
+ // mechanism produced it (Web PKI today, SPIFFE/mTLS in a mesh, DNTLS if it ever ships).
12
+ //
13
+ // ─── THE RULE THAT MAKES THIS SAFE ──────────────────────────────────────────────────────────────
14
+ // Verified peer context is IDENTITY, never AUTHORITY.
15
+ //
16
+ // Knowing who connected never implies what they may do. It does not substitute for ANY link in the
17
+ // authority chain, and it is never an input that *widens* one (ADR-0041, ADR-0043, ADR-0056). Its
18
+ // legitimate uses are: binding an app-layer proof to the channel it arrived on, admission decisions
19
+ // at the edge, audit evidence, and policy PREDICATES an authority decision may CONSULT — never
20
+ // replace.
21
+ //
22
+ // (The authority-chain packages are named in their own docs; this file deliberately does not use
23
+ // their vocabulary — `types` is a shared leaf and must not borrow a neighbour's terms.)
24
+ /** The context an unconfigured or unauthenticated path MUST report. Never omit the field instead. */
25
+ export const UNAUTHENTICATED_PEER = {
26
+ specVersion: 'ap.verified-peer-context/1',
27
+ method: 'web-pki',
28
+ strength: 'none',
29
+ };
30
+ const STRENGTH_RANK = { none: 0, host: 1, workload: 2, agent: 3 };
31
+ /** True when the peer context meets a minimum strength. Use this rather than comparing strings. */
32
+ export function meetsPeerStrength(actual, minimum) {
33
+ return STRENGTH_RANK[actual] >= STRENGTH_RANK[minimum];
34
+ }
35
+ /**
36
+ * True only when the transport authenticated the CANONICAL SMART AGENT — the one condition under
37
+ * which peer context may be treated as agent identity at all.
38
+ *
39
+ * Even then it is identity, not authority: an authenticated peer must still be separately authorized
40
+ * to act, by the authority chain re-run at the origin.
41
+ */
42
+ export function isAgentAuthenticatedPeer(ctx) {
43
+ return (ctx.strength === 'agent' &&
44
+ typeof ctx.canonicalAgentId === 'string' &&
45
+ ctx.peer?.scheme === 'caip10' &&
46
+ ctx.peer.id === ctx.canonicalAgentId);
47
+ }
48
+ /**
49
+ * True when the peer proof is bound to THIS channel — i.e. it cannot be replayed on another
50
+ * connection by a relay that holds a valid certificate for the host.
51
+ *
52
+ * SEPARATE FROM `isAgentAuthenticatedPeer` ON PURPOSE. Those answer different questions:
53
+ * - `isAgentAuthenticatedPeer` → WHO is at the other end.
54
+ * - `isChannelBoundPeer` → is that answer tied to THIS connection.
55
+ *
56
+ * A nonce-signed challenge proves control of a Smart Agent, so it earns `strength: 'agent'`. It does
57
+ * NOT, on its own, stop an active relay: a party that terminates TLS for the host can forward the
58
+ * challenge and the signature. Only a channel binding closes that, which is the substantive half of
59
+ * the DNTLS thesis (dntls-comparison.md §0.3 item 1).
60
+ *
61
+ * A consumer that cares about relay resistance MUST check this, not just strength.
62
+ */
63
+ export function isChannelBoundPeer(ctx) {
64
+ return isAgentAuthenticatedPeer(ctx) && ctx.channelBinding !== undefined;
65
+ }
66
+ /**
67
+ * Validate a peer context.
68
+ *
69
+ * Every rule here guards the same failure: a transport reporting a stronger claim than it actually
70
+ * verified, which downstream code would then trust as agent identity.
71
+ */
72
+ export function validatePeerContext(ctx) {
73
+ const out = [];
74
+ if (ctx.strength === 'agent') {
75
+ if (!ctx.canonicalAgentId) {
76
+ out.push({ field: 'canonicalAgentId', message: 'strength "agent" requires the canonical Smart Agent it authenticated' });
77
+ }
78
+ if (ctx.peer && ctx.peer.scheme !== 'caip10') {
79
+ out.push({ field: 'peer', message: 'strength "agent" requires a caip10 peer — a hostname or workload id is not a Smart Agent' });
80
+ }
81
+ if (ctx.peer?.scheme === 'caip10' && ctx.canonicalAgentId && ctx.peer.id !== ctx.canonicalAgentId) {
82
+ out.push({ field: 'peer', message: 'peer id and canonicalAgentId disagree' });
83
+ }
84
+ }
85
+ else if (ctx.canonicalAgentId) {
86
+ // The core conflation: reporting an SA that the transport did not actually authenticate.
87
+ out.push({
88
+ field: 'canonicalAgentId',
89
+ message: `strength "${ctx.strength}" must not carry a canonicalAgentId — only "agent" authenticates a Smart Agent`,
90
+ });
91
+ }
92
+ if (ctx.strength === 'none' && (ctx.keyBinding || ctx.channelBinding)) {
93
+ out.push({ field: 'strength', message: 'strength "none" must not report key or channel bindings' });
94
+ }
95
+ if (!Number.isNaN(Date.parse(ctx.observedAt)) && ctx.expiresAt) {
96
+ if (Date.parse(ctx.expiresAt) <= Date.parse(ctx.observedAt)) {
97
+ out.push({ field: 'expiresAt', message: 'expiresAt must be after observedAt' });
98
+ }
99
+ }
100
+ else if (Number.isNaN(Date.parse(ctx.observedAt))) {
101
+ out.push({ field: 'observedAt', message: 'observedAt must be a parseable ISO-8601 timestamp' });
102
+ }
103
+ return out;
104
+ }
105
+ //# sourceMappingURL=verified-peer-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verified-peer-context.js","sourceRoot":"","sources":["../src/verified-peer-context.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,17 +1,21 @@
1
1
  {
2
2
  "name": "@agenticprimitives/types",
3
- "version": "1.0.0-alpha.4",
3
+ "version": "1.0.0-alpha.41",
4
4
  "description": "Cross-cutting branded types and chain primitives shared across @agenticprimitives/* packages.",
5
+ "homepage": "https://agenticprimitives.dev",
6
+ "bugs": {
7
+ "url": "https://github.com/agentictrustlabs/agenticprimitives/issues"
8
+ },
9
+ "author": {
10
+ "name": "Agentic Trust Labs",
11
+ "url": "https://agenticprimitives.dev"
12
+ },
5
13
  "license": "MIT",
6
14
  "repository": {
7
15
  "type": "git",
8
16
  "url": "git+https://github.com/agentictrustlabs/agenticprimitives.git",
9
17
  "directory": "packages/types"
10
18
  },
11
- "homepage": "https://github.com/agentictrustlabs/agenticprimitives/tree/master/packages/types",
12
- "bugs": {
13
- "url": "https://github.com/agentictrustlabs/agenticprimitives/issues"
14
- },
15
19
  "type": "module",
16
20
  "main": "./dist/index.js",
17
21
  "types": "./dist/index.d.ts",
@@ -32,12 +36,21 @@
32
36
  },
33
37
  "keywords": [
34
38
  "types",
35
- "agentic"
39
+ "agentic",
40
+ "agentic-primitives",
41
+ "agenticprimitives",
42
+ "ai-agents",
43
+ "agent-authority",
44
+ "agentic-trust"
36
45
  ],
46
+ "devDependencies": {
47
+ "vitest": "^4.1.11"
48
+ },
37
49
  "scripts": {
38
50
  "build": "tsc -p tsconfig.build.json",
39
51
  "typecheck": "tsc -p tsconfig.json --noEmit",
40
- "test": "echo 'no tests yet' && exit 0",
41
- "clean": "rm -rf dist"
52
+ "test": "vitest run",
53
+ "clean": "rm -rf dist",
54
+ "test:unit": "vitest run test/unit --passWithNoTests"
42
55
  }
43
56
  }