@agenticprimitives/identity-directory 0.1.0-alpha.2
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/LICENSE +21 -0
- package/README.md +48 -0
- package/dist/directory.d.ts +5 -0
- package/dist/directory.d.ts.map +1 -0
- package/dist/directory.js +112 -0
- package/dist/directory.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +101 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +27 -0
- package/dist/types.js.map +1 -0
- package/package.json +57 -0
- package/spec.md +16 -0
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,48 @@
|
|
|
1
|
+
# @agenticprimitives/identity-directory
|
|
2
|
+
|
|
3
|
+
An **evidence-backed read model** over canonical agents and their facets — the
|
|
4
|
+
read side of the identity stack ([ADR-0015](../../docs/architecture/decisions/0015-identity-directory-is-an-evidence-backed-read-model.md);
|
|
5
|
+
[spec 223](../../specs/223-identity-directory.md)).
|
|
6
|
+
|
|
7
|
+
It answers *"which agent(s) does this name / credential / OIDC subject resolve to,
|
|
8
|
+
and on what evidence?"* — keyed on `CanonicalAgentId` (CAIP-10), with provenance +
|
|
9
|
+
assurance on every association. It is **not an authority**: it accelerates
|
|
10
|
+
discovery; the consumer re-reads on-chain for custody decisions.
|
|
11
|
+
|
|
12
|
+
## Ports + adapters
|
|
13
|
+
|
|
14
|
+
The core declares the ports; the implementations live in
|
|
15
|
+
[`@agenticprimitives/identity-directory-adapters`](../identity-directory-adapters):
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
NamingPort forward/reverse name ↔ agent (wraps agent-naming)
|
|
19
|
+
OnChainReadPort resolveAgent / credentialsOf — readContract only, NEVER getLogs
|
|
20
|
+
IndexerPort agentsByCredential / agentsByOidcSubject — the "indexed registry" home
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { createDirectory } from '@agenticprimitives/identity-directory';
|
|
27
|
+
import { makeAdapters } from '@agenticprimitives/identity-directory-adapters'; // (separate pkg)
|
|
28
|
+
|
|
29
|
+
const dir = createDirectory(makeAdapters({ /* viem client, naming, indexer */ }));
|
|
30
|
+
const r = await dir.resolveByCredential(principal); // 0 | 1 | many agents, each with evidence
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Doctrine (load-bearing)
|
|
34
|
+
|
|
35
|
+
- **No fallback** ([ADR-0013](../../docs/architecture/decisions/0013-no-silent-fallbacks.md)):
|
|
36
|
+
one mechanism per query; a `null`/empty port result is terminal.
|
|
37
|
+
- **No `eth_getLogs`** ([ADR-0012](../../docs/architecture/decisions/0012-no-eth-getlogs-in-product-read-paths.md)):
|
|
38
|
+
indexed reads go through `IndexerPort`.
|
|
39
|
+
- **Indexer proposes, on-chain confirms:** `resolveByCredential` /
|
|
40
|
+
`resolveByOidcSubject` upgrade to `onchain-confirmed` only when the credential is
|
|
41
|
+
in the agent's *current* on-chain set — a revoked credential is dropped.
|
|
42
|
+
- **Not an authority** ([ADR-0015](../../docs/architecture/decisions/0015-identity-directory-is-an-evidence-backed-read-model.md)):
|
|
43
|
+
resolution output never grants custody or value.
|
|
44
|
+
|
|
45
|
+
## Convergence
|
|
46
|
+
|
|
47
|
+
`Resolution.agents.length` is the convergence cardinality the broker (spec 224)
|
|
48
|
+
branches on: **0** → bootstrap, **1** → the common case, **many** → disambiguate.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Assurance } from '@agenticprimitives/types';
|
|
2
|
+
import { type DirectoryPorts, type DirectoryOpts, type IdentityDirectory } from './types';
|
|
3
|
+
export declare function createDirectory(ports: DirectoryPorts, opts?: DirectoryOpts): IdentityDirectory;
|
|
4
|
+
export type { Assurance };
|
|
5
|
+
//# sourceMappingURL=directory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory.d.ts","sourceRoot":"","sources":["../src/directory.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAyC,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACjG,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EAOvB,MAAM,SAAS,CAAC;AAMjB,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,GAAE,aAAkB,GAAG,iBAAiB,CA8FlG;AAGD,YAAY,EAAE,SAAS,EAAE,CAAC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// createDirectory — composes the ports into the query API (spec 223 §6/§7).
|
|
2
|
+
//
|
|
3
|
+
// Discipline (load-bearing):
|
|
4
|
+
// - No fallback (ADR-0013): each query uses ONE mechanism; a null/empty result
|
|
5
|
+
// is terminal — never an escalation to a second port.
|
|
6
|
+
// - Authoritative-port designation (audit P2-4): for session-relevant queries
|
|
7
|
+
// (credential / oidc) the IndexerPort only PROPOSES candidates; the
|
|
8
|
+
// OnChainReadPort is authoritative — a candidate is only `onchain-confirmed`
|
|
9
|
+
// if the credential is in the agent's CURRENT on-chain set. A credential
|
|
10
|
+
// revoked on-chain (spec 221) is dropped, never riding a stale index edge
|
|
11
|
+
// (audit P1-3).
|
|
12
|
+
// - Not an authority (ADR-0015): the directory accelerates discovery; it never
|
|
13
|
+
// grants anything. The broker re-reads on-chain for custody decisions.
|
|
14
|
+
import { buildEvent, nowIso } from '@agenticprimitives/audit';
|
|
15
|
+
import { CLASS, PREDICATE } from '@agenticprimitives/ontology';
|
|
16
|
+
import { maxAssurance, } from './types';
|
|
17
|
+
function oidcPrincipal(iss, sub) {
|
|
18
|
+
return { kind: 'oidc', id: `${iss}#${sub}`, assurance: 'asserted' };
|
|
19
|
+
}
|
|
20
|
+
export function createDirectory(ports, opts = {}) {
|
|
21
|
+
const auditSink = opts.auditSink;
|
|
22
|
+
async function emit(action, subjectId, predicate, resultCount) {
|
|
23
|
+
if (!auditSink)
|
|
24
|
+
return;
|
|
25
|
+
try {
|
|
26
|
+
await auditSink.write(buildEvent({
|
|
27
|
+
action,
|
|
28
|
+
outcome: 'success',
|
|
29
|
+
actor: { type: 'system', id: 'identity-directory' },
|
|
30
|
+
subject: { type: CLASS.Agent, id: subjectId },
|
|
31
|
+
context: { predicate, resultCount },
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
/* audit is fail-soft; never block a read on the sink */
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* For each candidate link, CONFIRM the principal is in the agent's current
|
|
40
|
+
* on-chain credential set. Confirmed → `onchain-confirmed` (with both the
|
|
41
|
+
* indexer evidence and the on-chain confirmation evidence). Unconfirmed
|
|
42
|
+
* (revoked / stale / never-real) → dropped.
|
|
43
|
+
*/
|
|
44
|
+
async function confirmCandidates(links, principal) {
|
|
45
|
+
const out = [];
|
|
46
|
+
for (const link of links) {
|
|
47
|
+
// Authoritative membership CHECK (isCustodian/isTrustee), not enumeration.
|
|
48
|
+
if (!(await ports.onChain.confirmsCredential(link.agent, principal)))
|
|
49
|
+
continue; // not currently a custodian → drop
|
|
50
|
+
const evidence = [
|
|
51
|
+
{
|
|
52
|
+
source: 'indexer',
|
|
53
|
+
assurance: link.assurance,
|
|
54
|
+
observedAt: link.observedAt ?? nowIso(),
|
|
55
|
+
ref: link.ref,
|
|
56
|
+
blockNumber: link.blockNumber,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
source: 'onchain',
|
|
60
|
+
assurance: 'onchain-confirmed',
|
|
61
|
+
observedAt: nowIso(),
|
|
62
|
+
ref: `credentialsOf:${link.agent}`,
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
out.push({ id: link.agent, evidence, assurance: maxAssurance(evidence.map((e) => e.assurance)) });
|
|
66
|
+
}
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
async resolveByName(name) {
|
|
71
|
+
const id = await ports.naming.forward(name);
|
|
72
|
+
// null is THE answer (no such name) — never escalate to another port (ADR-0013).
|
|
73
|
+
if (!id) {
|
|
74
|
+
await emit('identity-directory.resolveByName', name, PREDICATE.resolvesTo, 0);
|
|
75
|
+
return { agents: [] };
|
|
76
|
+
}
|
|
77
|
+
const evidence = [
|
|
78
|
+
{ source: 'naming', assurance: 'onchain-read', observedAt: nowIso(), ref: name },
|
|
79
|
+
];
|
|
80
|
+
await emit('identity-directory.resolveByName', name, PREDICATE.resolvesTo, 1);
|
|
81
|
+
return { agents: [{ id, evidence, assurance: 'onchain-read' }] };
|
|
82
|
+
},
|
|
83
|
+
async resolveByCredential(principal) {
|
|
84
|
+
const links = await ports.indexer.agentsByCredential(principal);
|
|
85
|
+
const agents = await confirmCandidates(links, principal);
|
|
86
|
+
await emit('identity-directory.resolveByCredential', `${principal.kind}:${principal.id}`, PREDICATE.controls, agents.length);
|
|
87
|
+
return { agents };
|
|
88
|
+
},
|
|
89
|
+
async resolveByOidcSubject(iss, sub) {
|
|
90
|
+
const links = await ports.indexer.agentsByOidcSubject(iss, sub);
|
|
91
|
+
const agents = await confirmCandidates(links, oidcPrincipal(iss, sub));
|
|
92
|
+
await emit('identity-directory.resolveByOidcSubject', `${iss}#${sub}`, PREDICATE.controls, agents.length);
|
|
93
|
+
return { agents };
|
|
94
|
+
},
|
|
95
|
+
async agent(id) {
|
|
96
|
+
if (!(await ports.onChain.exists(id)))
|
|
97
|
+
return null;
|
|
98
|
+
// Composition (NOT fallback): existence + reverse name are different facets
|
|
99
|
+
// of the SAME agent, each from its declared port. (Credential enumeration is
|
|
100
|
+
// not an on-chain primitive — confirmation is per-credential via the membership
|
|
101
|
+
// check; a full credential list, if ever needed, is an indexer concern.)
|
|
102
|
+
const name = await ports.naming.reverse(id);
|
|
103
|
+
const evidence = [
|
|
104
|
+
{ source: 'onchain', assurance: 'onchain-read', observedAt: nowIso(), ref: `exists:${id}` },
|
|
105
|
+
];
|
|
106
|
+
if (name)
|
|
107
|
+
evidence.push({ source: 'naming', assurance: 'onchain-read', observedAt: nowIso(), ref: name });
|
|
108
|
+
return { id, facets: { name: name ?? undefined }, evidence };
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=directory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory.js","sourceRoot":"","sources":["../src/directory.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type { EvidenceSource, Evidence, AgentWithEvidence, Resolution, AgentView, EvidenceLink, OnChainReadPort, NamingPort, IndexerPort, DirectoryPorts, DirectoryOpts, IdentityDirectory, } from './types';
|
|
2
|
+
export { ASSURANCE_ORDER, compareAssurance, maxAssurance } from './types';
|
|
3
|
+
export { createDirectory } from './directory';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,YAAY,EACV,cAAc,EACd,QAAQ,EACR,iBAAiB,EACjB,UAAU,EACV,SAAS,EACT,YAAY,EACZ,eAAe,EACf,UAAU,EACV,WAAW,EACX,cAAc,EACd,aAAa,EACb,iBAAiB,GAClB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE1E,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// @agenticprimitives/identity-directory — evidence-backed read model (spec 223).
|
|
2
|
+
//
|
|
3
|
+
// Public surface: the domain model, the ports (implemented in
|
|
4
|
+
// identity-directory-adapters), the assurance ordering, and createDirectory.
|
|
5
|
+
//
|
|
6
|
+
// See:
|
|
7
|
+
// - capability.manifest.json — boundary (types + audit + ontology only)
|
|
8
|
+
// - ../../specs/223-identity-directory.md — the contract
|
|
9
|
+
// - ../../docs/architecture/decisions/0015-identity-directory-is-an-evidence-backed-read-model.md
|
|
10
|
+
export { ASSURANCE_ORDER, compareAssurance, maxAssurance } from './types';
|
|
11
|
+
export { createDirectory } from './directory';
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,EAAE;AACF,8DAA8D;AAC9D,6EAA6E;AAC7E,EAAE;AACF,OAAO;AACP,0EAA0E;AAC1E,2DAA2D;AAC3D,oGAAoG;AAiBpG,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE1E,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { CanonicalAgentId, Assurance, CredentialPrincipal } from '@agenticprimitives/types';
|
|
2
|
+
export type { CanonicalAgentId, Assurance, CredentialPrincipal };
|
|
3
|
+
/** Which source asserted an association. */
|
|
4
|
+
export type EvidenceSource = 'naming' | 'onchain' | 'indexer';
|
|
5
|
+
/**
|
|
6
|
+
* Provenance for an asserted association (spec 223 §4). `blockNumber` is present
|
|
7
|
+
* and load-bearing for `onchain-read` evidence so a consumer can enforce a
|
|
8
|
+
* max-staleness bound (audit P1-3) — a credential revoked on-chain must not ride
|
|
9
|
+
* a stale read.
|
|
10
|
+
*/
|
|
11
|
+
export interface Evidence {
|
|
12
|
+
source: EvidenceSource;
|
|
13
|
+
observedAt: string;
|
|
14
|
+
assurance: Assurance;
|
|
15
|
+
/** Opaque source reference (name, tx, index key, "credentialsOf:<id>", …). */
|
|
16
|
+
ref: string;
|
|
17
|
+
/** Required for `onchain-read`/`onchain-confirmed`; the block the read reflects. */
|
|
18
|
+
blockNumber?: bigint;
|
|
19
|
+
}
|
|
20
|
+
/** An agent in a Resolution, with its provenance + the effective assurance. */
|
|
21
|
+
export interface AgentWithEvidence {
|
|
22
|
+
id: CanonicalAgentId;
|
|
23
|
+
evidence: Evidence[];
|
|
24
|
+
/** Highest assurance across `evidence`. */
|
|
25
|
+
assurance: Assurance;
|
|
26
|
+
}
|
|
27
|
+
/** The result of a resolution query. Convergence cardinality is `agents.length`. */
|
|
28
|
+
export interface Resolution {
|
|
29
|
+
agents: AgentWithEvidence[];
|
|
30
|
+
}
|
|
31
|
+
/** A view of one agent + provenance (from `agent(id)`). */
|
|
32
|
+
export interface AgentView {
|
|
33
|
+
id: CanonicalAgentId;
|
|
34
|
+
facets: {
|
|
35
|
+
name?: string;
|
|
36
|
+
};
|
|
37
|
+
evidence: Evidence[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A candidate link from a (non-authoritative) IndexerPort. The directory
|
|
41
|
+
* CONFIRMS it against the authoritative on-chain read before treating it as
|
|
42
|
+
* `onchain-confirmed` (audit P2-4 / P1-3).
|
|
43
|
+
*/
|
|
44
|
+
export interface EvidenceLink {
|
|
45
|
+
agent: CanonicalAgentId;
|
|
46
|
+
assurance: Assurance;
|
|
47
|
+
ref: string;
|
|
48
|
+
observedAt?: string;
|
|
49
|
+
blockNumber?: bigint;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Authoritative on-chain reads. `readContract` only — NEVER `eth_getLogs`.
|
|
53
|
+
*
|
|
54
|
+
* Shaped around what the custody/account contracts actually expose: membership
|
|
55
|
+
* CHECKS (`isCustodian`/`isTrustee`), not credential enumeration. So confirmation
|
|
56
|
+
* is `confirmsCredential` (a check), not a `credentialsOf` (a list) — the on-chain
|
|
57
|
+
* surface has no "list this agent's credentials" getter.
|
|
58
|
+
*/
|
|
59
|
+
export interface OnChainReadPort {
|
|
60
|
+
/** Does this agent exist as a deployed account on this chain? */
|
|
61
|
+
exists(id: CanonicalAgentId): Promise<boolean>;
|
|
62
|
+
/** Authoritative: is `principal` CURRENTLY a control credential of `id`? */
|
|
63
|
+
confirmsCredential(id: CanonicalAgentId, principal: CredentialPrincipal): Promise<boolean>;
|
|
64
|
+
}
|
|
65
|
+
/** Wraps `agent-naming`. The adapter lifts `Address → CanonicalAgentId` by binding a chainId. */
|
|
66
|
+
export interface NamingPort {
|
|
67
|
+
forward(name: string): Promise<CanonicalAgentId | null>;
|
|
68
|
+
reverse(id: CanonicalAgentId): Promise<string | null>;
|
|
69
|
+
}
|
|
70
|
+
/** The home for "indexed registry" reads (HCS-2 *indexed* → here, never a log walk). */
|
|
71
|
+
export interface IndexerPort {
|
|
72
|
+
agentsByCredential(principal: CredentialPrincipal): Promise<EvidenceLink[]>;
|
|
73
|
+
agentsByOidcSubject(iss: string, sub: string): Promise<EvidenceLink[]>;
|
|
74
|
+
}
|
|
75
|
+
export interface DirectoryPorts {
|
|
76
|
+
naming: NamingPort;
|
|
77
|
+
onChain: OnChainReadPort;
|
|
78
|
+
indexer: IndexerPort;
|
|
79
|
+
}
|
|
80
|
+
import type { AuditSink } from '@agenticprimitives/audit';
|
|
81
|
+
export interface DirectoryOpts {
|
|
82
|
+
/** Injectable clock (ms). Defaults to Date.now. */
|
|
83
|
+
now?: () => number;
|
|
84
|
+
/** Optional sink — a `identity-directory.resolve` event is emitted per query. */
|
|
85
|
+
auditSink?: AuditSink;
|
|
86
|
+
}
|
|
87
|
+
/** The directory query API (spec 223 §6). */
|
|
88
|
+
export interface IdentityDirectory {
|
|
89
|
+
resolveByName(name: string): Promise<Resolution>;
|
|
90
|
+
/** Session-relevant: indexer proposes, on-chain CONFIRMS (audit P2-4/P1-3). */
|
|
91
|
+
resolveByCredential(principal: CredentialPrincipal): Promise<Resolution>;
|
|
92
|
+
resolveByOidcSubject(iss: string, sub: string): Promise<Resolution>;
|
|
93
|
+
agent(id: CanonicalAgentId): Promise<AgentView | null>;
|
|
94
|
+
}
|
|
95
|
+
/** Ordered low→high. Consumers (e.g. the broker session-issuance floor) compare on this. */
|
|
96
|
+
export declare const ASSURANCE_ORDER: readonly Assurance[];
|
|
97
|
+
/** Negative / 0 / positive like a comparator. */
|
|
98
|
+
export declare function compareAssurance(a: Assurance, b: Assurance): number;
|
|
99
|
+
/** The highest assurance across a non-empty list (defaults to 'unverified' if empty). */
|
|
100
|
+
export declare function maxAssurance(values: Assurance[]): Assurance;
|
|
101
|
+
//# 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,27 @@
|
|
|
1
|
+
// Domain model + ports for the identity directory (spec 223).
|
|
2
|
+
//
|
|
3
|
+
// The directory is a READ MODEL keyed on CanonicalAgentId. Every association it
|
|
4
|
+
// returns carries Evidence (provenance + assurance). It is NOT an authority
|
|
5
|
+
// (ADR-0015), uses no eth_getLogs (ADR-0012), and never falls back between
|
|
6
|
+
// mechanisms (ADR-0013).
|
|
7
|
+
// ─── Assurance ordering ───────────────────────────────────────────────
|
|
8
|
+
/** Ordered low→high. Consumers (e.g. the broker session-issuance floor) compare on this. */
|
|
9
|
+
export const ASSURANCE_ORDER = [
|
|
10
|
+
'unverified',
|
|
11
|
+
'asserted',
|
|
12
|
+
'onchain-read',
|
|
13
|
+
'onchain-confirmed',
|
|
14
|
+
];
|
|
15
|
+
/** Negative / 0 / positive like a comparator. */
|
|
16
|
+
export function compareAssurance(a, b) {
|
|
17
|
+
return ASSURANCE_ORDER.indexOf(a) - ASSURANCE_ORDER.indexOf(b);
|
|
18
|
+
}
|
|
19
|
+
/** The highest assurance across a non-empty list (defaults to 'unverified' if empty). */
|
|
20
|
+
export function maxAssurance(values) {
|
|
21
|
+
let best = 'unverified';
|
|
22
|
+
for (const v of values)
|
|
23
|
+
if (compareAssurance(v, best) > 0)
|
|
24
|
+
best = v;
|
|
25
|
+
return best;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,gFAAgF;AAChF,4EAA4E;AAC5E,2EAA2E;AAC3E,yBAAyB;AAsHzB,yEAAyE;AAEzE,4FAA4F;AAC5F,MAAM,CAAC,MAAM,eAAe,GAAyB;IACnD,YAAY;IACZ,UAAU;IACV,cAAc;IACd,mBAAmB;CACX,CAAC;AAEX,iDAAiD;AACjD,MAAM,UAAU,gBAAgB,CAAC,CAAY,EAAE,CAAY;IACzD,OAAO,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,YAAY,CAAC,MAAmB;IAC9C,IAAI,IAAI,GAAc,YAAY,CAAC;IACnC,KAAK,MAAM,CAAC,IAAI,MAAM;QAAE,IAAI,gBAAgB,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC;YAAE,IAAI,GAAG,CAAC,CAAC;IACpE,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agenticprimitives/identity-directory",
|
|
3
|
+
"version": "0.1.0-alpha.2",
|
|
4
|
+
"description": "Evidence-backed read model over canonical agents and their facets (ADR-0015 / spec 223). Declares the ports (NamingPort / OnChainReadPort / IndexerPort) + the query API with provenance + assurance. Not an authority; no eth_getLogs; no fallback. Adapters live in identity-directory-adapters.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/agentictrustlabs/agenticprimitives.git",
|
|
9
|
+
"directory": "packages/identity-directory"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/agentictrustlabs/agenticprimitives/tree/master/packages/identity-directory",
|
|
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
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"LICENSE",
|
|
26
|
+
"dist",
|
|
27
|
+
"spec.md",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc -p tsconfig.build.json",
|
|
32
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
33
|
+
"test": "vitest run",
|
|
34
|
+
"test:unit": "vitest run test/unit",
|
|
35
|
+
"test:integration": "vitest run test/integration --passWithNoTests",
|
|
36
|
+
"test:watch": "vitest",
|
|
37
|
+
"clean": "rm -rf dist"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"@agenticprimitives/audit": "workspace:*",
|
|
44
|
+
"@agenticprimitives/ontology": "workspace:*",
|
|
45
|
+
"@agenticprimitives/types": "workspace:*"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"vitest": "^2.1.0"
|
|
49
|
+
},
|
|
50
|
+
"keywords": [
|
|
51
|
+
"identity",
|
|
52
|
+
"directory",
|
|
53
|
+
"read-model",
|
|
54
|
+
"knowledge-graph",
|
|
55
|
+
"agentic"
|
|
56
|
+
]
|
|
57
|
+
}
|
package/spec.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Spec — @agenticprimitives/identity-directory
|
|
2
|
+
|
|
3
|
+
The authoritative spec is [`specs/223-identity-directory.md`](../../specs/223-identity-directory.md)
|
|
4
|
+
(domain model, ports, query API + convergence, doctrine compliance, phased plan).
|
|
5
|
+
|
|
6
|
+
Decision record: [ADR-0015 — identity-directory is an evidence-backed read model](../../docs/architecture/decisions/0015-identity-directory-is-an-evidence-backed-read-model.md).
|
|
7
|
+
Conforms to the ontology in [spec 225](../../specs/225-ontology.md); keys on the
|
|
8
|
+
CAIP-10 `CanonicalAgentId` of [ADR-0016](../../docs/architecture/decisions/0016-canonical-agent-id-is-the-sso-subject.md).
|
|
9
|
+
|
|
10
|
+
This file is the per-package pointer required by `check:package-docs`; do not
|
|
11
|
+
duplicate the spec here — edit spec 223.
|
|
12
|
+
|
|
13
|
+
> Reconciliation note: spec 223 §5 sketched an `OidcPort`; OIDC *verification*
|
|
14
|
+
> lives in `connect-auth` (ADR-0017), so the directory core ships three ports
|
|
15
|
+
> (Naming / OnChainRead / Indexer) and `resolveByOidcSubject(iss, sub)` takes an
|
|
16
|
+
> already-verified subject. The broker wires connect-auth → directory.
|