@vallum/registry 0.0.0-prerelease
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 +36 -0
- package/dist/a2aCard.d.ts +149 -0
- package/dist/a2aCard.js +387 -0
- package/dist/a2aDiscoveryBundle.d.ts +53 -0
- package/dist/a2aDiscoveryBundle.js +326 -0
- package/dist/a2aJwks.d.ts +37 -0
- package/dist/a2aJwks.js +102 -0
- package/dist/a2aWellKnown.d.ts +28 -0
- package/dist/a2aWellKnown.js +58 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +9 -0
- package/dist/iotaIdentityAdapter.d.ts +92 -0
- package/dist/iotaIdentityAdapter.js +329 -0
- package/dist/iotaNamesAdapter.d.ts +49 -0
- package/dist/iotaNamesAdapter.js +188 -0
- package/dist/profileSchema.d.ts +76 -0
- package/dist/profileSchema.js +187 -0
- package/dist/resolveAgent.d.ts +26 -0
- package/dist/resolveAgent.js +63 -0
- package/package.json +32 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
export const AGENT_PROFILE_VERSION = "agent-profile/v1";
|
|
2
|
+
export function validAgentProfileFixture() {
|
|
3
|
+
return {
|
|
4
|
+
version: AGENT_PROFILE_VERSION,
|
|
5
|
+
name: "researcher.demo.iota",
|
|
6
|
+
agentDid: "did:iota:agent:researcher-demo",
|
|
7
|
+
ownerDid: "did:iota:owner:research-team",
|
|
8
|
+
wallet: {
|
|
9
|
+
walletId: "wallet_researcher_demo",
|
|
10
|
+
address: "0x1111111111111111111111111111111111111111111111111111111111111111",
|
|
11
|
+
signerRef: "signer_ref_researcher_demo",
|
|
12
|
+
creationSource: "agent_created",
|
|
13
|
+
status: "active",
|
|
14
|
+
},
|
|
15
|
+
capabilities: [{
|
|
16
|
+
id: "research.summary",
|
|
17
|
+
displayName: "Research summary",
|
|
18
|
+
contracts: ["escrow:v1"],
|
|
19
|
+
scopes: ["contract:escrow", "action:open_escrow"],
|
|
20
|
+
credentialRefs: ["credential:research-summary:v1"],
|
|
21
|
+
}],
|
|
22
|
+
endpoints: [
|
|
23
|
+
{ type: "mcp", url: "https://agent.example.test/mcp" },
|
|
24
|
+
{ type: "agent_card", url: "https://agent.example.test/.well-known/agent-card.json" },
|
|
25
|
+
],
|
|
26
|
+
credentialRefs: ["credential:research-summary:v1"],
|
|
27
|
+
supportedContracts: [{
|
|
28
|
+
id: "escrow:v1",
|
|
29
|
+
packageId: "0x2222222222222222222222222222222222222222222222222222222222222222",
|
|
30
|
+
module: "escrow",
|
|
31
|
+
functionName: "open_escrow",
|
|
32
|
+
}],
|
|
33
|
+
paymentMethods: [{
|
|
34
|
+
type: "iota",
|
|
35
|
+
asset: "IOTA",
|
|
36
|
+
address: "0x1111111111111111111111111111111111111111111111111111111111111111",
|
|
37
|
+
}],
|
|
38
|
+
spendPolicyRef: "policy:researcher-demo",
|
|
39
|
+
reputationRef: "reputation:researcher-demo",
|
|
40
|
+
expiresAt: "2026-06-10T13:00:00.000Z",
|
|
41
|
+
status: "active",
|
|
42
|
+
revocation: {
|
|
43
|
+
revoked: false,
|
|
44
|
+
},
|
|
45
|
+
metadata: {
|
|
46
|
+
purpose: "profile-schema-fixture",
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export function validateAgentProfile(value, options = {}) {
|
|
51
|
+
if (!isRecord(value)) {
|
|
52
|
+
return fail("PROFILE_NOT_OBJECT", "$", "Agent profile must be a JSON object.");
|
|
53
|
+
}
|
|
54
|
+
if (value.version !== AGENT_PROFILE_VERSION) {
|
|
55
|
+
return fail("UNSUPPORTED_VERSION", "$.version", "Agent profile version is unsupported.");
|
|
56
|
+
}
|
|
57
|
+
const profile = value;
|
|
58
|
+
const errors = [];
|
|
59
|
+
rejectSecretFields(errors, value);
|
|
60
|
+
requireNonEmptyString(errors, profile.name, "$.name");
|
|
61
|
+
requireNonEmptyString(errors, profile.agentDid, "$.agentDid");
|
|
62
|
+
requireNonEmptyString(errors, profile.ownerDid, "$.ownerDid");
|
|
63
|
+
requireWallet(errors, profile.wallet, "$.wallet");
|
|
64
|
+
requireCapabilities(errors, profile.capabilities, "$.capabilities");
|
|
65
|
+
requireEndpoints(errors, profile.endpoints, "$.endpoints");
|
|
66
|
+
requireNonEmptyString(errors, profile.expiresAt, "$.expiresAt");
|
|
67
|
+
requireRevocation(errors, profile.revocation, "$.revocation");
|
|
68
|
+
const explicitStatus = normalizeStatus(profile.status);
|
|
69
|
+
if (!explicitStatus) {
|
|
70
|
+
push(errors, "FIELD_INVALID", "$.status", "Profile status must be active, revoked, or expired.");
|
|
71
|
+
}
|
|
72
|
+
if (typeof profile.expiresAt === "string" && profile.expiresAt.trim() !== "") {
|
|
73
|
+
const expiresAt = Date.parse(profile.expiresAt);
|
|
74
|
+
if (Number.isNaN(expiresAt)) {
|
|
75
|
+
push(errors, "FIELD_INVALID", "$.expiresAt", "Profile expiry must be an ISO timestamp.");
|
|
76
|
+
}
|
|
77
|
+
else if (expiresAt <= (options.now ?? new Date()).getTime()) {
|
|
78
|
+
push(errors, "PROFILE_EXPIRED", "$.expiresAt", "Agent profile is expired.");
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (profile.revocation?.revoked || profile.status === "revoked") {
|
|
82
|
+
push(errors, "PROFILE_REVOKED", "$.revocation.revoked", "Agent profile is revoked.");
|
|
83
|
+
}
|
|
84
|
+
if (profile.status === "expired") {
|
|
85
|
+
push(errors, "PROFILE_EXPIRED", "$.status", "Agent profile status is expired.");
|
|
86
|
+
}
|
|
87
|
+
if (errors.length > 0) {
|
|
88
|
+
return {
|
|
89
|
+
ok: false,
|
|
90
|
+
errors,
|
|
91
|
+
...(explicitStatus ? { status: explicitStatus } : {}),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return { ok: true, profile };
|
|
95
|
+
}
|
|
96
|
+
function requireWallet(errors, value, path) {
|
|
97
|
+
if (!isRecord(value)) {
|
|
98
|
+
push(errors, "REQUIRED_FIELD_MISSING", path, "Wallet object is required.");
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
requireNonEmptyString(errors, value.walletId, `${path}.walletId`);
|
|
102
|
+
requireNonEmptyString(errors, value.address, `${path}.address`);
|
|
103
|
+
requireNonEmptyString(errors, value.signerRef, `${path}.signerRef`);
|
|
104
|
+
requireNonEmptyString(errors, value.creationSource, `${path}.creationSource`);
|
|
105
|
+
if (!["active", "disabled", "revoked", "rotated"].includes(String(value.status))) {
|
|
106
|
+
push(errors, "FIELD_INVALID", `${path}.status`, "Wallet status is invalid.");
|
|
107
|
+
}
|
|
108
|
+
else if (value.status !== "active") {
|
|
109
|
+
push(errors, "PROFILE_REVOKED", `${path}.status`, "Agent profile wallet is not active.");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function requireCapabilities(errors, value, path) {
|
|
113
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
114
|
+
push(errors, "REQUIRED_FIELD_MISSING", path, "At least one capability is required.");
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
value.forEach((capability, index) => {
|
|
118
|
+
if (!isRecord(capability)) {
|
|
119
|
+
push(errors, "FIELD_INVALID", `${path}[${index}]`, "Capability must be an object.");
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
requireNonEmptyString(errors, capability.id, `${path}[${index}].id`);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function requireEndpoints(errors, value, path) {
|
|
126
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
127
|
+
push(errors, "REQUIRED_FIELD_MISSING", path, "At least one endpoint is required.");
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
value.forEach((endpoint, index) => {
|
|
131
|
+
if (!isRecord(endpoint)) {
|
|
132
|
+
push(errors, "FIELD_INVALID", `${path}[${index}]`, "Endpoint must be an object.");
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (!["mcp", "a2a", "agent_card", "https"].includes(String(endpoint.type))) {
|
|
136
|
+
push(errors, "FIELD_INVALID", `${path}[${index}].type`, "Endpoint type is invalid.");
|
|
137
|
+
}
|
|
138
|
+
requireNonEmptyString(errors, endpoint.url, `${path}[${index}].url`);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
function requireRevocation(errors, value, path) {
|
|
142
|
+
if (!isRecord(value)) {
|
|
143
|
+
push(errors, "REQUIRED_FIELD_MISSING", path, "Revocation object is required.");
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (typeof value.revoked !== "boolean") {
|
|
147
|
+
push(errors, "REQUIRED_FIELD_MISSING", `${path}.revoked`, "Revocation state is required.");
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function requireNonEmptyString(errors, value, path) {
|
|
151
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
152
|
+
push(errors, "REQUIRED_FIELD_MISSING", path, "Required string field is missing.");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function rejectSecretFields(errors, value, path = "$") {
|
|
156
|
+
if (Array.isArray(value)) {
|
|
157
|
+
value.forEach((child, index) => {
|
|
158
|
+
rejectSecretFields(errors, child, `${path}[${index}]`);
|
|
159
|
+
});
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (!isRecord(value))
|
|
163
|
+
return;
|
|
164
|
+
for (const [key, child] of Object.entries(value)) {
|
|
165
|
+
const childPath = `${path}.${key}`;
|
|
166
|
+
if (isSecretField(key)) {
|
|
167
|
+
push(errors, "SECRET_FIELD_NOT_ALLOWED", childPath, "Agent profile must not contain secret material.");
|
|
168
|
+
}
|
|
169
|
+
rejectSecretFields(errors, child, childPath);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function normalizeStatus(value) {
|
|
173
|
+
return value === "active" || value === "revoked" || value === "expired" ? value : undefined;
|
|
174
|
+
}
|
|
175
|
+
function fail(code, path, message) {
|
|
176
|
+
return { ok: false, errors: [{ code, path, message }] };
|
|
177
|
+
}
|
|
178
|
+
function push(errors, code, path, message) {
|
|
179
|
+
errors.push({ code, path, message });
|
|
180
|
+
}
|
|
181
|
+
function isRecord(value) {
|
|
182
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
183
|
+
}
|
|
184
|
+
function isSecretField(key) {
|
|
185
|
+
return /^(seed|mnemonic|privateKey|private_key|rawKeypair|raw_keypair|rawTransactionBytes|raw_transaction_bytes|userSignature|user_signature|sponsorKey|sponsor_key|appApiKey|app_api_key|bearerToken|bearer_token|paymentCredential|payment_credential|signerSecret|signer_secret)$/i.test(key);
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=profileSchema.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type AgentProfile, type AgentProfileValidationError } from "./profileSchema.js";
|
|
2
|
+
export type ResolveAgentErrorCode = "PROFILE_NOT_FOUND" | "PROFILE_MALFORMED" | "PROFILE_UNSUPPORTED_SCHEMA" | "PROFILE_REVOKED" | "PROFILE_EXPIRED" | "PROFILE_UNVERIFIABLE" | "PROFILE_STALE_CACHE";
|
|
3
|
+
export interface ResolveAgentError {
|
|
4
|
+
readonly code: ResolveAgentErrorCode;
|
|
5
|
+
readonly message: string;
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly validationErrors?: readonly AgentProfileValidationError[];
|
|
8
|
+
}
|
|
9
|
+
export type ResolveAgentResult = {
|
|
10
|
+
readonly ok: true;
|
|
11
|
+
readonly profile: AgentProfile;
|
|
12
|
+
} | {
|
|
13
|
+
readonly ok: false;
|
|
14
|
+
readonly error: ResolveAgentError;
|
|
15
|
+
};
|
|
16
|
+
export interface AgentResolver {
|
|
17
|
+
resolve(name: string): Promise<ResolveAgentResult>;
|
|
18
|
+
}
|
|
19
|
+
export interface LocalAgentResolverOptions {
|
|
20
|
+
readonly profiles: readonly unknown[];
|
|
21
|
+
readonly now?: () => Date;
|
|
22
|
+
}
|
|
23
|
+
export declare function createLocalAgentResolver(options: LocalAgentResolverOptions): AgentResolver;
|
|
24
|
+
export declare function resolveAgent(name: string, resolver: AgentResolver): Promise<ResolveAgentResult>;
|
|
25
|
+
export declare function resolveAgentValidationErrorCode(errors: readonly AgentProfileValidationError[]): ResolveAgentErrorCode;
|
|
26
|
+
//# sourceMappingURL=resolveAgent.d.ts.map
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { validateAgentProfile, } from "./profileSchema.js";
|
|
2
|
+
export function createLocalAgentResolver(options) {
|
|
3
|
+
const profilesByName = new Map();
|
|
4
|
+
for (const profile of options.profiles) {
|
|
5
|
+
if (isNamedProfileRecord(profile)) {
|
|
6
|
+
profilesByName.set(profile.name, profile);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return {
|
|
10
|
+
async resolve(name) {
|
|
11
|
+
const normalizedName = normalizeName(name);
|
|
12
|
+
const profile = profilesByName.get(normalizedName);
|
|
13
|
+
if (!profile) {
|
|
14
|
+
return {
|
|
15
|
+
ok: false,
|
|
16
|
+
error: {
|
|
17
|
+
code: "PROFILE_NOT_FOUND",
|
|
18
|
+
message: "Agent profile was not found.",
|
|
19
|
+
name: normalizedName,
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return validateResolvedProfile(normalizedName, profile, options.now?.());
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export async function resolveAgent(name, resolver) {
|
|
28
|
+
return resolver.resolve(normalizeName(name));
|
|
29
|
+
}
|
|
30
|
+
function validateResolvedProfile(name, profile, now) {
|
|
31
|
+
const validation = validateAgentProfile(profile, { now });
|
|
32
|
+
if (validation.ok) {
|
|
33
|
+
return { ok: true, profile: validation.profile };
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
ok: false,
|
|
37
|
+
error: {
|
|
38
|
+
code: resolveAgentValidationErrorCode(validation.errors),
|
|
39
|
+
message: "Agent profile failed validation.",
|
|
40
|
+
name,
|
|
41
|
+
validationErrors: validation.errors,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function resolveAgentValidationErrorCode(errors) {
|
|
46
|
+
if (errors.some((error) => error.code === "PROFILE_REVOKED"))
|
|
47
|
+
return "PROFILE_REVOKED";
|
|
48
|
+
if (errors.some((error) => error.code === "PROFILE_EXPIRED"))
|
|
49
|
+
return "PROFILE_EXPIRED";
|
|
50
|
+
if (errors.some((error) => error.code === "UNSUPPORTED_VERSION"))
|
|
51
|
+
return "PROFILE_UNSUPPORTED_SCHEMA";
|
|
52
|
+
return "PROFILE_MALFORMED";
|
|
53
|
+
}
|
|
54
|
+
function normalizeName(name) {
|
|
55
|
+
return name.trim();
|
|
56
|
+
}
|
|
57
|
+
function isNamedProfileRecord(value) {
|
|
58
|
+
return Boolean(value) &&
|
|
59
|
+
typeof value === "object" &&
|
|
60
|
+
!Array.isArray(value) &&
|
|
61
|
+
typeof value.name === "string";
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=resolveAgent.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vallum/registry",
|
|
3
|
+
"version": "0.0.0-prerelease",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"description": "Versioned Agent Profile schema and validator for Vallum.",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist/**/*.js",
|
|
17
|
+
"dist/**/*.d.ts",
|
|
18
|
+
"LICENSE",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc -p tsconfig.build.json"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=20"
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public",
|
|
30
|
+
"tag": "next"
|
|
31
|
+
}
|
|
32
|
+
}
|