@cheqd/studio 3.16.0-develop.8 → 3.16.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.
Files changed (66) hide show
  1. package/dist/app.d.ts.map +1 -1
  2. package/dist/app.js +11 -0
  3. package/dist/app.js.map +1 -1
  4. package/dist/controllers/api/accreditation.d.ts +2 -10
  5. package/dist/controllers/api/accreditation.d.ts.map +1 -1
  6. package/dist/controllers/api/accreditation.js +110 -369
  7. package/dist/controllers/api/accreditation.js.map +1 -1
  8. package/dist/controllers/api/credential.d.ts +1 -1
  9. package/dist/controllers/api/credential.d.ts.map +1 -1
  10. package/dist/controllers/api/credential.js +2 -1
  11. package/dist/controllers/api/credential.js.map +1 -1
  12. package/dist/controllers/api/received-credential.d.ts +375 -0
  13. package/dist/controllers/api/received-credential.d.ts.map +1 -0
  14. package/dist/controllers/api/received-credential.js +650 -0
  15. package/dist/controllers/api/received-credential.js.map +1 -0
  16. package/dist/database/entities/issued-credential.entity.d.ts +18 -2
  17. package/dist/database/entities/issued-credential.entity.d.ts.map +1 -1
  18. package/dist/database/entities/issued-credential.entity.js +29 -0
  19. package/dist/database/entities/issued-credential.entity.js.map +1 -1
  20. package/dist/database/migrations/1766408271347-studio-migrations.d.ts +7 -0
  21. package/dist/database/migrations/1766408271347-studio-migrations.d.ts.map +1 -0
  22. package/dist/database/migrations/1766408271347-studio-migrations.js +16 -0
  23. package/dist/database/migrations/1766408271347-studio-migrations.js.map +1 -0
  24. package/dist/database/types/types.d.ts.map +1 -1
  25. package/dist/database/types/types.js +2 -0
  26. package/dist/database/types/types.js.map +1 -1
  27. package/dist/middleware/auth/routes/api/credential-auth.d.ts.map +1 -1
  28. package/dist/middleware/auth/routes/api/credential-auth.js +12 -0
  29. package/dist/middleware/auth/routes/api/credential-auth.js.map +1 -1
  30. package/dist/services/api/accreditation.d.ts +17 -2
  31. package/dist/services/api/accreditation.d.ts.map +1 -1
  32. package/dist/services/api/accreditation.js +400 -7
  33. package/dist/services/api/accreditation.js.map +1 -1
  34. package/dist/services/api/credentials.d.ts.map +1 -1
  35. package/dist/services/api/credentials.js +38 -6
  36. package/dist/services/api/credentials.js.map +1 -1
  37. package/dist/services/api/received-credentials.d.ts +129 -0
  38. package/dist/services/api/received-credentials.d.ts.map +1 -0
  39. package/dist/services/api/received-credentials.js +498 -0
  40. package/dist/services/api/received-credentials.js.map +1 -0
  41. package/dist/services/identity/abstract.d.ts +4 -0
  42. package/dist/services/identity/abstract.d.ts.map +1 -1
  43. package/dist/services/identity/abstract.js +12 -0
  44. package/dist/services/identity/abstract.js.map +1 -1
  45. package/dist/services/identity/index.d.ts +22 -0
  46. package/dist/services/identity/index.d.ts.map +1 -1
  47. package/dist/services/identity/index.js.map +1 -1
  48. package/dist/services/identity/providers/studio/agent.d.ts +15 -0
  49. package/dist/services/identity/providers/studio/agent.d.ts.map +1 -1
  50. package/dist/services/identity/providers/studio/agent.js +51 -9
  51. package/dist/services/identity/providers/studio/agent.js.map +1 -1
  52. package/dist/services/identity/providers/studio/local.d.ts +4 -0
  53. package/dist/services/identity/providers/studio/local.d.ts.map +1 -1
  54. package/dist/services/identity/providers/studio/local.js +12 -0
  55. package/dist/services/identity/providers/studio/local.js.map +1 -1
  56. package/dist/services/identity/providers/studio/postgres.d.ts +7 -0
  57. package/dist/services/identity/providers/studio/postgres.d.ts.map +1 -1
  58. package/dist/services/identity/providers/studio/postgres.js +19 -0
  59. package/dist/services/identity/providers/studio/postgres.js.map +1 -1
  60. package/dist/services/track/admin/account-submitter.d.ts.map +1 -1
  61. package/dist/services/track/admin/account-submitter.js +1 -3
  62. package/dist/services/track/admin/account-submitter.js.map +1 -1
  63. package/dist/static/swagger-api.json +526 -1
  64. package/dist/types/accreditation.d.ts +1 -1
  65. package/dist/types/accreditation.d.ts.map +1 -1
  66. package/package.json +4 -4
@@ -5,40 +5,14 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  import { StatusCodes } from 'http-status-codes';
8
- import { v4 } from 'uuid';
9
- import { AccreditationRequestType, DIDAccreditationPolicyTypes, DIDAccreditationTypes, } from '../../types/accreditation.js';
10
- import { CredentialCategory, CredentialConnectors } from '../../types/credential.js';
8
+ import { AccreditationRequestType } from '../../types/accreditation.js';
11
9
  import { OperationCategoryNameEnum, OperationNameEnum } from '../../types/constants.js';
12
- import { IdentityServiceStrategySetup } from '../../services/identity/index.js';
13
10
  import { AccreditationService } from '../../services/api/accreditation.js';
14
- import { Credentials } from '../../services/api/credentials.js';
15
11
  import { eventTracker } from '../../services/track/tracker.js';
16
12
  import { body, query } from '../validator/index.js';
17
13
  import { validate } from '../validator/decorator.js';
18
14
  import { constructDidUrl, parseDidFromDidUrl } from '../../helpers/helpers.js';
19
- import NodeCache from 'node-cache';
20
- import { StatusListType } from '../../types/credential-status.js';
21
15
  import { CheqdNetwork } from '@cheqd/sdk';
22
- const ACCREDITATION_RESOLVE_CACHE_TTL_MS = 30_000;
23
- const ACCREDITATION_RESOLVE_CACHE_MAX_ENTRIES = 200;
24
- const ACCREDITATION_RESOLVE_CONCURRENCY = 8;
25
- function buildCacheKey(url, customerId) {
26
- return `${customerId ?? 'anonymous'}::${url}`;
27
- }
28
- const accreditationResolveCache = new NodeCache({
29
- stdTTL: ACCREDITATION_RESOLVE_CACHE_TTL_MS / 1000,
30
- checkperiod: 0,
31
- useClones: false,
32
- deleteOnExpire: true,
33
- maxKeys: ACCREDITATION_RESOLVE_CACHE_MAX_ENTRIES,
34
- });
35
- const inFlightAccreditations = new Map();
36
- function getCachedAccreditation(key) {
37
- return accreditationResolveCache.get(key) ?? null;
38
- }
39
- function setCachedAccreditation(key, value) {
40
- accreditationResolveCache.set(key, value);
41
- }
42
16
  export class AccreditationController {
43
17
  static issueValidator = [
44
18
  query('accreditationType')
@@ -188,10 +162,8 @@ export class AccreditationController {
188
162
  * $ref: '#/components/schemas/InternalError'
189
163
  */
190
164
  async issue(request, response) {
191
- // Get strategy e.g. postgres or local
192
- const identityServiceStrategySetup = new IdentityServiceStrategySetup();
193
- // Extract did from params
194
165
  const { accreditationType } = request.query;
166
+ const { schemas, issuerDid, subjectDid } = request.body;
195
167
  // Handles string input instead of an array
196
168
  if (typeof request.body.type === 'string') {
197
169
  request.body.type = [request.body.type];
@@ -199,117 +171,27 @@ export class AccreditationController {
199
171
  if (typeof request.body['@context'] === 'string') {
200
172
  request.body['@context'] = [request.body['@context']];
201
173
  }
202
- const { issuerDid, subjectDid, schemas, type, parentAccreditation, rootAuthorization, trustFramework, trustFrameworkId, attributes, accreditationName, format, credentialStatus, } = request.body;
203
174
  try {
204
- // Validate issuer and subject DIDs in parallel only for authorize
205
- // For attest, accredit they are validated in verify_accreditation
206
- const [body, subjectDidRes] = await Promise.all([
207
- identityServiceStrategySetup.agent.resolveDid(issuerDid),
208
- identityServiceStrategySetup.agent.resolveDid(subjectDid),
209
- ]);
210
- // Validate issuer DID
211
- if (!body?.didDocument) {
212
- return response.status(StatusCodes.BAD_REQUEST).send({
213
- error: `DID ${issuerDid} is not resolved because of error from resolver: ${body.didResolutionMetadata.error}.`,
214
- });
215
- }
216
- if (body.didDocumentMetadata.deactivated) {
217
- return response.status(StatusCodes.BAD_REQUEST).send({
218
- error: `${issuerDid} is deactivated`,
219
- });
220
- }
221
- // Validate subject DID
222
- if (!subjectDidRes?.didDocument) {
223
- return response.status(StatusCodes.BAD_REQUEST).send({
224
- error: `DID ${subjectDid} is not resolved because of error from resolver: ${body.didResolutionMetadata.error}.`,
225
- });
175
+ const result = await AccreditationService.instance.issue_accreditation(accreditationType, issuerDid, subjectDid, schemas, request.body, response.locals.customer);
176
+ if (result.success) {
177
+ // Track operation
178
+ const trackInfo = {
179
+ category: OperationCategoryNameEnum.CREDENTIAL,
180
+ name: OperationNameEnum.CREDENTIAL_ISSUE,
181
+ customer: response.locals.customer,
182
+ user: response.locals.user,
183
+ data: {
184
+ did: issuerDid,
185
+ },
186
+ };
187
+ eventTracker.emit('track', trackInfo);
188
+ return response.status(StatusCodes.OK).json(result.data);
226
189
  }
227
- if (subjectDidRes.didDocumentMetadata.deactivated) {
228
- return response.status(StatusCodes.BAD_REQUEST).send({
229
- error: `${subjectDid} is deactivated`,
190
+ else {
191
+ return response.status(result.status).json({
192
+ error: result.error,
230
193
  });
231
194
  }
232
- const resourceId = v4();
233
- const accreditedFor = schemas.map(({ url, types }) => ({
234
- schemaId: url,
235
- types: Array.isArray(types) ? types : [types],
236
- }));
237
- // construct credential request
238
- const credentialRequest = {
239
- subjectDid,
240
- attributes: {
241
- ...attributes,
242
- accreditedFor,
243
- id: subjectDid,
244
- },
245
- issuerDid,
246
- format: format || 'jwt',
247
- connector: CredentialConnectors.Resource, // resource connector
248
- credentialId: resourceId,
249
- credentialName: accreditationName,
250
- credentialStatus,
251
- category: CredentialCategory.ACCREDITATION,
252
- };
253
- let resourceType;
254
- switch (accreditationType) {
255
- case AccreditationRequestType.authorize:
256
- resourceType = DIDAccreditationTypes.VerifiableAuthorizationForTrustChain;
257
- credentialRequest.type = [...(type || []), resourceType];
258
- credentialRequest.termsOfUse = {
259
- type: DIDAccreditationPolicyTypes.Authorize,
260
- trustFramework,
261
- trustFrameworkId,
262
- };
263
- break;
264
- case AccreditationRequestType.accredit:
265
- resourceType = DIDAccreditationTypes.VerifiableAccreditationToAccredit;
266
- credentialRequest.type = [...(type || []), resourceType];
267
- credentialRequest.termsOfUse = {
268
- type: DIDAccreditationPolicyTypes.Accredit,
269
- parentAccreditation,
270
- rootAuthorization,
271
- };
272
- break;
273
- case AccreditationRequestType.attest:
274
- resourceType = DIDAccreditationTypes.VerifiableAccreditationToAttest;
275
- credentialRequest.type = [...(type || []), resourceType];
276
- credentialRequest.termsOfUse = {
277
- type: DIDAccreditationPolicyTypes.Accredit,
278
- parentAccreditation,
279
- rootAuthorization,
280
- };
281
- break;
282
- }
283
- // validate parent and root accreditations
284
- if (accreditationType === AccreditationRequestType.accredit ||
285
- accreditationType === AccreditationRequestType.attest) {
286
- const result = await AccreditationService.instance.verify_accreditation(issuerDid, parentAccreditation, accreditedFor, true, false, response.locals.customer, rootAuthorization);
287
- if (result.success === false) {
288
- return response.status(result.status).send({
289
- error: `Invalid Request: Root Authorization or parent Accreditation is not valid: ${result.error}`,
290
- });
291
- }
292
- }
293
- // issue accreditation
294
- const accreditation = await Credentials.instance.issue_credential(credentialRequest, response.locals.customer);
295
- // Track operation
296
- const trackInfo = {
297
- category: OperationCategoryNameEnum.CREDENTIAL,
298
- name: OperationNameEnum.CREDENTIAL_ISSUE,
299
- customer: response.locals.customer,
300
- user: response.locals.user,
301
- data: {
302
- did: issuerDid,
303
- },
304
- };
305
- eventTracker.emit('track', trackInfo);
306
- return response.status(StatusCodes.OK).json({
307
- didUrls: [
308
- `${issuerDid}/resources/${resourceId}`,
309
- `${issuerDid}?resourceName=${encodeURIComponent(accreditationName)}&resourceType=${credentialRequest.type}`,
310
- ],
311
- accreditation,
312
- });
313
195
  }
314
196
  catch (error) {
315
197
  return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
@@ -362,7 +244,6 @@ export class AccreditationController {
362
244
  * $ref: '#/components/schemas/InternalError'
363
245
  */
364
246
  async verify(request, response) {
365
- // Extract did from params
366
247
  let { verifyStatus = false, allowDeactivatedDid = false } = request.query;
367
248
  const { policies, subjectDid, schemas } = request.body;
368
249
  // construct didUrl
@@ -442,12 +323,8 @@ export class AccreditationController {
442
323
  * $ref: '#/components/schemas/InternalError'
443
324
  */
444
325
  async revoke(request, response) {
445
- // Get publish flag
446
326
  const { publish } = request.query;
447
- // Get symmetric key
448
327
  const { symmetricKey, ...didUrlParams } = request.body;
449
- // Get strategy e.g. postgres or local
450
- const identityServiceStrategySetup = new IdentityServiceStrategySetup(response.locals.customer.customerId);
451
328
  const didUrl = constructDidUrl(didUrlParams);
452
329
  if (!didUrl) {
453
330
  return response.status(StatusCodes.BAD_REQUEST).json({
@@ -455,41 +332,36 @@ export class AccreditationController {
455
332
  });
456
333
  }
457
334
  try {
458
- const res = await identityServiceStrategySetup.agent.resolve(didUrl);
459
- const resource = await res.json();
460
- if (resource.dereferencingMetadata) {
461
- return response.status(StatusCodes.NOT_FOUND).json({
462
- error: `DID URL ${didUrl} is not found`,
463
- });
335
+ const result = await AccreditationService.instance.revoke_accreditation(didUrl, publish, symmetricKey, response.locals.customer);
336
+ if (result.success) {
337
+ // Track operation if revocation was successful and publish is true
338
+ // Otherwise the StatusList2021 or BitstringStatusList publisher should manually publish the resource
339
+ // and it will be tracked there
340
+ if (result.data.resourceMetadata && publish) {
341
+ // get issuer did
342
+ const issuerDid = parseDidFromDidUrl(didUrl);
343
+ const trackInfo = {
344
+ category: OperationCategoryNameEnum.CREDENTIAL,
345
+ name: OperationNameEnum.CREDENTIAL_REVOKE,
346
+ customer: response.locals.customer,
347
+ user: response.locals.user,
348
+ data: {
349
+ did: issuerDid,
350
+ encrypted: result.data.statusList?.metadata?.encrypted,
351
+ resource: result.data.resourceMetadata,
352
+ symmetricKey: '',
353
+ },
354
+ };
355
+ // Track operation
356
+ eventTracker.emit('track', trackInfo);
357
+ }
358
+ return response.status(StatusCodes.OK).json(result.data);
464
359
  }
465
- const accreditation = resource;
466
- const result = await identityServiceStrategySetup.agent.revokeCredentials(accreditation, StatusListType.Bitstring, // default to BitstringStatusList for accreditation
467
- publish, response.locals.customer, symmetricKey);
468
- // Track operation if revocation was successful and publish is true
469
- // Otherwise the StatusList2021 or BitstringStatusList publisher should manually publish the resource
470
- // and it will be tracked there
471
- if (!result.error && result.resourceMetadata && publish) {
472
- // get issuer did
473
- const issuerDid = typeof accreditation.issuer === 'string'
474
- ? accreditation.issuer
475
- : accreditation.issuer.id;
476
- const trackInfo = {
477
- category: OperationCategoryNameEnum.CREDENTIAL,
478
- name: OperationNameEnum.CREDENTIAL_REVOKE,
479
- customer: response.locals.customer,
480
- user: response.locals.user,
481
- data: {
482
- did: issuerDid,
483
- encrypted: result.statusList?.metadata?.encrypted,
484
- resource: result.resourceMetadata,
485
- symmetricKey: '',
486
- },
487
- };
488
- // Track operation
489
- eventTracker.emit('track', trackInfo);
360
+ else {
361
+ return response.status(result.status).json({
362
+ error: result.error,
363
+ });
490
364
  }
491
- // Return Ok response
492
- return response.status(StatusCodes.OK).json(result);
493
365
  }
494
366
  catch (error) {
495
367
  return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
@@ -537,12 +409,8 @@ export class AccreditationController {
537
409
  * $ref: '#/components/schemas/InternalError'
538
410
  */
539
411
  async suspend(request, response) {
540
- // Get publish flag
541
412
  const { publish } = request.query;
542
- // Get symmetric key
543
413
  const { symmetricKey, ...didUrlParams } = request.body;
544
- // Get strategy e.g. postgres or local
545
- const identityServiceStrategySetup = new IdentityServiceStrategySetup(response.locals.customer.customerId);
546
414
  const didUrl = constructDidUrl(didUrlParams);
547
415
  if (!didUrl) {
548
416
  return response.status(StatusCodes.BAD_REQUEST).json({
@@ -550,43 +418,36 @@ export class AccreditationController {
550
418
  });
551
419
  }
552
420
  try {
553
- const res = await identityServiceStrategySetup.agent.resolve(didUrl);
554
- const resource = await res.json();
555
- if (resource.dereferencingMetadata) {
556
- return {
557
- success: false,
558
- status: 404,
559
- error: `DID URL ${didUrl} is not found`,
560
- };
421
+ const result = await AccreditationService.instance.suspend_accreditation(didUrl, publish, symmetricKey, response.locals.customer);
422
+ if (result.success) {
423
+ // Track operation if suspension was successful and publish is true
424
+ // Otherwise the StatusList2021 or BitstringStatusList publisher should manually publish the resource
425
+ // and it will be tracked there
426
+ if (result.data.resourceMetadata && publish) {
427
+ // get issuer did
428
+ const issuerDid = parseDidFromDidUrl(didUrl);
429
+ const trackInfo = {
430
+ category: OperationCategoryNameEnum.CREDENTIAL,
431
+ name: OperationNameEnum.CREDENTIAL_SUSPEND,
432
+ customer: response.locals.customer,
433
+ user: response.locals.user,
434
+ data: {
435
+ did: issuerDid,
436
+ encrypted: result.data.statusList?.metadata?.encrypted,
437
+ resource: result.data.resourceMetadata,
438
+ symmetricKey: '',
439
+ },
440
+ };
441
+ // Track operation
442
+ eventTracker.emit('track', trackInfo);
443
+ }
444
+ return response.status(StatusCodes.OK).json(result.data);
561
445
  }
562
- const accreditation = resource;
563
- const result = await identityServiceStrategySetup.agent.suspendCredentials(accreditation, StatusListType.Bitstring, // default to BitstringStatusList for accreditation
564
- publish, response.locals.customer, symmetricKey);
565
- // Track operation if revocation was successful and publish is true
566
- // Otherwise the StatusList2021 or BitstringStatusList publisher should manually publish the resource
567
- // and it will be tracked there
568
- if (!result.error && result.resourceMetadata && publish) {
569
- // get issuer did
570
- const issuerDid = typeof accreditation.issuer === 'string'
571
- ? accreditation.issuer
572
- : accreditation.issuer.id;
573
- const trackInfo = {
574
- category: OperationCategoryNameEnum.CREDENTIAL,
575
- name: OperationNameEnum.CREDENTIAL_SUSPEND,
576
- customer: response.locals.customer,
577
- user: response.locals.user,
578
- data: {
579
- did: issuerDid,
580
- encrypted: result.statusList?.metadata?.encrypted,
581
- resource: result.resourceMetadata,
582
- symmetricKey: '',
583
- },
584
- };
585
- // Track operation
586
- eventTracker.emit('track', trackInfo);
446
+ else {
447
+ return response.status(result.status).json({
448
+ error: result.error,
449
+ });
587
450
  }
588
- // Return Ok response
589
- return response.status(StatusCodes.OK).json(result);
590
451
  }
591
452
  catch (error) {
592
453
  return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
@@ -634,12 +495,8 @@ export class AccreditationController {
634
495
  * $ref: '#/components/schemas/InternalError'
635
496
  */
636
497
  async reinstate(request, response) {
637
- // Get publish flag
638
498
  const { publish } = request.query;
639
- // Get symmetric key
640
499
  const { symmetricKey, ...didUrlParams } = request.body;
641
- // Get strategy e.g. postgres or local
642
- const identityServiceStrategySetup = new IdentityServiceStrategySetup(response.locals.customer.customerId);
643
500
  const didUrl = constructDidUrl(didUrlParams);
644
501
  if (!didUrl) {
645
502
  return response.status(StatusCodes.BAD_REQUEST).json({
@@ -647,43 +504,36 @@ export class AccreditationController {
647
504
  });
648
505
  }
649
506
  try {
650
- const res = await identityServiceStrategySetup.agent.resolve(didUrl);
651
- const resource = await res.json();
652
- if (resource.dereferencingMetadata) {
653
- return {
654
- success: false,
655
- status: 404,
656
- error: `DID URL ${didUrl} is not found`,
657
- };
507
+ const result = await AccreditationService.instance.reinstate_accreditation(didUrl, publish, symmetricKey, response.locals.customer);
508
+ if (result.success) {
509
+ // Track operation if reinstatement was successful and publish is true
510
+ // Otherwise the StatusList2021 or BitstringStatusList publisher should manually publish the resource
511
+ // and it will be tracked there
512
+ if (result.data.resourceMetadata && publish) {
513
+ // get issuer did
514
+ const issuerDid = parseDidFromDidUrl(didUrl);
515
+ const trackInfo = {
516
+ category: OperationCategoryNameEnum.CREDENTIAL,
517
+ name: OperationNameEnum.CREDENTIAL_UNSUSPEND,
518
+ customer: response.locals.customer,
519
+ user: response.locals.user,
520
+ data: {
521
+ did: issuerDid,
522
+ encrypted: result.data.statusList?.metadata?.encrypted || false,
523
+ resource: result.data.resourceMetadata,
524
+ symmetricKey: '',
525
+ },
526
+ };
527
+ // Track operation
528
+ eventTracker.emit('track', trackInfo);
529
+ }
530
+ return response.status(StatusCodes.OK).json(result.data);
658
531
  }
659
- const accreditation = resource;
660
- const result = await identityServiceStrategySetup.agent.reinstateCredentials(accreditation, StatusListType.Bitstring, // default to BitstringStatusList for accreditation
661
- publish, response.locals.customer, symmetricKey);
662
- // Track operation if revocation was successful and publish is true
663
- // Otherwise the StatusList2021 or BitstringStatusList publisher should manually publish the resource
664
- // and it will be tracked there
665
- if (!result.error && result.resourceMetadata && publish) {
666
- // get issuer did
667
- const issuerDid = typeof accreditation.issuer === 'string'
668
- ? accreditation.issuer
669
- : accreditation.issuer.id;
670
- const trackInfo = {
671
- category: OperationCategoryNameEnum.CREDENTIAL,
672
- name: OperationNameEnum.CREDENTIAL_UNSUSPEND,
673
- customer: response.locals.customer,
674
- user: response.locals.user,
675
- data: {
676
- did: issuerDid,
677
- encrypted: result.statusList?.metadata?.encrypted || false,
678
- resource: result.resourceMetadata,
679
- symmetricKey: '',
680
- },
681
- };
682
- // Track operation
683
- eventTracker.emit('track', trackInfo);
532
+ else {
533
+ return response.status(result.status).json({
534
+ error: result.error,
535
+ });
684
536
  }
685
- // Return Ok response
686
- return response.status(StatusCodes.OK).json(result);
687
537
  }
688
538
  catch (error) {
689
539
  return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
@@ -754,125 +604,16 @@ export class AccreditationController {
754
604
  */
755
605
  async listAccreditations(request, response) {
756
606
  const { network, accreditationType, did, page, limit } = request.query;
757
- // Get strategy e.g. postgres or local
758
- const identityServiceStrategySetup = response.locals.customer
759
- ? new IdentityServiceStrategySetup(response.locals.customer.customerId)
760
- : new IdentityServiceStrategySetup();
761
- let resourceType;
762
- switch (accreditationType) {
763
- case AccreditationRequestType.authorize:
764
- resourceType = DIDAccreditationTypes.VerifiableAuthorizationForTrustChain;
765
- break;
766
- case AccreditationRequestType.accredit:
767
- resourceType = DIDAccreditationTypes.VerifiableAccreditationToAccredit;
768
- break;
769
- case AccreditationRequestType.attest:
770
- resourceType = DIDAccreditationTypes.VerifiableAccreditationToAttest;
771
- break;
772
- default:
773
- return response.status(StatusCodes.BAD_REQUEST).json({
774
- error: `Invalid accreditationType: ${accreditationType}. Must be one of: authorize, accredit, attest.`,
775
- });
776
- }
777
607
  try {
778
- // Fetch resources of accreditation resourceType associated with the account
779
- const { resources } = await identityServiceStrategySetup.agent.findLatestResourcesVersionsByType(resourceType, response.locals.customer, network, did, page, limit);
780
- // Build resource URLs for resolution
781
- const resourceUrls = resources.map((item) => `${item.did}/resources/${item.resourceId}`);
782
- // No resources to resolve, return early
783
- if (resourceUrls.length === 0) {
784
- return response.status(StatusCodes.OK).json({
785
- total: 0,
786
- accreditations: [],
787
- });
608
+ const result = await AccreditationService.instance.list_accreditations(response.locals.customer, accreditationType, network, did, page, limit);
609
+ if (result.success) {
610
+ return response.status(StatusCodes.OK).json(result.data);
788
611
  }
789
- // 1. Fetch all tracking records from the issued credentials table
790
- const { credentials: trackingRecords } = await Credentials.instance.list(response.locals.customer, {
791
- category: CredentialCategory.ACCREDITATION,
792
- providerCredentialId: resources.map((item) => item.resourceId),
793
- credentialType: resourceType,
794
- });
795
- // 2. OPTIMIZATION: Create a Map for O(1) tracking record lookup by providerCredentialId
796
- const trackingMap = new Map();
797
- for (const record of trackingRecords) {
798
- trackingMap.set(record.providerCredentialId, record);
612
+ else {
613
+ return response.status(result.status).json({
614
+ error: result.error,
615
+ });
799
616
  }
800
- const resolveAccreditationWithCache = async (url) => {
801
- const cacheKey = buildCacheKey(url, response.locals.customer?.customerId);
802
- const cached = getCachedAccreditation(cacheKey);
803
- if (cached) {
804
- return cached;
805
- }
806
- const inFlight = inFlightAccreditations.get(cacheKey);
807
- if (inFlight) {
808
- return inFlight;
809
- }
810
- const resolverPromise = (async () => {
811
- try {
812
- const res = await identityServiceStrategySetup.agent.resolve(url, true);
813
- const credential = await res.json();
814
- // Skip if the credential doesn't have contentStream
815
- if (!credential.contentStream) {
816
- return null;
817
- }
818
- const resourceId = credential.contentMetadata.resourceId;
819
- const trackingRecord = trackingMap.get(resourceId);
820
- if (trackingRecord) {
821
- const { issuedCredentialId, providerId, providerCredentialId, status, statusUpdatedAt } = trackingRecord;
822
- // Merge tracking metadata with credential
823
- const accreditation = {
824
- ...credential.contentStream,
825
- metadata: {
826
- issuedCredentialId,
827
- providerId,
828
- providerCredentialId,
829
- status,
830
- statusUpdatedAt,
831
- },
832
- };
833
- setCachedAccreditation(cacheKey, accreditation);
834
- return accreditation;
835
- }
836
- else {
837
- // No tracking record, return just the credential (legacy)
838
- setCachedAccreditation(cacheKey, credential.contentStream);
839
- return credential.contentStream;
840
- }
841
- }
842
- catch (error) {
843
- console.error(`Failed to process accreditation for URL: ${url}`, error);
844
- return null;
845
- }
846
- finally {
847
- inFlightAccreditations.delete(cacheKey);
848
- }
849
- })();
850
- inFlightAccreditations.set(cacheKey, resolverPromise);
851
- return resolverPromise;
852
- };
853
- // 3. Resolve resources and enhance with tracking metadata with bounded concurrency
854
- const resolvedAccreditations = new Array(resourceUrls.length);
855
- let currentIndex = 0;
856
- const workers = Array.from({ length: Math.min(ACCREDITATION_RESOLVE_CONCURRENCY, resourceUrls.length) }, async () => {
857
- // eslint-disable-next-line no-constant-condition
858
- while (true) {
859
- const index = currentIndex++;
860
- if (index >= resourceUrls.length) {
861
- break;
862
- }
863
- const accreditation = await resolveAccreditationWithCache(resourceUrls[index]);
864
- if (accreditation) {
865
- resolvedAccreditations[index] = accreditation;
866
- }
867
- }
868
- });
869
- // 4. Wait for all resolutions to complete and filter out any failed/skipped ones (null)
870
- await Promise.all(workers);
871
- const accreditations = resolvedAccreditations.filter(Boolean);
872
- return response.status(StatusCodes.OK).json({
873
- total: accreditations.length,
874
- accreditations: accreditations,
875
- });
876
617
  }
877
618
  catch (error) {
878
619
  return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({