@aep-foundation/agent 0.1.0

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/dist/index.cjs ADDED
@@ -0,0 +1,1024 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AepCommandError: () => AepCommandError,
24
+ AepInspectError: () => AepInspectError,
25
+ buildClientAssertionClaims: () => buildClientAssertionClaims,
26
+ clientAssertionAuthenticationHeaders: () => clientAssertionAuthenticationHeaders,
27
+ createAepAgent: () => createAepAgent,
28
+ createInMemoryAgentIdentityStore: () => createInMemoryAgentIdentityStore,
29
+ createInMemoryInspectCache: () => createInMemoryInspectCache,
30
+ createInMemorySessionCredentialStore: () => createInMemorySessionCredentialStore,
31
+ createJwtClientAssertionSigner: () => createJwtClientAssertionSigner,
32
+ createPlatformDelegatedSigner: () => createPlatformDelegatedSigner,
33
+ createPlatformIdentityProvider: () => createPlatformIdentityProvider,
34
+ createRandomIdempotencyKeyProvider: () => createRandomIdempotencyKeyProvider,
35
+ credentialPresentationHeaders: () => credentialPresentationHeaders,
36
+ discoverPlatform: () => discoverPlatform,
37
+ enrollService: () => enrollService,
38
+ grantService: () => grantService,
39
+ inspectService: () => inspectService,
40
+ protectedResourceAuthenticationHeaders: () => protectedResourceAuthenticationHeaders,
41
+ provisionPlatformIdentity: () => provisionPlatformIdentity,
42
+ revokeService: () => revokeService,
43
+ selectGrantType: () => selectGrantType,
44
+ sessionCredentialRecordFromGrantResult: () => sessionCredentialRecordFromGrantResult,
45
+ signClientAssertion: () => signClientAssertion,
46
+ statusService: () => statusService
47
+ });
48
+ module.exports = __toCommonJS(index_exports);
49
+ var import_core = require("@aep-foundation/core");
50
+ var import_platform = require("@aep-foundation/platform");
51
+ var AepInspectError = class extends Error {
52
+ status;
53
+ constructor(message, status) {
54
+ super(message);
55
+ this.name = "AepInspectError";
56
+ if (status !== void 0) {
57
+ this.status = status;
58
+ }
59
+ }
60
+ };
61
+ var AepCommandError = class extends Error {
62
+ problem;
63
+ status;
64
+ constructor(message, status, problem) {
65
+ super(message);
66
+ this.name = "AepCommandError";
67
+ this.status = status;
68
+ if (problem !== void 0) {
69
+ this.problem = problem;
70
+ }
71
+ }
72
+ };
73
+ function createAepAgent(options) {
74
+ const identityStore = options.identityStore ?? createInMemoryAgentIdentityStore();
75
+ const credentialStore = options.credentialStore ?? createInMemorySessionCredentialStore();
76
+ const idempotencyKeys = options.idempotencyKeys ?? createRandomIdempotencyKeyProvider();
77
+ const inspectCache = options.inspectCache ?? createInMemoryInspectCache();
78
+ const assertionOptions = assertionOptionsWithDefinedValues(options);
79
+ return {
80
+ serviceSession: (sessionOptions) => createAepServiceSession({
81
+ ...assertionOptions,
82
+ credentialStore,
83
+ idempotencyKeys,
84
+ identityProvider: options.identityProvider,
85
+ identityStore,
86
+ inspectCache,
87
+ serviceUrl: sessionOptions.serviceUrl
88
+ })
89
+ };
90
+ }
91
+ function createAepServiceSession(state) {
92
+ const serviceUrl = normalizeServiceUrl(state.serviceUrl);
93
+ const serviceUrlString = String(serviceUrl);
94
+ let inspectPromise;
95
+ let identityPromise;
96
+ let signerPromise;
97
+ const inspectOnce = async () => {
98
+ if (inspectPromise !== void 0) {
99
+ return inspectPromise;
100
+ }
101
+ inspectPromise = (async () => {
102
+ const cached = await state.inspectCache.get(serviceUrlString);
103
+ if (cached !== void 0) {
104
+ return cached;
105
+ }
106
+ const inspected = await inspectService({ serviceUrl });
107
+ const cachedResult = {
108
+ ...inspected,
109
+ cachedAt: (/* @__PURE__ */ new Date()).toISOString()
110
+ };
111
+ await state.inspectCache.set(serviceUrlString, cachedResult);
112
+ return inspected;
113
+ })();
114
+ return inspectPromise;
115
+ };
116
+ const identityOnce = async () => {
117
+ if (identityPromise !== void 0) {
118
+ return identityPromise;
119
+ }
120
+ identityPromise = (async () => {
121
+ const inspected = await inspectOnce();
122
+ const serviceDid = inspected.document.service.did;
123
+ const existing = await state.identityStore.findByServiceDid(serviceDid);
124
+ if (existing !== void 0) {
125
+ return existing;
126
+ }
127
+ const created = await state.identityProvider.getOrCreateIdentity({
128
+ inspect: inspected.document,
129
+ serviceDid,
130
+ serviceUrl: serviceUrlString
131
+ });
132
+ return state.identityStore.saveIdentity(created);
133
+ })();
134
+ return identityPromise;
135
+ };
136
+ const signerOnce = async () => {
137
+ if (signerPromise !== void 0) {
138
+ return signerPromise;
139
+ }
140
+ signerPromise = Promise.resolve(state.identityProvider.signerFor(await identityOnce()));
141
+ return signerPromise;
142
+ };
143
+ const commandOptions = async () => {
144
+ const inspected = await inspectOnce();
145
+ const identity = await identityOnce();
146
+ const signer = await signerOnce();
147
+ return {
148
+ agentDid: identity.agentDid,
149
+ clientAssertionSigner: signer,
150
+ inspect: inspected,
151
+ serviceUrl
152
+ };
153
+ };
154
+ const assertionOptions = () => ({
155
+ ...state.assertionClock === void 0 ? {} : { assertionClock: state.assertionClock },
156
+ ...state.assertionJti === void 0 ? {} : { assertionJti: state.assertionJti },
157
+ ...state.assertionTtlSeconds === void 0 ? {} : { assertionTtlSeconds: state.assertionTtlSeconds }
158
+ });
159
+ const idempotencyKey = async (operation) => {
160
+ const inspected = await inspectOnce();
161
+ return state.idempotencyKeys.createKey({
162
+ ...operation,
163
+ serviceDid: inspected.document.service.did,
164
+ serviceUrl: serviceUrlString
165
+ });
166
+ };
167
+ return {
168
+ async authenticationHeaders(options = {}) {
169
+ const inspected = await inspectOnce();
170
+ if (options.preferCredential !== false) {
171
+ const credential = await state.credentialStore.findUsableCredential(
172
+ inspected.document.service.did
173
+ );
174
+ if (credential !== void 0) {
175
+ return protectedResourceAuthenticationHeaders({
176
+ credential: (0, import_core.parseBuiltInGrantResponse)(credential.grantType, credential.credential)
177
+ });
178
+ }
179
+ }
180
+ const identity = await identityOnce();
181
+ const signer = await signerOnce();
182
+ return protectedResourceAuthenticationHeaders({
183
+ agentDid: identity.agentDid,
184
+ inspect: inspected,
185
+ ...state.assertionClock === void 0 ? {} : { clock: state.assertionClock },
186
+ ...state.assertionJti === void 0 ? {} : { jti: state.assertionJti },
187
+ signer,
188
+ ...state.assertionTtlSeconds === void 0 ? {} : { ttlSeconds: state.assertionTtlSeconds }
189
+ });
190
+ },
191
+ async enroll(options = {}) {
192
+ return enrollService({
193
+ ...await commandOptions(),
194
+ ...assertionOptions(),
195
+ ...options.claims === void 0 ? {} : { claims: options.claims },
196
+ idempotencyKey: options.idempotencyKey ?? await idempotencyKey({ command: "enroll" })
197
+ });
198
+ },
199
+ async grant(options = {}) {
200
+ const inspected = await inspectOnce();
201
+ const grantType = options.grantType ?? selectGrantType(inspected, {
202
+ ...options.preferredGrantTypes === void 0 ? {} : { preferredGrantTypes: options.preferredGrantTypes }
203
+ });
204
+ const result = await grantService({
205
+ ...await commandOptions(),
206
+ ...assertionOptions(),
207
+ grantType,
208
+ idempotencyKey: options.idempotencyKey ?? await idempotencyKey({ command: "grant", grantType }),
209
+ ...options.parameters === void 0 ? {} : { parameters: options.parameters },
210
+ ...options.requestedScopes === void 0 ? {} : { requestedScopes: options.requestedScopes }
211
+ });
212
+ await state.credentialStore.saveCredential(
213
+ sessionCredentialRecordFromGrantResult(result, {
214
+ grantType,
215
+ inspect: inspected,
216
+ serviceUrl
217
+ })
218
+ );
219
+ return result;
220
+ },
221
+ identity: identityOnce,
222
+ inspect: inspectOnce,
223
+ async revoke(options) {
224
+ const selector = revokeSessionSelector(options);
225
+ const result = await revokeService({
226
+ ...await commandOptions(),
227
+ ...assertionOptions(),
228
+ ...selector,
229
+ idempotencyKey: options.idempotencyKey ?? await idempotencyKey({
230
+ command: "revoke",
231
+ ..."credentialId" in selector ? { credentialId: selector.credentialId } : {},
232
+ ..."grantType" in selector ? { grantType: selector.grantType } : {}
233
+ }),
234
+ ...options.parameters === void 0 ? {} : { parameters: options.parameters }
235
+ });
236
+ const inspected = await inspectOnce();
237
+ if ("credentialId" in selector) {
238
+ await state.credentialStore.deleteCredential(
239
+ inspected.document.service.did,
240
+ selector.credentialId
241
+ );
242
+ }
243
+ return result;
244
+ },
245
+ async status() {
246
+ return statusService({
247
+ ...await commandOptions(),
248
+ ...assertionOptions()
249
+ });
250
+ }
251
+ };
252
+ }
253
+ function revokeSessionSelector(options) {
254
+ if (options.allGrantTypes === true) {
255
+ return { allGrantTypes: true };
256
+ }
257
+ if (options.credentialId !== void 0) {
258
+ return { credentialId: options.credentialId };
259
+ }
260
+ return { grantType: options.grantType };
261
+ }
262
+ function buildClientAssertionClaims(options) {
263
+ if (!import_core.AEP_AUTHENTICATED_COMMANDS.includes(options.command)) {
264
+ throw new TypeError(`Unsupported authenticated command: ${options.command}.`);
265
+ }
266
+ const now = Math.floor((options.clock ?? (() => /* @__PURE__ */ new Date()))().getTime() / 1e3);
267
+ const ttlSeconds = options.ttlSeconds ?? 300;
268
+ const jti = typeof options.jti === "function" ? options.jti() : options.jti ?? randomJti();
269
+ return (0, import_core.parseClientAssertionClaims)({
270
+ aud: options.serviceDid,
271
+ exp: now + ttlSeconds,
272
+ iat: now,
273
+ iss: options.agentDid,
274
+ jti,
275
+ op: options.command,
276
+ sub: options.agentDid
277
+ });
278
+ }
279
+ async function signClientAssertion(options) {
280
+ const claims = buildClientAssertionClaims(options);
281
+ return options.signer(claims, {
282
+ command: options.command,
283
+ serviceDid: options.serviceDid,
284
+ signingAlgorithms: [...options.signingAlgorithms ?? import_core.AEP_SIGNING_ALGORITHMS]
285
+ });
286
+ }
287
+ function createJwtClientAssertionSigner(options) {
288
+ return (claims, context) => (0, import_core.signClientAssertionJwt)(claims, {
289
+ alg: options.alg ?? preferredSigningAlgorithm(context.signingAlgorithms),
290
+ key: options.key,
291
+ ...options.kid === void 0 ? {} : { kid: options.kid },
292
+ ...options.typ === void 0 ? {} : { typ: options.typ }
293
+ });
294
+ }
295
+ async function discoverPlatform(options) {
296
+ const fetchImpl = requireFetch();
297
+ const platformUrl = normalizePlatformUrl(options.platformUrl);
298
+ const discoveryUrl = new URL("/.well-known/aep-platform", platformUrl);
299
+ const response = await fetchImpl(discoveryUrl, {
300
+ headers: {
301
+ Accept: import_core.AEP_MEDIA_TYPE
302
+ }
303
+ });
304
+ await throwCommandError(response, "Platform discovery");
305
+ const document = parsePlatformDiscoveryDocument(await response.json());
306
+ return {
307
+ document,
308
+ discoveryUrl,
309
+ endpointUrl: (endpoint) => new URL(requireEndpointPath(document, endpoint), platformUrl)
310
+ };
311
+ }
312
+ async function provisionPlatformIdentity(options) {
313
+ const fetchImpl = requireFetch();
314
+ const discovery = options.discovery ?? await discoverPlatform({
315
+ platformUrl: options.platformUrl
316
+ });
317
+ const commandUrl = discovery.endpointUrl("provision");
318
+ const body = (0, import_platform.createPlatformProvisionRequest)({
319
+ idempotencyKey: options.idempotencyKey,
320
+ serviceDid: options.serviceDid
321
+ });
322
+ const response = await fetchImpl(commandUrl, {
323
+ body: JSON.stringify(body),
324
+ headers: {
325
+ Accept: import_core.AEP_MEDIA_TYPE,
326
+ ...options.authorization === void 0 ? {} : { Authorization: options.authorization },
327
+ "Content-Type": import_core.AEP_MEDIA_TYPE,
328
+ "Idempotency-Key": options.idempotencyKey
329
+ },
330
+ method: "POST"
331
+ });
332
+ await throwCommandError(response, "Platform provision");
333
+ return {
334
+ body: parsePlatformAgentIdentity(await response.json()),
335
+ commandUrl,
336
+ status: response.status
337
+ };
338
+ }
339
+ function createPlatformDelegatedSigner(options) {
340
+ return async (claims) => {
341
+ const fetchImpl = requireFetch();
342
+ const discovery = options.discovery ?? await discoverPlatform({
343
+ platformUrl: options.platformUrl
344
+ });
345
+ const commandUrl = endpointUrlWithIdentity(
346
+ discovery,
347
+ "sign",
348
+ options.identity.agent_identity_id
349
+ );
350
+ const lifetimeSeconds = claims.exp - claims.iat;
351
+ const request = (0, import_platform.createPlatformSignRequest)({
352
+ command: claims.op,
353
+ jti: claims.jti,
354
+ lifetimeSeconds,
355
+ serviceDid: claims.aud
356
+ });
357
+ const response = await fetchImpl(commandUrl, {
358
+ body: JSON.stringify(request),
359
+ headers: {
360
+ Accept: import_core.AEP_MEDIA_TYPE,
361
+ ...options.authorization === void 0 ? {} : { Authorization: options.authorization },
362
+ "Content-Type": import_core.AEP_MEDIA_TYPE
363
+ },
364
+ method: "POST"
365
+ });
366
+ await throwCommandError(response, "Platform sign");
367
+ return parsePlatformSignResponse(await response.json()).client_assertion;
368
+ };
369
+ }
370
+ function createPlatformIdentityProvider(options) {
371
+ let discoveryPromise;
372
+ const discovery = () => {
373
+ discoveryPromise ??= discoverPlatform({ platformUrl: options.platformUrl });
374
+ return discoveryPromise;
375
+ };
376
+ return {
377
+ async getOrCreateIdentity(input) {
378
+ const platformDiscovery = await discovery();
379
+ const idempotencyKey = typeof options.idempotencyKey === "function" ? options.idempotencyKey(input) : options.idempotencyKey ?? randomJti();
380
+ const result = await provisionPlatformIdentity({
381
+ ...options.authorization === void 0 ? {} : { authorization: options.authorization },
382
+ discovery: platformDiscovery,
383
+ idempotencyKey,
384
+ platformUrl: options.platformUrl,
385
+ serviceDid: input.serviceDid
386
+ });
387
+ return agentServiceIdentityFromPlatform(result.body, options.platformUrl);
388
+ },
389
+ async signerFor(identity) {
390
+ if (identity.identityKind !== "platform-hosted") {
391
+ throw new TypeError("Platform identity provider cannot sign for a sovereign identity.");
392
+ }
393
+ const platformDiscovery = await discovery();
394
+ return createPlatformDelegatedSigner({
395
+ ...options.authorization === void 0 ? {} : { authorization: options.authorization },
396
+ discovery: platformDiscovery,
397
+ identity: platformAgentIdentityFromAgentIdentity(identity),
398
+ platformUrl: options.platformUrl
399
+ });
400
+ }
401
+ };
402
+ }
403
+ function agentServiceIdentityFromPlatform(identity, platformUrl) {
404
+ return {
405
+ agentDid: identity.agent_did,
406
+ identityKind: "platform-hosted",
407
+ metadata: {
408
+ agentIdentityId: identity.agent_identity_id,
409
+ createdAt: identity.created_at,
410
+ didDocumentUrl: identity.did_document_url,
411
+ keyId: identity.key_id,
412
+ platformUrl: String(platformUrl),
413
+ status: identity.status,
414
+ updatedAt: identity.updated_at
415
+ },
416
+ serviceDid: identity.service_did,
417
+ signingAlgorithms: [...identity.signing_algorithms]
418
+ };
419
+ }
420
+ function platformAgentIdentityFromAgentIdentity(identity) {
421
+ const metadata = identity.metadata ?? {};
422
+ return {
423
+ agent_did: identity.agentDid,
424
+ agent_identity_id: metadataString(metadata, "agentIdentityId"),
425
+ created_at: metadataString(metadata, "createdAt"),
426
+ did_document_url: metadataString(metadata, "didDocumentUrl"),
427
+ key_id: metadataString(metadata, "keyId"),
428
+ service_did: identity.serviceDid,
429
+ signing_algorithms: [...identity.signingAlgorithms],
430
+ status: parseManagedAgentStatus(metadataString(metadata, "status")),
431
+ updated_at: metadataString(metadata, "updatedAt")
432
+ };
433
+ }
434
+ function selectGrantType(inspect, options = {}) {
435
+ const document = isInspectServiceResult(inspect) ? inspect.document : inspect;
436
+ const advertised = document.commands.grant_types ?? [];
437
+ const preferred = options.preferredGrantTypes ?? advertised;
438
+ for (const grantType of preferred) {
439
+ if (advertised.includes(grantType)) {
440
+ return grantType;
441
+ }
442
+ }
443
+ throw new TypeError("AEP Service does not advertise a compatible grant type.");
444
+ }
445
+ function createInMemorySessionCredentialStore(records = []) {
446
+ const credentials = /* @__PURE__ */ new Map();
447
+ records.forEach(
448
+ (record) => credentials.set(sessionCredentialKey(record), cloneCredential(record))
449
+ );
450
+ return {
451
+ deleteCredential(serviceDid, credentialId) {
452
+ for (const [key, record] of credentials) {
453
+ if (record.serviceDid === serviceDid && record.credentialId === credentialId) {
454
+ credentials.delete(key);
455
+ }
456
+ }
457
+ },
458
+ findCredential(serviceDid, credentialId) {
459
+ for (const record of credentials.values()) {
460
+ if (record.serviceDid === serviceDid && record.credentialId === credentialId) {
461
+ return cloneCredential(record);
462
+ }
463
+ }
464
+ return void 0;
465
+ },
466
+ findUsableCredential(serviceDid, now = /* @__PURE__ */ new Date()) {
467
+ const nowMs = now.getTime();
468
+ for (const record of credentials.values()) {
469
+ if (record.serviceDid !== serviceDid) {
470
+ continue;
471
+ }
472
+ if (record.expiresAt !== void 0 && Date.parse(record.expiresAt) <= nowMs) {
473
+ continue;
474
+ }
475
+ return cloneCredential(record);
476
+ }
477
+ return void 0;
478
+ },
479
+ listCredentials(serviceDid) {
480
+ return [...credentials.values()].filter((record) => record.serviceDid === serviceDid).map(cloneCredential);
481
+ },
482
+ saveCredential(record) {
483
+ const cloned = cloneCredential(record);
484
+ credentials.set(sessionCredentialKey(cloned), cloned);
485
+ return cloneCredential(cloned);
486
+ }
487
+ };
488
+ }
489
+ function createInMemoryAgentIdentityStore(records = []) {
490
+ const identities = /* @__PURE__ */ new Map();
491
+ records.forEach((record) => identities.set(record.serviceDid, cloneAgentIdentity(record)));
492
+ return {
493
+ findByServiceDid(serviceDid) {
494
+ const identity = identities.get(serviceDid);
495
+ return identity === void 0 ? void 0 : cloneAgentIdentity(identity);
496
+ },
497
+ saveIdentity(identity) {
498
+ const cloned = cloneAgentIdentity(identity);
499
+ identities.set(cloned.serviceDid, cloned);
500
+ return cloneAgentIdentity(cloned);
501
+ }
502
+ };
503
+ }
504
+ function createRandomIdempotencyKeyProvider(generator = randomJti) {
505
+ return {
506
+ createKey: () => generator()
507
+ };
508
+ }
509
+ function createInMemoryInspectCache(records = []) {
510
+ const cache = /* @__PURE__ */ new Map();
511
+ records.forEach((record) => cache.set(record.serviceUrl, cloneCachedInspect(record.result)));
512
+ return {
513
+ get(serviceUrl) {
514
+ const cached = cache.get(serviceUrl);
515
+ return cached === void 0 ? void 0 : cloneCachedInspect(cached);
516
+ },
517
+ set(serviceUrl, result) {
518
+ cache.set(serviceUrl, cloneCachedInspect(result));
519
+ }
520
+ };
521
+ }
522
+ function sessionCredentialRecordFromGrantResult(result, options) {
523
+ const credentialId = credentialIdFromGrantResult(result.body);
524
+ const document = isInspectServiceResult(options.inspect) ? options.inspect.document : options.inspect;
525
+ const expiresAt = expiresAtFromGrantResult(result.body);
526
+ return {
527
+ credential: structuredClone(result.body),
528
+ credentialId,
529
+ grantType: options.grantType,
530
+ issuedAt: (options.clock ?? (() => /* @__PURE__ */ new Date()))().toISOString(),
531
+ serviceDid: document.service.did,
532
+ ...expiresAt === void 0 ? {} : { expiresAt },
533
+ ...options.serviceUrl === void 0 ? {} : { serviceUrl: String(options.serviceUrl) }
534
+ };
535
+ }
536
+ function credentialPresentationHeaders(credential) {
537
+ if (isOAuthBearerGrantResponse(credential)) {
538
+ return {
539
+ Authorization: `Bearer ${credential.access_token}`
540
+ };
541
+ }
542
+ if (isApiKeyGrantResponse(credential)) {
543
+ return {
544
+ [credential.header]: credential.api_key
545
+ };
546
+ }
547
+ if (isBasicGrantResponse(credential)) {
548
+ return {
549
+ Authorization: `Basic ${base64(`${credential.username}:${credential.password}`)}`
550
+ };
551
+ }
552
+ throw new TypeError("Unsupported AEP built-in credential.");
553
+ }
554
+ async function clientAssertionAuthenticationHeaders(options) {
555
+ const document = options.inspect === void 0 ? void 0 : inspectDocument(options.inspect);
556
+ const serviceDid = options.serviceDid ?? document?.service.did;
557
+ if (serviceDid === void 0) {
558
+ throw new TypeError("AEP client assertion authentication headers require a service DID.");
559
+ }
560
+ const signingAlgorithms = options.signingAlgorithms ?? document?.core.signing_algorithms;
561
+ const clientAssertion = await signClientAssertion({
562
+ agentDid: options.agentDid,
563
+ command: options.command ?? "status",
564
+ ...options.clock === void 0 ? {} : { clock: options.clock },
565
+ ...options.jti === void 0 ? {} : { jti: options.jti },
566
+ serviceDid,
567
+ signer: options.signer,
568
+ ...signingAlgorithms === void 0 ? {} : { signingAlgorithms },
569
+ ...options.ttlSeconds === void 0 ? {} : { ttlSeconds: options.ttlSeconds }
570
+ });
571
+ return {
572
+ Authorization: `${import_core.AEP_AUTH_SCHEME} ${clientAssertion}`
573
+ };
574
+ }
575
+ async function protectedResourceAuthenticationHeaders(options) {
576
+ if ("credential" in options) {
577
+ return credentialPresentationHeaders(options.credential);
578
+ }
579
+ return clientAssertionAuthenticationHeaders(options);
580
+ }
581
+ async function inspectService(options) {
582
+ const fetchImpl = requireFetch();
583
+ const serviceUrl = normalizeServiceUrl(options.serviceUrl);
584
+ const inspectUrl = new URL(import_core.AEP_WELL_KNOWN_PATH, serviceUrl);
585
+ const response = await fetchImpl(inspectUrl, {
586
+ headers: {
587
+ Accept: import_core.AEP_MEDIA_TYPE
588
+ }
589
+ });
590
+ if (!response.ok) {
591
+ throw new AepInspectError(
592
+ `AEP Inspect failed with HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""}.`,
593
+ response.status
594
+ );
595
+ }
596
+ const document = (0, import_core.parseInspectDocument)(await response.json());
597
+ const cacheControl = response.headers.get("cache-control") ?? void 0;
598
+ const etag = response.headers.get("etag") ?? void 0;
599
+ return {
600
+ document,
601
+ inspectUrl,
602
+ commandUrl: (command) => new URL((0, import_core.commandPathFromInspect)(document, command), serviceUrl),
603
+ ...cacheControl === void 0 ? {} : { cacheControl },
604
+ ...etag === void 0 ? {} : { etag }
605
+ };
606
+ }
607
+ async function enrollService(options) {
608
+ const fetchImpl = requireFetch();
609
+ const inspect = await resolveInspect(options);
610
+ const commandUrl = commandUrlFromInspect(options.serviceUrl, inspect, "enroll");
611
+ const clientAssertion = await resolveClientAssertion(options, inspect, "enroll");
612
+ const body = {
613
+ agent_did: options.agentDid,
614
+ ...options.claims === void 0 ? {} : { claims: structuredClone(options.claims) },
615
+ idempotency_key: options.idempotencyKey
616
+ };
617
+ const response = await fetchImpl(commandUrl, {
618
+ body: JSON.stringify(body),
619
+ headers: {
620
+ Accept: import_core.AEP_MEDIA_TYPE,
621
+ Authorization: `${import_core.AEP_AUTH_SCHEME} ${clientAssertion}`,
622
+ "Content-Type": import_core.AEP_MEDIA_TYPE,
623
+ "Idempotency-Key": options.idempotencyKey
624
+ },
625
+ method: "POST"
626
+ });
627
+ await throwCommandError(response, "Enroll");
628
+ return {
629
+ body: (0, import_core.parseEnrollResponse)(await response.json()),
630
+ commandUrl,
631
+ status: response.status
632
+ };
633
+ }
634
+ async function grantService(options) {
635
+ const fetchImpl = requireFetch();
636
+ const inspect = await resolveInspect(options);
637
+ const commandUrl = commandUrlFromInspect(options.serviceUrl, inspect, "grant");
638
+ const clientAssertion = await resolveClientAssertion(options, inspect, "grant");
639
+ const body = (0, import_core.parseGrantRequest)({
640
+ ...options.parameters ?? {},
641
+ grant_type: options.grantType,
642
+ ...options.requestedScopes === void 0 ? {} : { requested_scopes: [...options.requestedScopes] }
643
+ });
644
+ const response = await fetchImpl(commandUrl, {
645
+ body: JSON.stringify(body),
646
+ headers: {
647
+ Accept: import_core.AEP_MEDIA_TYPE,
648
+ Authorization: `${import_core.AEP_AUTH_SCHEME} ${clientAssertion}`,
649
+ "Content-Type": import_core.AEP_MEDIA_TYPE,
650
+ "Idempotency-Key": options.idempotencyKey
651
+ },
652
+ method: "POST"
653
+ });
654
+ await throwCommandError(response, "Grant");
655
+ return {
656
+ body: parseGrantResponse(body.grant_type, await response.json()),
657
+ commandUrl,
658
+ status: response.status
659
+ };
660
+ }
661
+ async function revokeService(options) {
662
+ const fetchImpl = requireFetch();
663
+ const inspect = await resolveInspect(options);
664
+ const commandUrl = commandUrlFromInspect(options.serviceUrl, inspect, "revoke");
665
+ const clientAssertion = await resolveClientAssertion(options, inspect, "revoke");
666
+ const body = (0, import_core.parseRevokeRequest)({
667
+ ...options.parameters ?? {},
668
+ ...revokeSelectorBody(options)
669
+ });
670
+ const response = await fetchImpl(commandUrl, {
671
+ body: JSON.stringify(body),
672
+ headers: {
673
+ Accept: import_core.AEP_MEDIA_TYPE,
674
+ Authorization: `${import_core.AEP_AUTH_SCHEME} ${clientAssertion}`,
675
+ "Content-Type": import_core.AEP_MEDIA_TYPE,
676
+ "Idempotency-Key": options.idempotencyKey
677
+ },
678
+ method: "POST"
679
+ });
680
+ await throwCommandError(response, "Revoke");
681
+ return {
682
+ body: (0, import_core.parseRevokeResponse)(await response.json()),
683
+ commandUrl,
684
+ status: response.status
685
+ };
686
+ }
687
+ async function statusService(options) {
688
+ const fetchImpl = requireFetch();
689
+ const inspect = await resolveInspect(options);
690
+ const commandUrl = commandUrlFromInspect(options.serviceUrl, inspect, "status");
691
+ const clientAssertion = await resolveClientAssertion(options, inspect, "status");
692
+ const response = await fetchImpl(commandUrl, {
693
+ headers: {
694
+ Accept: import_core.AEP_MEDIA_TYPE,
695
+ Authorization: `${import_core.AEP_AUTH_SCHEME} ${clientAssertion}`
696
+ },
697
+ method: "GET"
698
+ });
699
+ await throwCommandError(response, "Status");
700
+ return {
701
+ body: (0, import_core.parseStatusResponse)(await response.json()),
702
+ commandUrl,
703
+ status: response.status
704
+ };
705
+ }
706
+ function normalizePlatformUrl(platformUrl) {
707
+ const url = platformUrl instanceof URL ? new URL(platformUrl) : new URL(platformUrl);
708
+ if (url.pathname !== "/" || url.search || url.hash) {
709
+ url.pathname = "/";
710
+ url.search = "";
711
+ url.hash = "";
712
+ }
713
+ return url;
714
+ }
715
+ function normalizeServiceUrl(serviceUrl) {
716
+ const url = serviceUrl instanceof URL ? new URL(serviceUrl) : new URL(serviceUrl);
717
+ if (url.pathname !== "/" || url.search || url.hash) {
718
+ url.pathname = "/";
719
+ url.search = "";
720
+ url.hash = "";
721
+ }
722
+ return url;
723
+ }
724
+ function parsePlatformDiscoveryDocument(value) {
725
+ const document = requireRecord(value, "Platform discovery document");
726
+ const endpoints = requireRecord(document["endpoints"], "Platform discovery endpoints");
727
+ const http = requireRecord(document["http"], "Platform discovery HTTP metadata");
728
+ const identity = requireRecord(document["identity"], "Platform discovery identity metadata");
729
+ const platform = requireRecord(document["platform"], "Platform discovery platform metadata");
730
+ const signing = requireRecord(document["signing"], "Platform discovery signing metadata");
731
+ const algorithms = requireStringArray(signing, "algorithms");
732
+ const didMethods = requireStringArray(identity, "did_methods");
733
+ return {
734
+ ...document,
735
+ aep_version: requireString(document, "aep_version"),
736
+ endpoints: {
737
+ ...endpoints,
738
+ ...endpoints["hosted_verification"] === void 0 ? {} : { hosted_verification: requireString(endpoints, "hosted_verification") },
739
+ lifecycle: requireString(endpoints, "lifecycle"),
740
+ list: requireString(endpoints, "list"),
741
+ provision: requireString(endpoints, "provision"),
742
+ sign: requireString(endpoints, "sign")
743
+ },
744
+ http: {
745
+ ...http,
746
+ endpoint_base: requireString(http, "endpoint_base")
747
+ },
748
+ identity: {
749
+ ...identity,
750
+ did_methods: didMethods,
751
+ did_url_template: requireString(identity, "did_url_template")
752
+ },
753
+ platform: {
754
+ ...platform,
755
+ ...platform["did"] === void 0 ? {} : { did: requireString(platform, "did") },
756
+ hosted_verification: requireBoolean(platform, "hosted_verification"),
757
+ name: requireString(platform, "name")
758
+ },
759
+ signing: {
760
+ ...signing,
761
+ algorithms,
762
+ default_lifetime_seconds: requireString(signing, "default_lifetime_seconds")
763
+ }
764
+ };
765
+ }
766
+ function parsePlatformAgentIdentity(value) {
767
+ const body = requireRecord(value, "Platform Agent identity");
768
+ return {
769
+ agent_did: requireString(body, "agent_did"),
770
+ agent_identity_id: requireString(body, "agent_identity_id"),
771
+ created_at: requireString(body, "created_at"),
772
+ did_document_url: requireString(body, "did_document_url"),
773
+ key_id: requireString(body, "key_id"),
774
+ service_did: requireString(body, "service_did"),
775
+ signing_algorithms: requireStringArray(body, "signing_algorithms"),
776
+ status: parseManagedAgentStatus(requireString(body, "status")),
777
+ updated_at: requireString(body, "updated_at")
778
+ };
779
+ }
780
+ function parsePlatformSignResponse(value) {
781
+ const body = requireRecord(value, "Platform sign response");
782
+ return {
783
+ agent_did: requireString(body, "agent_did"),
784
+ client_assertion: requireString(body, "client_assertion"),
785
+ expires_at: requireString(body, "expires_at"),
786
+ issued_at: requireString(body, "issued_at"),
787
+ jti: requireString(body, "jti"),
788
+ service_did: requireString(body, "service_did")
789
+ };
790
+ }
791
+ function endpointUrlWithIdentity(discovery, endpoint, agentIdentityId) {
792
+ const endpointUrl = discovery.endpointUrl(endpoint);
793
+ const encodedAgentIdentityTemplate = "%7Bagent_identity_id%7D";
794
+ endpointUrl.pathname = endpointUrl.pathname.replace("{agent_identity_id}", encodeURIComponent(agentIdentityId)).replace(encodedAgentIdentityTemplate, encodeURIComponent(agentIdentityId));
795
+ return endpointUrl;
796
+ }
797
+ function requireEndpointPath(document, endpoint) {
798
+ const value = document.endpoints[endpoint];
799
+ if (typeof value !== "string" || value.length === 0) {
800
+ throw new TypeError(`Platform discovery does not advertise ${String(endpoint)}.`);
801
+ }
802
+ return value;
803
+ }
804
+ function inspectDocument(inspect) {
805
+ return isInspectServiceResult(inspect) ? inspect.document : inspect;
806
+ }
807
+ function requireFetch() {
808
+ const resolved = globalThis.fetch;
809
+ if (typeof resolved !== "function") {
810
+ throw new TypeError("AEP agent requires a fetch implementation.");
811
+ }
812
+ return resolved;
813
+ }
814
+ async function resolveInspect(options) {
815
+ return options.inspect ?? await inspectService({
816
+ serviceUrl: options.serviceUrl
817
+ });
818
+ }
819
+ function commandUrlFromInspect(serviceUrl, inspect, command) {
820
+ if (!inspect.document.commands.supported.includes(command)) {
821
+ throw new TypeError(`AEP Service does not advertise ${command}.`);
822
+ }
823
+ return new URL(
824
+ (0, import_core.commandPathFromInspect)(inspect.document, command),
825
+ normalizeServiceUrl(serviceUrl)
826
+ );
827
+ }
828
+ async function resolveClientAssertion(options, inspect, command) {
829
+ if (options.clientAssertion !== void 0) {
830
+ return options.clientAssertion;
831
+ }
832
+ if (options.clientAssertionSigner === void 0) {
833
+ throw new TypeError("AEP command requires clientAssertion or clientAssertionSigner.");
834
+ }
835
+ if (options.agentDid === void 0) {
836
+ throw new TypeError("AEP command signing requires agentDid.");
837
+ }
838
+ return signClientAssertion({
839
+ agentDid: options.agentDid,
840
+ command,
841
+ serviceDid: inspect.document.service.did,
842
+ signer: options.clientAssertionSigner,
843
+ ...options.assertionClock === void 0 ? {} : { clock: options.assertionClock },
844
+ ...options.assertionJti === void 0 ? {} : { jti: options.assertionJti },
845
+ ...inspect.document.core.signing_algorithms === void 0 ? {} : { signingAlgorithms: inspect.document.core.signing_algorithms },
846
+ ...options.assertionTtlSeconds === void 0 ? {} : { ttlSeconds: options.assertionTtlSeconds }
847
+ });
848
+ }
849
+ function assertionOptionsWithDefinedValues(options) {
850
+ return {
851
+ ...options.assertionClock === void 0 ? {} : { assertionClock: options.assertionClock },
852
+ ...options.assertionJti === void 0 ? {} : { assertionJti: options.assertionJti },
853
+ ...options.assertionTtlSeconds === void 0 ? {} : { assertionTtlSeconds: options.assertionTtlSeconds }
854
+ };
855
+ }
856
+ function revokeSelectorBody(options) {
857
+ if (options.allGrantTypes === true) {
858
+ return {
859
+ all_grant_types: "true"
860
+ };
861
+ }
862
+ if (options.credentialId !== void 0) {
863
+ return {
864
+ credential_id: options.credentialId
865
+ };
866
+ }
867
+ return {
868
+ grant_type: options.grantType
869
+ };
870
+ }
871
+ function parseGrantResponse(grantType, value) {
872
+ if (import_core.AEP_BUILT_IN_GRANT_TYPES.includes(grantType)) {
873
+ return (0, import_core.parseBuiltInGrantResponse)(grantType, value);
874
+ }
875
+ if (isRecord(value)) {
876
+ return value;
877
+ }
878
+ throw new TypeError("Invalid AEP Grant response.");
879
+ }
880
+ function isRecord(value) {
881
+ return value !== null && typeof value === "object" && !Array.isArray(value);
882
+ }
883
+ function requireRecord(value, label) {
884
+ if (!isRecord(value)) {
885
+ throw new TypeError(`${label} must be an object.`);
886
+ }
887
+ return value;
888
+ }
889
+ function requireString(record, key) {
890
+ const value = record[key];
891
+ if (typeof value !== "string" || value.length === 0) {
892
+ throw new TypeError(`${key} must be a non-empty string.`);
893
+ }
894
+ return value;
895
+ }
896
+ function requireBoolean(record, key) {
897
+ const value = record[key];
898
+ if (typeof value !== "boolean") {
899
+ throw new TypeError(`${key} must be a boolean.`);
900
+ }
901
+ return value;
902
+ }
903
+ function requireStringArray(record, key) {
904
+ const value = record[key];
905
+ if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) {
906
+ throw new TypeError(`${key} must be a string array.`);
907
+ }
908
+ return [...value];
909
+ }
910
+ function parseManagedAgentStatus(value) {
911
+ if (value !== "active" && value !== "revoked" && value !== "suspended" && value !== "terminated") {
912
+ throw new TypeError("status must be a supported managed Agent status.");
913
+ }
914
+ return value;
915
+ }
916
+ function isInspectServiceResult(value) {
917
+ return isRecord(value) && isRecord(value["document"]) && value["inspectUrl"] instanceof URL && typeof value["commandUrl"] === "function";
918
+ }
919
+ function randomJti() {
920
+ return `jti_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`;
921
+ }
922
+ function credentialIdFromGrantResult(credential) {
923
+ if (typeof credential.credential_id !== "string" || credential.credential_id.length === 0) {
924
+ throw new TypeError("AEP Grant response does not include credential_id.");
925
+ }
926
+ return credential.credential_id;
927
+ }
928
+ function expiresAtFromGrantResult(credential) {
929
+ return typeof credential.expires_at === "string" ? credential.expires_at : void 0;
930
+ }
931
+ function sessionCredentialKey(record) {
932
+ return `${record.serviceDid}\0${record.credentialId}`;
933
+ }
934
+ function cloneCredential(record) {
935
+ return {
936
+ ...record,
937
+ credential: structuredClone(record.credential)
938
+ };
939
+ }
940
+ function cloneAgentIdentity(identity) {
941
+ return {
942
+ ...identity,
943
+ ...identity.metadata === void 0 ? {} : { metadata: structuredClone(identity.metadata) },
944
+ signingAlgorithms: [...identity.signingAlgorithms]
945
+ };
946
+ }
947
+ function cloneCachedInspect(result) {
948
+ return {
949
+ ...result,
950
+ document: structuredClone(result.document)
951
+ };
952
+ }
953
+ function metadataString(metadata, key) {
954
+ const value = metadata[key];
955
+ if (typeof value !== "string" || value.length === 0) {
956
+ throw new TypeError(`Platform-hosted Agent identity metadata is missing ${key}.`);
957
+ }
958
+ return value;
959
+ }
960
+ function isOAuthBearerGrantResponse(credential) {
961
+ return "access_token" in credential && credential.token_type === "Bearer";
962
+ }
963
+ function isApiKeyGrantResponse(credential) {
964
+ return "api_key" in credential && "header" in credential;
965
+ }
966
+ function isBasicGrantResponse(credential) {
967
+ return "username" in credential && "password" in credential;
968
+ }
969
+ function base64(value) {
970
+ return Buffer.from(value, "utf8").toString("base64");
971
+ }
972
+ function preferredSigningAlgorithm(algorithms) {
973
+ const algorithm = algorithms.find((candidate) => candidate === "ES256" || candidate === "EdDSA");
974
+ if (algorithm === void 0) {
975
+ throw new TypeError("AEP Service does not advertise a supported JOSE signing algorithm.");
976
+ }
977
+ return algorithm;
978
+ }
979
+ async function throwCommandError(response, command) {
980
+ if (response.ok) {
981
+ return;
982
+ }
983
+ const problem = await readProblemDetails(response);
984
+ throw new AepCommandError(
985
+ `AEP ${command} failed with HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""}.`,
986
+ response.status,
987
+ problem
988
+ );
989
+ }
990
+ async function readProblemDetails(response) {
991
+ try {
992
+ return (0, import_core.parseProblemDetails)(await response.json());
993
+ } catch {
994
+ return void 0;
995
+ }
996
+ }
997
+ // Annotate the CommonJS export names for ESM import in node:
998
+ 0 && (module.exports = {
999
+ AepCommandError,
1000
+ AepInspectError,
1001
+ buildClientAssertionClaims,
1002
+ clientAssertionAuthenticationHeaders,
1003
+ createAepAgent,
1004
+ createInMemoryAgentIdentityStore,
1005
+ createInMemoryInspectCache,
1006
+ createInMemorySessionCredentialStore,
1007
+ createJwtClientAssertionSigner,
1008
+ createPlatformDelegatedSigner,
1009
+ createPlatformIdentityProvider,
1010
+ createRandomIdempotencyKeyProvider,
1011
+ credentialPresentationHeaders,
1012
+ discoverPlatform,
1013
+ enrollService,
1014
+ grantService,
1015
+ inspectService,
1016
+ protectedResourceAuthenticationHeaders,
1017
+ provisionPlatformIdentity,
1018
+ revokeService,
1019
+ selectGrantType,
1020
+ sessionCredentialRecordFromGrantResult,
1021
+ signClientAssertion,
1022
+ statusService
1023
+ });
1024
+ //# sourceMappingURL=index.cjs.map