@aep-foundation/platform 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.js ADDED
@@ -0,0 +1,810 @@
1
+ // src/index.ts
2
+ import {
3
+ AEP_MEDIA_TYPE,
4
+ AEP_PROBLEM_MEDIA_TYPE,
5
+ createProblemDetails,
6
+ decodeJwtUnverified,
7
+ didWebDocumentUrl,
8
+ signClientAssertionJwt,
9
+ verifyClientAssertionJwt
10
+ } from "@aep-foundation/core";
11
+ var packageName = "@aep-foundation/platform";
12
+ var platformHostedIdentityDraft = "draft-kavian-aep-platform-hosted-identity-00";
13
+ var defaultAssertionLifetimeSeconds = 300;
14
+ var InMemoryManagedAgentRegistry = class {
15
+ #identities = /* @__PURE__ */ new Map();
16
+ constructor(identities = []) {
17
+ identities.forEach((identity) => this.upsert(identity));
18
+ }
19
+ get(agentDid) {
20
+ const identity = this.#identities.get(agentDid);
21
+ return identity === void 0 ? void 0 : cloneManagedAgentIdentity(identity);
22
+ }
23
+ list(filter = {}) {
24
+ return Array.from(this.#identities.values()).filter(
25
+ (identity) => filter.accountId === void 0 || identity.accountId === filter.accountId
26
+ ).filter((identity) => filter.status === void 0 || identity.status === filter.status).filter((identity) => filter.tenantId === void 0 || identity.tenantId === filter.tenantId).map(cloneManagedAgentIdentity);
27
+ }
28
+ remove(agentDid) {
29
+ return this.#identities.delete(agentDid);
30
+ }
31
+ setStatus(agentDid, status) {
32
+ const identity = this.#identities.get(agentDid);
33
+ if (identity === void 0) {
34
+ throw new Error(`Managed Agent identity not found: ${agentDid}.`);
35
+ }
36
+ const updated = {
37
+ ...identity,
38
+ status,
39
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
40
+ };
41
+ this.#identities.set(agentDid, updated);
42
+ return cloneManagedAgentIdentity(updated);
43
+ }
44
+ upsert(identity) {
45
+ assertNonEmpty("agentDid", identity.agentDid);
46
+ const cloned = cloneManagedAgentIdentity(identity);
47
+ this.#identities.set(cloned.agentDid, cloned);
48
+ return cloneManagedAgentIdentity(cloned);
49
+ }
50
+ };
51
+ function createManagedAgentIdentity(options) {
52
+ assertNonEmpty("agentDid", options.agentDid);
53
+ const now = (options.clock ?? (() => /* @__PURE__ */ new Date()))().toISOString();
54
+ return {
55
+ agentDid: options.agentDid,
56
+ createdAt: now,
57
+ metadata: structuredClone(options.metadata ?? {}),
58
+ status: options.status ?? "active",
59
+ updatedAt: now,
60
+ ...options.accountId === void 0 ? {} : { accountId: options.accountId },
61
+ ...options.subjectDid === void 0 ? {} : { subjectDid: options.subjectDid },
62
+ ...options.tenantId === void 0 ? {} : { tenantId: options.tenantId }
63
+ };
64
+ }
65
+ function updateManagedAgentIdentity(identity, update, clock = () => /* @__PURE__ */ new Date()) {
66
+ return {
67
+ ...cloneManagedAgentIdentity(identity),
68
+ ...update,
69
+ metadata: update.metadata === void 0 ? cloneRecord(identity.metadata) : {
70
+ ...cloneRecord(identity.metadata),
71
+ ...cloneRecord(update.metadata)
72
+ },
73
+ updatedAt: clock().toISOString()
74
+ };
75
+ }
76
+ function createPlatformDiscoveryDocument(options) {
77
+ assertNonEmpty("didUrlTemplate", options.didUrlTemplate);
78
+ assertNonEmpty("endpointBase", options.endpointBase);
79
+ assertNonEmpty("lifecycle endpoint", options.endpoints.lifecycle);
80
+ assertNonEmpty("list endpoint", options.endpoints.list);
81
+ assertNonEmpty("platformName", options.platformName);
82
+ assertNonEmpty("provision endpoint", options.endpoints.provision);
83
+ assertNonEmpty("sign endpoint", options.endpoints.sign);
84
+ const defaultLifetimeSeconds = options.defaultLifetimeSeconds ?? defaultAssertionLifetimeSeconds;
85
+ validateLifetimeSeconds(defaultLifetimeSeconds, options.maxLifetimeSeconds);
86
+ if (options.signingAlgorithms.length === 0) {
87
+ throw new TypeError("signingAlgorithms must include at least one algorithm.");
88
+ }
89
+ const didMethods = [...options.didMethods ?? ["did:web"]];
90
+ if (didMethods.length === 0) {
91
+ throw new TypeError("didMethods must include at least one DID method.");
92
+ }
93
+ return {
94
+ aep_version: options.aepVersion ?? "1.0",
95
+ endpoints: {
96
+ ...options.endpoints.hostedVerification === void 0 ? {} : { hosted_verification: options.endpoints.hostedVerification },
97
+ lifecycle: options.endpoints.lifecycle,
98
+ list: options.endpoints.list,
99
+ provision: options.endpoints.provision,
100
+ sign: options.endpoints.sign
101
+ },
102
+ http: {
103
+ endpoint_base: options.endpointBase
104
+ },
105
+ identity: {
106
+ did_methods: didMethods,
107
+ did_url_template: options.didUrlTemplate
108
+ },
109
+ platform: {
110
+ ...options.platformDid === void 0 ? {} : { did: options.platformDid },
111
+ hosted_verification: options.hostedVerification ?? false,
112
+ name: options.platformName
113
+ },
114
+ signing: {
115
+ algorithms: [...options.signingAlgorithms],
116
+ default_lifetime_seconds: String(defaultLifetimeSeconds)
117
+ }
118
+ };
119
+ }
120
+ function createServiceScopedAgentDid(options) {
121
+ assertNonEmpty("agentDidId", options.agentDidId);
122
+ assertNonEmpty("host", options.host);
123
+ const encodedHost = encodeURIComponent(options.host);
124
+ const pathPrefix = options.pathPrefix ?? "agents";
125
+ const pathParts = pathPrefix.split("/").filter((part) => part.length > 0).map((part) => encodeURIComponent(part));
126
+ return ["did:web", encodedHost, ...pathParts, encodeURIComponent(options.agentDidId)].join(":");
127
+ }
128
+ function createPlatformAgentIdentity(options) {
129
+ assertNonEmpty("agentDid", options.agentDid);
130
+ assertNonEmpty("agentIdentityId", options.agentIdentityId);
131
+ assertNonEmpty("serviceDid", options.serviceDid);
132
+ if (options.signingAlgorithms.length === 0) {
133
+ throw new TypeError("signingAlgorithms must include at least one algorithm.");
134
+ }
135
+ const now = (options.clock ?? (() => /* @__PURE__ */ new Date()))().toISOString();
136
+ const keyId = options.keyId ?? options.agentDid;
137
+ return {
138
+ agent_did: options.agentDid,
139
+ agent_identity_id: options.agentIdentityId,
140
+ created_at: now,
141
+ did_document_url: options.didDocumentUrl ?? didWebDocumentUrl(options.agentDid).toString(),
142
+ key_id: keyId,
143
+ service_did: options.serviceDid,
144
+ signing_algorithms: [...options.signingAlgorithms],
145
+ status: options.status ?? "active",
146
+ updated_at: now
147
+ };
148
+ }
149
+ function createPlatformAgentIdentityListResponse(identities, total = identities.length) {
150
+ return {
151
+ count: String(identities.length),
152
+ data: identities.map((identity) => structuredClone(identity)),
153
+ total: String(total)
154
+ };
155
+ }
156
+ function createPlatformLifecycleRequest(options) {
157
+ return {
158
+ status: options.status
159
+ };
160
+ }
161
+ function createPlatformProvisionRequest(options) {
162
+ assertNonEmpty("idempotencyKey", options.idempotencyKey);
163
+ assertNonEmpty("serviceDid", options.serviceDid);
164
+ return {
165
+ idempotency_key: options.idempotencyKey,
166
+ service_did: options.serviceDid
167
+ };
168
+ }
169
+ function createPlatformEnrollRequest(options) {
170
+ assertUsableIdentity(options.identity);
171
+ assertNonEmpty("idempotencyKey", options.idempotencyKey);
172
+ return {
173
+ agent_did: options.identity.agentDid,
174
+ ...options.claims === void 0 ? {} : { claims: cloneRecord(options.claims) },
175
+ idempotency_key: options.idempotencyKey
176
+ };
177
+ }
178
+ function createPlatformClientAssertionClaims(options) {
179
+ assertUsableIdentity(options.identity);
180
+ assertNonEmpty("serviceDid", options.serviceDid);
181
+ assertNonEmpty("jti", options.jti);
182
+ const issuedAt = toEpochSeconds(options.issuedAt ?? /* @__PURE__ */ new Date());
183
+ const lifetimeSeconds = validateLifetimeSeconds(
184
+ options.lifetimeSeconds ?? defaultAssertionLifetimeSeconds,
185
+ options.maxLifetimeSeconds
186
+ );
187
+ return {
188
+ aud: options.serviceDid,
189
+ exp: issuedAt + lifetimeSeconds,
190
+ iat: issuedAt,
191
+ iss: options.identity.agentDid,
192
+ jti: options.jti,
193
+ op: options.command,
194
+ sub: options.identity.agentDid
195
+ };
196
+ }
197
+ function createManagedAgentDidDocument(options) {
198
+ assertUsableIdentity(options.identity);
199
+ if (options.verificationMethods.length === 0) {
200
+ throw new TypeError("verificationMethods must include at least one method.");
201
+ }
202
+ const document = {
203
+ "@context": ["https://www.w3.org/ns/did/v1", ...options.additionalContexts ?? []],
204
+ id: options.identity.agentDid,
205
+ ...options.controller === void 0 ? {} : { controller: options.controller },
206
+ verificationMethod: options.verificationMethods.map(
207
+ (method, index) => createDidVerificationMethod(options.identity.agentDid, method, index)
208
+ ),
209
+ ...options.service === void 0 ? {} : { service: options.service.map(cloneDidService) }
210
+ };
211
+ for (const relationship of relationshipNames()) {
212
+ const methodIds = document.verificationMethod?.filter(
213
+ (method, index) => (options.verificationMethods[index]?.relationships ?? ["authentication"]).includes(
214
+ relationship
215
+ )
216
+ ).map((method) => method.id);
217
+ if (methodIds !== void 0 && methodIds.length > 0) {
218
+ document[relationship] = methodIds;
219
+ }
220
+ }
221
+ return document;
222
+ }
223
+ async function publishManagedAgentDidDocument(options) {
224
+ const document = createManagedAgentDidDocument(options);
225
+ return options.publisher.publish(document);
226
+ }
227
+ function createJwtPlatformDelegatedSigner(options) {
228
+ return (claims, context) => signClientAssertionJwt(claims, {
229
+ alg: options.alg ?? preferredSigningAlgorithm(context.signingAlgorithms),
230
+ key: options.key,
231
+ ...options.kid === void 0 ? {} : { kid: options.kid },
232
+ ...options.typ === void 0 ? {} : { typ: options.typ }
233
+ });
234
+ }
235
+ async function signPlatformClientAssertion(options) {
236
+ const claims = createPlatformClientAssertionClaims(options);
237
+ return options.signer(claims, {
238
+ identity: options.identity,
239
+ signingAlgorithms: [...options.signingAlgorithms ?? ["EdDSA", "ES256"]]
240
+ });
241
+ }
242
+ function createPlatformSignRequest(options) {
243
+ assertNonEmpty("jti", options.jti);
244
+ assertNonEmpty("serviceDid", options.serviceDid);
245
+ const lifetimeSeconds = options.lifetimeSeconds === void 0 ? void 0 : validateLifetimeSeconds(options.lifetimeSeconds, options.maxLifetimeSeconds);
246
+ return {
247
+ jti: options.jti,
248
+ ...lifetimeSeconds === void 0 ? {} : { lifetime_seconds: String(lifetimeSeconds) },
249
+ op: options.command,
250
+ service_did: options.serviceDid
251
+ };
252
+ }
253
+ function createPlatformSignResponse(options) {
254
+ assertUsableIdentity(options.identity);
255
+ assertNonEmpty("clientAssertion", options.clientAssertion);
256
+ assertNonEmpty("jti", options.jti);
257
+ assertNonEmpty("serviceDid", options.serviceDid);
258
+ const issuedAt = toEpochSeconds(options.issuedAt ?? /* @__PURE__ */ new Date());
259
+ const lifetimeSeconds = validateLifetimeSeconds(
260
+ options.lifetimeSeconds ?? defaultAssertionLifetimeSeconds,
261
+ options.maxLifetimeSeconds
262
+ );
263
+ return {
264
+ agent_did: options.identity.agentDid,
265
+ client_assertion: options.clientAssertion,
266
+ expires_at: epochSecondsToIso(issuedAt + lifetimeSeconds),
267
+ issued_at: epochSecondsToIso(issuedAt),
268
+ jti: options.jti,
269
+ service_did: options.serviceDid
270
+ };
271
+ }
272
+ function createPlatformVerificationRequest(options) {
273
+ assertNonEmpty("clientAssertion", options.clientAssertion);
274
+ assertNonEmpty("serviceDid", options.serviceDid);
275
+ return {
276
+ client_assertion: options.clientAssertion,
277
+ op: options.command,
278
+ service_did: options.serviceDid
279
+ };
280
+ }
281
+ function createPlatformVerificationResponse(options) {
282
+ assertNonEmpty("reason", options.reason);
283
+ assertNonEmpty("serviceDid", options.serviceDid);
284
+ return {
285
+ ...options.agentDid === void 0 ? {} : { agent_did: options.agentDid },
286
+ ...options.agentIdentityId === void 0 ? {} : { agent_identity_id: options.agentIdentityId },
287
+ ...options.command === void 0 ? {} : { op: options.command },
288
+ reason: options.reason,
289
+ service_did: options.serviceDid,
290
+ ...options.status === void 0 ? {} : { status: options.status },
291
+ verified: options.verified
292
+ };
293
+ }
294
+ function createAepPlatform(options) {
295
+ assertNonEmpty("didHost", options.didHost);
296
+ assertNonEmpty("didUrlTemplate", options.didUrlTemplate);
297
+ if (options.signingAlgorithms.length === 0) {
298
+ throw new TypeError("signingAlgorithms must include at least one algorithm.");
299
+ }
300
+ const clock = options.clock ?? (() => /* @__PURE__ */ new Date());
301
+ const idGenerator = options.idGenerator ?? randomPlatformId;
302
+ const lifecyclePolicy = options.lifecyclePolicy ?? defaultLifecyclePolicy;
303
+ const authorizer = options.authorizer ?? {};
304
+ const discoveryDocument = createPlatformDiscoveryDocument({
305
+ ...options.discovery,
306
+ defaultLifetimeSeconds: options.defaultLifetimeSeconds ?? defaultAssertionLifetimeSeconds,
307
+ didUrlTemplate: options.didUrlTemplate,
308
+ signingAlgorithms: options.signingAlgorithms
309
+ });
310
+ return {
311
+ discovery() {
312
+ return ok(200, discoveryDocument);
313
+ },
314
+ async getDidDocument(agentIdentityId, context = {}) {
315
+ const identity = await authorizedIdentity(
316
+ agentIdentityId,
317
+ authorizer,
318
+ options.identityStore,
319
+ context
320
+ );
321
+ if (identity === void 0) {
322
+ return problem(404, "not_recognized", "Identity not recognized.");
323
+ }
324
+ const verificationMethod = await options.keyStore.didVerificationMethod(identity, context);
325
+ return ok(
326
+ 200,
327
+ createManagedAgentDidDocument({
328
+ identity: managedIdentityFromRecord(identity),
329
+ verificationMethods: [verificationMethod]
330
+ })
331
+ );
332
+ },
333
+ async getIdentity(agentIdentityId, context = {}) {
334
+ const identity = await authorizedIdentity(
335
+ agentIdentityId,
336
+ authorizer,
337
+ options.identityStore,
338
+ context
339
+ );
340
+ if (identity === void 0) {
341
+ return problem(404, "not_recognized", "Identity not recognized.");
342
+ }
343
+ return ok(200, platformIdentityFromRecord(identity));
344
+ },
345
+ async list(query = {}, context = {}) {
346
+ if (await authorizer.authorizeList?.(context) === false) {
347
+ return problem(404, "not_recognized", "Identity not recognized.");
348
+ }
349
+ const result = await options.identityStore.list(query, context);
350
+ return ok(
351
+ 200,
352
+ createPlatformAgentIdentityListResponse(
353
+ result.identities.map(platformIdentityFromRecord),
354
+ result.total
355
+ )
356
+ );
357
+ },
358
+ async provision(body, context = {}) {
359
+ const request = parsePlatformProvisionRequestBody(body);
360
+ if (await authorizer.authorizeProvision?.(request, context) === false) {
361
+ return problem(404, "not_recognized", "Identity not recognized.");
362
+ }
363
+ if (!await options.serviceDidResolver.resolve(request.service_did, context)) {
364
+ return problem(400, "invalid_request", "Service DID could not be resolved.");
365
+ }
366
+ const requestHash = stableStringify(request);
367
+ const existing = await options.idempotencyStore.get(request.idempotency_key, context);
368
+ if (existing !== void 0) {
369
+ if (existing.requestHash !== requestHash) {
370
+ return problem(409, "idempotency_conflict", "Idempotency key already used.");
371
+ }
372
+ return ok(200, existing.response);
373
+ }
374
+ const generatedId = idGenerator();
375
+ assertNonEmpty("generated identity id", generatedId);
376
+ const now = clock().toISOString();
377
+ const agentDidId = generatedId;
378
+ const agentDid = createServiceScopedAgentDid({
379
+ agentDidId,
380
+ host: options.didHost,
381
+ pathPrefix: options.didPathPrefix ?? "agents"
382
+ });
383
+ const identity = {
384
+ agentDid,
385
+ agentDidId,
386
+ agentIdentityId: generatedId.startsWith("pai_") ? generatedId : `pai_${generatedId}`,
387
+ createdAt: now,
388
+ didDocumentUrl: renderDidUrlTemplate(options.didUrlTemplate, agentDidId),
389
+ keyId: agentDid,
390
+ serviceDid: request.service_did,
391
+ signingAlgorithms: [...options.signingAlgorithms],
392
+ status: "active",
393
+ updatedAt: now
394
+ };
395
+ await options.keyStore.create(identity, context);
396
+ await options.identityStore.create(identity, context);
397
+ const response = platformIdentityFromRecord(identity);
398
+ await options.idempotencyStore.set(
399
+ {
400
+ idempotencyKey: request.idempotency_key,
401
+ requestHash,
402
+ response
403
+ },
404
+ context
405
+ );
406
+ return ok(200, response);
407
+ },
408
+ async sign(agentIdentityId, body, context = {}) {
409
+ const request = parsePlatformSignRequestBody(body);
410
+ const identity = await authorizedIdentity(
411
+ agentIdentityId,
412
+ authorizer,
413
+ options.identityStore,
414
+ context
415
+ );
416
+ if (identity === void 0 || identity.serviceDid !== request.service_did) {
417
+ return problem(404, "not_recognized", "Identity not recognized.");
418
+ }
419
+ if (!await lifecyclePolicy.canSign(identity, context)) {
420
+ return problem(403, lifecycleProblemCode(identity.status), "Identity cannot sign.");
421
+ }
422
+ if (!await options.serviceDidResolver.resolve(request.service_did, context)) {
423
+ return problem(400, "invalid_request", "Service DID could not be resolved.");
424
+ }
425
+ const issuedAt = context.now ?? clock();
426
+ const lifetimeSeconds = request.lifetime_seconds === void 0 ? void 0 : Number(request.lifetime_seconds);
427
+ const managedIdentity = managedIdentityFromRecord(identity);
428
+ const claims = createPlatformClientAssertionClaims({
429
+ command: request.op,
430
+ identity: managedIdentity,
431
+ issuedAt,
432
+ jti: request.jti,
433
+ ...options.maxLifetimeSeconds === void 0 ? {} : { maxLifetimeSeconds: options.maxLifetimeSeconds },
434
+ serviceDid: request.service_did,
435
+ ...lifetimeSeconds === void 0 ? {} : { lifetimeSeconds }
436
+ });
437
+ const clientAssertion = await options.keyStore.sign(identity, claims, context);
438
+ return ok(
439
+ 200,
440
+ createPlatformSignResponse({
441
+ clientAssertion,
442
+ identity: managedIdentity,
443
+ issuedAt,
444
+ jti: request.jti,
445
+ ...options.maxLifetimeSeconds === void 0 ? {} : { maxLifetimeSeconds: options.maxLifetimeSeconds },
446
+ serviceDid: request.service_did,
447
+ ...lifetimeSeconds === void 0 ? {} : { lifetimeSeconds }
448
+ })
449
+ );
450
+ },
451
+ async updateIdentity(agentIdentityId, body, context = {}) {
452
+ const request = parsePlatformLifecycleRequestBody(body);
453
+ const identity = await authorizedIdentity(
454
+ agentIdentityId,
455
+ authorizer,
456
+ options.identityStore,
457
+ context
458
+ );
459
+ if (identity === void 0) {
460
+ return problem(404, "not_recognized", "Identity not recognized.");
461
+ }
462
+ if (!await lifecyclePolicy.canTransition(identity, request.status, context)) {
463
+ return problem(
464
+ 403,
465
+ lifecycleProblemCode(identity.status),
466
+ "Lifecycle transition rejected."
467
+ );
468
+ }
469
+ const updated = await options.identityStore.update(
470
+ agentIdentityId,
471
+ {
472
+ status: request.status,
473
+ updatedAt: clock().toISOString()
474
+ },
475
+ context
476
+ );
477
+ if (updated === void 0) {
478
+ return problem(404, "not_recognized", "Identity not recognized.");
479
+ }
480
+ return ok(200, platformIdentityFromRecord(updated));
481
+ },
482
+ async verify(body, context = {}) {
483
+ const request = parsePlatformVerificationRequestBody(body);
484
+ try {
485
+ const decoded = decodeJwtUnverified(request.client_assertion);
486
+ const agentDid = requireString(decoded.payload, "iss");
487
+ const subject = requireString(decoded.payload, "sub");
488
+ const jti = requireString(decoded.payload, "jti");
489
+ const expiresAt = requireNumber(decoded.payload, "exp");
490
+ if (agentDid !== subject) {
491
+ return ok(200, unrecognizedVerification(request, "not_recognized"));
492
+ }
493
+ const identity = await options.identityStore.findByAgentDid(agentDid, context);
494
+ if (identity === void 0 || identity.serviceDid !== request.service_did || !await lifecyclePolicy.canVerify(identity, context)) {
495
+ return ok(200, unrecognizedVerification(request, "not_recognized"));
496
+ }
497
+ const claims = await verifyClientAssertionJwt(request.client_assertion, {
498
+ algorithms: identity.signingAlgorithms,
499
+ audience: request.service_did,
500
+ currentDate: context.now ?? clock(),
501
+ issuer: agentDid,
502
+ key: await options.keyStore.verificationKey(identity, context),
503
+ subject: agentDid
504
+ });
505
+ if (claims.op !== request.op) {
506
+ return ok(200, unrecognizedVerification(request, "not_recognized"));
507
+ }
508
+ const replayKey = [request.service_did, request.op, agentDid, jti].join("");
509
+ const consumed = await options.replayStore.consume(
510
+ replayKey,
511
+ new Date(expiresAt * 1e3),
512
+ context
513
+ );
514
+ if (!consumed) {
515
+ return ok(200, unrecognizedVerification(request, "not_recognized"));
516
+ }
517
+ return ok(
518
+ 200,
519
+ createPlatformVerificationResponse({
520
+ agentDid: identity.agentDid,
521
+ agentIdentityId: identity.agentIdentityId,
522
+ command: request.op,
523
+ reason: "verified",
524
+ serviceDid: request.service_did,
525
+ status: identity.status,
526
+ verified: true
527
+ })
528
+ );
529
+ } catch {
530
+ return ok(200, unrecognizedVerification(request, "not_recognized"));
531
+ }
532
+ }
533
+ };
534
+ }
535
+ var defaultLifecyclePolicy = {
536
+ canSign(identity) {
537
+ return identity.status === "active";
538
+ },
539
+ canTransition() {
540
+ return true;
541
+ },
542
+ canVerify(identity) {
543
+ return identity.status === "active";
544
+ }
545
+ };
546
+ function ok(status, body) {
547
+ return {
548
+ body,
549
+ contentType: AEP_MEDIA_TYPE,
550
+ status
551
+ };
552
+ }
553
+ function problem(status, code, title) {
554
+ return {
555
+ body: createProblemDetails({
556
+ code,
557
+ status,
558
+ title
559
+ }),
560
+ contentType: AEP_PROBLEM_MEDIA_TYPE,
561
+ status
562
+ };
563
+ }
564
+ async function authorizedIdentity(agentIdentityId, authorizer, store, context) {
565
+ const identity = await store.get(agentIdentityId, context);
566
+ if (identity === void 0) {
567
+ return void 0;
568
+ }
569
+ if (await authorizer.authorizeIdentityAccess?.(identity, context) === false) {
570
+ return void 0;
571
+ }
572
+ return clonePlatformIdentityRecord(identity);
573
+ }
574
+ function platformIdentityFromRecord(identity) {
575
+ return {
576
+ agent_did: identity.agentDid,
577
+ agent_identity_id: identity.agentIdentityId,
578
+ created_at: identity.createdAt,
579
+ did_document_url: identity.didDocumentUrl,
580
+ key_id: identity.keyId,
581
+ service_did: identity.serviceDid,
582
+ signing_algorithms: [...identity.signingAlgorithms],
583
+ status: identity.status,
584
+ updated_at: identity.updatedAt
585
+ };
586
+ }
587
+ function managedIdentityFromRecord(identity) {
588
+ return {
589
+ agentDid: identity.agentDid,
590
+ createdAt: identity.createdAt,
591
+ metadata: {
592
+ agent_did_id: identity.agentDidId,
593
+ agent_identity_id: identity.agentIdentityId,
594
+ did_document_url: identity.didDocumentUrl,
595
+ key_id: identity.keyId,
596
+ service_did: identity.serviceDid
597
+ },
598
+ status: identity.status,
599
+ updatedAt: identity.updatedAt
600
+ };
601
+ }
602
+ function clonePlatformIdentityRecord(identity) {
603
+ return {
604
+ ...identity,
605
+ signingAlgorithms: [...identity.signingAlgorithms]
606
+ };
607
+ }
608
+ function parsePlatformProvisionRequestBody(value) {
609
+ const body = requireRecord(value, "Platform provision request");
610
+ return createPlatformProvisionRequest({
611
+ idempotencyKey: requireString(body, "idempotency_key"),
612
+ serviceDid: requireString(body, "service_did")
613
+ });
614
+ }
615
+ function parsePlatformLifecycleRequestBody(value) {
616
+ const body = requireRecord(value, "Platform lifecycle request");
617
+ const status = requireString(body, "status");
618
+ if (!isManagedAgentStatus(status)) {
619
+ throw new TypeError("status must be a supported managed Agent status.");
620
+ }
621
+ return createPlatformLifecycleRequest({ status });
622
+ }
623
+ function parsePlatformSignRequestBody(value) {
624
+ const body = requireRecord(value, "Platform sign request");
625
+ const command = requireString(body, "op");
626
+ if (!isAuthenticatedCommand(command)) {
627
+ throw new TypeError("op must be an AEP authenticated command.");
628
+ }
629
+ const lifetimeSeconds = body["lifetime_seconds"] === void 0 ? void 0 : requireString(body, "lifetime_seconds");
630
+ return createPlatformSignRequest({
631
+ command,
632
+ jti: requireString(body, "jti"),
633
+ serviceDid: requireString(body, "service_did"),
634
+ ...lifetimeSeconds === void 0 ? {} : { lifetimeSeconds: Number(lifetimeSeconds) }
635
+ });
636
+ }
637
+ function parsePlatformVerificationRequestBody(value) {
638
+ const body = requireRecord(value, "Platform verification request");
639
+ const command = requireString(body, "op");
640
+ if (!isAuthenticatedCommand(command)) {
641
+ throw new TypeError("op must be an AEP authenticated command.");
642
+ }
643
+ return createPlatformVerificationRequest({
644
+ clientAssertion: requireString(body, "client_assertion"),
645
+ command,
646
+ serviceDid: requireString(body, "service_did")
647
+ });
648
+ }
649
+ function unrecognizedVerification(request, reason) {
650
+ return createPlatformVerificationResponse({
651
+ reason,
652
+ serviceDid: request.service_did,
653
+ verified: false
654
+ });
655
+ }
656
+ function renderDidUrlTemplate(template, agentDidId) {
657
+ if (!template.includes("{agent_did_id}")) {
658
+ throw new TypeError("didUrlTemplate must include {agent_did_id}.");
659
+ }
660
+ return template.replace("{agent_did_id}", encodeURIComponent(agentDidId));
661
+ }
662
+ function lifecycleProblemCode(status) {
663
+ if (status === "terminated") {
664
+ return "identity_terminated";
665
+ }
666
+ if (status === "suspended" || status === "revoked") {
667
+ return "identity_suspended";
668
+ }
669
+ return "identity_unavailable";
670
+ }
671
+ function stableStringify(value) {
672
+ if (Array.isArray(value)) {
673
+ return `[${value.map(stableStringify).join(",")}]`;
674
+ }
675
+ if (typeof value === "object" && value !== null) {
676
+ return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`).join(",")}}`;
677
+ }
678
+ return JSON.stringify(value);
679
+ }
680
+ function randomPlatformId() {
681
+ return globalThis.crypto.randomUUID().replaceAll("-", "");
682
+ }
683
+ function requireRecord(value, label) {
684
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
685
+ throw new TypeError(`${label} must be an object.`);
686
+ }
687
+ return value;
688
+ }
689
+ function requireString(record, key) {
690
+ const value = record[key];
691
+ if (typeof value !== "string" || value.trim().length === 0) {
692
+ throw new TypeError(`${key} must be a non-empty string.`);
693
+ }
694
+ return value;
695
+ }
696
+ function requireNumber(record, key) {
697
+ const value = record[key];
698
+ if (typeof value !== "number" || !Number.isInteger(value)) {
699
+ throw new TypeError(`${key} must be an integer.`);
700
+ }
701
+ return value;
702
+ }
703
+ function isAuthenticatedCommand(value) {
704
+ return value === "enroll" || value === "grant" || value === "revoke" || value === "status";
705
+ }
706
+ function isManagedAgentStatus(value) {
707
+ return value === "active" || value === "revoked" || value === "suspended" || value === "terminated";
708
+ }
709
+ function assertUsableIdentity(identity) {
710
+ assertNonEmpty("agentDid", identity.agentDid);
711
+ if (identity.status !== "active") {
712
+ throw new Error(`Managed Agent identity is not active: ${identity.agentDid}.`);
713
+ }
714
+ }
715
+ function assertNonEmpty(label, value) {
716
+ if (value.trim().length === 0) {
717
+ throw new TypeError(`${label} must be a non-empty string.`);
718
+ }
719
+ }
720
+ function cloneManagedAgentIdentity(identity) {
721
+ return {
722
+ ...identity,
723
+ metadata: cloneRecord(identity.metadata)
724
+ };
725
+ }
726
+ function cloneRecord(record) {
727
+ return structuredClone(record);
728
+ }
729
+ function toEpochSeconds(value) {
730
+ const epochSeconds = typeof value === "number" ? value : Math.floor(value.getTime() / 1e3);
731
+ if (!Number.isInteger(epochSeconds) || epochSeconds < 0) {
732
+ throw new TypeError("issuedAt must resolve to a non-negative epoch second.");
733
+ }
734
+ return epochSeconds;
735
+ }
736
+ function epochSecondsToIso(value) {
737
+ return new Date(value * 1e3).toISOString();
738
+ }
739
+ function validateLifetimeSeconds(lifetimeSeconds, maxLifetimeSeconds = defaultAssertionLifetimeSeconds) {
740
+ if (!Number.isInteger(lifetimeSeconds) || lifetimeSeconds <= 0) {
741
+ throw new TypeError("lifetimeSeconds must be a positive integer.");
742
+ }
743
+ if (!Number.isInteger(maxLifetimeSeconds) || maxLifetimeSeconds <= 0) {
744
+ throw new TypeError("maxLifetimeSeconds must be a positive integer.");
745
+ }
746
+ if (lifetimeSeconds > maxLifetimeSeconds) {
747
+ throw new TypeError("lifetimeSeconds must not exceed maxLifetimeSeconds.");
748
+ }
749
+ return lifetimeSeconds;
750
+ }
751
+ function createDidVerificationMethod(agentDid, method, index) {
752
+ const id = method.id ?? `${agentDid}#key-${index + 1}`;
753
+ const controller = method.controller ?? agentDid;
754
+ const methodBody = { ...method };
755
+ delete methodBody.relationships;
756
+ assertNonEmpty("verification method id", id);
757
+ assertNonEmpty("verification method type", method.type);
758
+ assertNonEmpty("verification method controller", controller);
759
+ return {
760
+ ...structuredClone(methodBody),
761
+ controller,
762
+ id,
763
+ type: method.type
764
+ };
765
+ }
766
+ function cloneDidService(service) {
767
+ return structuredClone(service);
768
+ }
769
+ function relationshipNames() {
770
+ return [
771
+ "authentication",
772
+ "assertionMethod",
773
+ "capabilityInvocation",
774
+ "capabilityDelegation",
775
+ "keyAgreement"
776
+ ];
777
+ }
778
+ function preferredSigningAlgorithm(algorithms) {
779
+ const algorithm = algorithms.find((candidate) => candidate === "ES256" || candidate === "EdDSA");
780
+ if (algorithm === void 0) {
781
+ throw new TypeError("No supported AEP JOSE signing algorithm is available.");
782
+ }
783
+ return algorithm;
784
+ }
785
+ export {
786
+ InMemoryManagedAgentRegistry,
787
+ createAepPlatform,
788
+ createJwtPlatformDelegatedSigner,
789
+ createManagedAgentDidDocument,
790
+ createManagedAgentIdentity,
791
+ createPlatformAgentIdentity,
792
+ createPlatformAgentIdentityListResponse,
793
+ createPlatformClientAssertionClaims,
794
+ createPlatformDiscoveryDocument,
795
+ createPlatformEnrollRequest,
796
+ createPlatformLifecycleRequest,
797
+ createPlatformProvisionRequest,
798
+ createPlatformSignRequest,
799
+ createPlatformSignResponse,
800
+ createPlatformVerificationRequest,
801
+ createPlatformVerificationResponse,
802
+ createServiceScopedAgentDid,
803
+ defaultAssertionLifetimeSeconds,
804
+ packageName,
805
+ platformHostedIdentityDraft,
806
+ publishManagedAgentDidDocument,
807
+ signPlatformClientAssertion,
808
+ updateManagedAgentIdentity
809
+ };
810
+ //# sourceMappingURL=index.js.map