@cheqd/did-provider-cheqd 4.5.5-develop.1 → 4.6.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 (30) hide show
  1. package/build/esm/agent/ICheqd.d.ts +291 -82
  2. package/build/esm/agent/ICheqd.d.ts.map +1 -1
  3. package/build/esm/agent/ICheqd.js +1567 -87
  4. package/build/esm/agent/ICheqd.js.map +1 -1
  5. package/build/esm/did-manager/cheqd-did-provider.d.ts +13 -2
  6. package/build/esm/did-manager/cheqd-did-provider.d.ts.map +1 -1
  7. package/build/esm/did-manager/cheqd-did-provider.js +10 -2
  8. package/build/esm/did-manager/cheqd-did-provider.js.map +1 -1
  9. package/build/esm/dkg-threshold/lit-protocol/v6.d.ts.map +1 -1
  10. package/build/esm/dkg-threshold/lit-protocol/v6.js +63 -33
  11. package/build/esm/dkg-threshold/lit-protocol/v6.js.map +1 -1
  12. package/build/esm/utils/helpers.d.ts +28 -7
  13. package/build/esm/utils/helpers.d.ts.map +1 -1
  14. package/build/esm/utils/helpers.js +120 -29
  15. package/build/esm/utils/helpers.js.map +1 -1
  16. package/build/tsconfig.esm.tsbuildinfo +1 -1
  17. package/build/tsconfig.types.tsbuildinfo +1 -1
  18. package/build/types/agent/ICheqd.d.ts +291 -82
  19. package/build/types/agent/ICheqd.d.ts.map +1 -1
  20. package/build/types/did-manager/cheqd-did-provider.d.ts +13 -2
  21. package/build/types/did-manager/cheqd-did-provider.d.ts.map +1 -1
  22. package/build/types/dkg-threshold/lit-protocol/v6.d.ts.map +1 -1
  23. package/build/types/utils/helpers.d.ts +28 -7
  24. package/build/types/utils/helpers.d.ts.map +1 -1
  25. package/package.json +6 -4
  26. package/src/agent/ICheqd.ts +2425 -372
  27. package/src/did-manager/cheqd-did-provider.ts +19 -4
  28. package/src/dkg-threshold/lit-protocol/v6.ts +65 -34
  29. package/src/utils/helpers.ts +172 -34
  30. package/tsconfig.json +2 -0
@@ -39,6 +39,7 @@ import {
39
39
  W3CVerifiableCredential,
40
40
  ICredentialVerifier,
41
41
  DIDResolutionResult,
42
+ CredentialStatusReference,
42
43
  } from '@veramo/core';
43
44
  import {
44
45
  CheqdDIDProvider,
@@ -47,17 +48,22 @@ import {
47
48
  ResourcePayload,
48
49
  StatusList2021ResourcePayload,
49
50
  DefaultRESTUrls,
50
- DefaultStatusList2021Encodings,
51
+ DefaultStatusListEncodings,
51
52
  DefaultStatusList2021ResourceTypes,
52
53
  DefaultStatusList2021StatusPurposeTypes,
53
- DefaultStatusList2021Encoding,
54
+ DefaultStatusListEncoding,
54
55
  DefaultStatusList2021ResourceType,
55
56
  DefaultStatusList2021StatusPurposeType,
57
+ BitstringStatusPurposeTypes,
56
58
  TPublicKeyEd25519,
59
+ BitstringStatusListResourceType,
60
+ BitstringStatusListPurposeType,
61
+ BitstringStatusListResourcePayload,
57
62
  } from '../did-manager/cheqd-did-provider.js';
58
63
  import { fromString, toString } from 'uint8arrays';
59
64
  import { decodeJWT } from 'did-jwt';
60
65
  import { StatusList } from '@digitalbazaar/vc-status-list';
66
+ import { Bitstring as DBBitstring } from '@digitalbazaar/bitstring';
61
67
  import { v4 } from 'uuid';
62
68
  import fs from 'fs';
63
69
  import Debug from 'debug';
@@ -72,8 +78,12 @@ import {
72
78
  } from '../dkg-threshold/lit-protocol/v6.js';
73
79
  import {
74
80
  blobToHexString,
81
+ decodeWithMetadata,
82
+ encodeWithMetadata,
83
+ generateRandomStatusListIndex,
75
84
  getEncodedList,
76
85
  isEncodedList,
86
+ isValidEncodedBitstring,
77
87
  randomFromRange,
78
88
  safeDeserialise,
79
89
  toBlob,
@@ -185,6 +195,13 @@ export type VerificationResult = {
185
195
  suspended?: boolean;
186
196
  error?: IVerifyResult['error'];
187
197
  };
198
+ export interface BitstringValidationResult {
199
+ status: number; // e.g., 0x0, 0x1, 0x2
200
+ purpose: string; // e.g., 'revocation', 'suspension'
201
+ valid: boolean;
202
+ message?: string;
203
+ }
204
+ export type BitstringVerificationResult = VerificationResult & BitstringValidationResult;
188
205
  export type EncryptionResult = {
189
206
  symmetricEncryptionCiphertext: string;
190
207
  thresholdEncryptionCiphertext: string;
@@ -192,6 +209,28 @@ export type EncryptionResult = {
192
209
  symmetricKey: string;
193
210
  };
194
211
  export type StatusCheckResult = { revoked?: boolean; suspended?: boolean; error?: IError };
212
+ export type BitstringUpdateResult = {
213
+ updated: boolean;
214
+ statusValue: BitstringStatusValue;
215
+ previousStatusValue?: BitstringStatusValue;
216
+ statusMessage?: string; // Human-readable status message
217
+ error?: IError;
218
+ statusList?: BitstringStatusList;
219
+ symmetricKey?: string;
220
+ published?: boolean;
221
+ resourceMetadata?: LinkedResourceMetadataResolutionResult;
222
+ };
223
+ export type BulkBitstringUpdateResult = {
224
+ updated: boolean[];
225
+ statusValues: BitstringStatusValue[];
226
+ previousStatusValues?: BitstringStatusValue[];
227
+ statusMessages?: string[]; // Human-readable status message
228
+ error?: IError;
229
+ statusList?: BitstringStatusList;
230
+ symmetricKey?: string;
231
+ published?: boolean;
232
+ resourceMetadata?: LinkedResourceMetadataResolutionResult;
233
+ };
195
234
  export type RevocationResult = {
196
235
  revoked: boolean;
197
236
  error?: IError;
@@ -255,7 +294,7 @@ export type StatusList2021Revocation = {
255
294
  metadata: {
256
295
  type: typeof DefaultStatusList2021ResourceTypes.revocation;
257
296
  encrypted: boolean;
258
- encoding: DefaultStatusList2021Encoding;
297
+ encoding: DefaultStatusListEncoding;
259
298
  statusListHash?: string;
260
299
  paymentConditions?: PaymentCondition[];
261
300
  };
@@ -270,7 +309,7 @@ export type StatusList2021Suspension = {
270
309
  metadata: {
271
310
  type: typeof DefaultStatusList2021ResourceTypes.suspension;
272
311
  encrypted: boolean;
273
- encoding: DefaultStatusList2021Encoding;
312
+ encoding: DefaultStatusListEncoding;
274
313
  statusListHash?: string;
275
314
  paymentConditions?: PaymentCondition[];
276
315
  };
@@ -285,7 +324,7 @@ export type StatusList2021RevocationNonMigrated = {
285
324
  metadata: {
286
325
  type: typeof DefaultStatusList2021ResourceTypes.revocation;
287
326
  encrypted: boolean;
288
- encoding: DefaultStatusList2021Encoding;
327
+ encoding: DefaultStatusListEncoding;
289
328
  encryptedSymmetricKey?: string;
290
329
  paymentConditions?: PaymentCondition[];
291
330
  };
@@ -300,11 +339,52 @@ export type StatusList2021SuspensionNonMigrated = {
300
339
  metadata: {
301
340
  type: typeof DefaultStatusList2021ResourceTypes.suspension;
302
341
  encrypted: boolean;
303
- encoding: DefaultStatusList2021Encoding;
342
+ encoding: DefaultStatusListEncoding;
304
343
  encryptedSymmetricKey?: string;
305
344
  paymentConditions?: PaymentCondition[];
306
345
  };
307
346
  };
347
+ export interface BitstringStatusListEntry extends CredentialStatusReference {
348
+ id: string;
349
+ type: 'BitstringStatusListEntry';
350
+ statusPurpose: BitstringStatusListPurposeType;
351
+ statusListIndex: string; // must be string representation of integer
352
+ statusListCredential: string; // DID URL of the status list credential
353
+ statusSize?: number | 1; // bits per credential (1, 2, 4, 8)
354
+ statusMessage?: BitstringStatusMessage[]; // status value meanings
355
+ statusReference?: string | string[]; // reference to status meanings
356
+ }
357
+ export interface BitstringStatusMessage {
358
+ status: string; // hex value prefixed with 0x (e.g., "0x0", "0x1")
359
+ message: string; // human-readable explanation
360
+ [key: string]: any; // additional properties can be added
361
+ }
362
+
363
+ export interface EncodedListMetadata {
364
+ encrypted: boolean;
365
+ encoding: DefaultStatusListEncoding;
366
+ length: number;
367
+ statusSize?: number; // bits per credential (1, 2, 4, 8)
368
+ statusMessages?: BitstringStatusMessage[]; // status value meanings
369
+ statusListHash?: string;
370
+ symmetricLength?: number; // length of symmetric encryption ciphertext in bytes
371
+ paymentConditions?: PaymentCondition[];
372
+ }
373
+ export type BitstringVerifiableCredential = VerifiableCredential & {
374
+ credentialStatus: BitstringStatusListEntry;
375
+ };
376
+ export type BitstringStatusListCredential = VerifiableCredential & {
377
+ credentialSubject: {
378
+ type: string;
379
+ statusPurpose: BitstringStatusListPurposeType;
380
+ encodedList: EncodedList;
381
+ ttl?: number; // time to live in milliseconds
382
+ };
383
+ };
384
+ export interface BitstringStatusList {
385
+ bitstringStatusListCredential: BitstringStatusListCredential;
386
+ metadata: EncodedListMetadata;
387
+ }
308
388
  export type AccessControlConditionType = (typeof AccessControlConditionTypes)[keyof typeof AccessControlConditionTypes];
309
389
  export type AccessControlConditionReturnValueComparator =
310
390
  (typeof AccessControlConditionReturnValueComparators)[keyof typeof AccessControlConditionReturnValueComparators];
@@ -327,6 +407,14 @@ export type CreateStatusList2021Result = {
327
407
  encrypted?: boolean;
328
408
  symmetricKey?: string;
329
409
  };
410
+ export type CreateStatusListResult = {
411
+ created: boolean;
412
+ error?: Error;
413
+ resource: BitstringStatusList;
414
+ resourceMetadata: LinkedResourceMetadataResolutionResult;
415
+ encrypted?: boolean;
416
+ symmetricKey?: string;
417
+ };
330
418
  export type TransactionResult = {
331
419
  successful: boolean;
332
420
  transactionHash?: string;
@@ -385,6 +473,17 @@ export const GenerateStatusList2021MethodName = 'cheqdGenerateStatusList2021';
385
473
  export const IssueRevocableCredentialWithStatusList2021MethodName = 'cheqdIssueRevocableCredentialWithStatusList2021';
386
474
  export const IssueSuspendableCredentialWithStatusList2021MethodName =
387
475
  'cheqdIssueSuspendableCredentialWithStatusList2021';
476
+
477
+ export const CreateStatusListMethodName = 'cheqdCreateStatusList';
478
+ export const BroadcastStatusListMethodName = 'cheqdBroadcastStatusList';
479
+ export const GenerateStatusListMethodName = 'cheqdGenerateStatusList';
480
+ export const VerifyStatusListCredentialMethodName = 'cheqdVerifyStatusListCredential';
481
+ export const IssueCredentialWithStatusListMethodName = 'cheqdIssueCredentialWithStatusList';
482
+ export const VerifyCredentialWithStatusListMethodName = 'cheqdVerifyCredentialWithStatusList';
483
+ export const UpdateCredentialWithStatusListMethodName = 'cheqdUpdateCredentialWithStatusList';
484
+ export const BulkUpdateCredentialsWithStatusListMethodName = 'cheqdBulkUpdateCredentialsWithStatusList';
485
+ export const VerifyPresentationWithStatusListMethodName = 'cheqdVerifyPresentationWithStatusList';
486
+ // END: TODO, start Remove or update with status list 2021
388
487
  export const VerifyCredentialMethodName = 'cheqdVerifyCredential';
389
488
  export const VerifyPresentationMethodName = 'cheqdVerifyPresentation';
390
489
  export const CheckCredentialStatusMethodName = 'cheqdCheckCredentialStatus';
@@ -394,6 +493,7 @@ export const SuspendCredentialMethodName = 'cheqdSuspendCredential';
394
493
  export const SuspendCredentialsMethodName = 'cheqdSuspendCredentials';
395
494
  export const UnsuspendCredentialMethodName = 'cheqdUnsuspendCredential';
396
495
  export const UnsuspendCredentialsMethodName = 'cheqdUnsuspendCredentials';
496
+ // END: Remove or update with status list 2021
397
497
  export const TransactSendTokensMethodName = 'cheqdTransactSendTokens';
398
498
  export const ObservePaymentConditionMethodName = 'cheqdObservePaymentCondition';
399
499
  export const MintCapacityCreditMethodName = 'cheqdMintCapacityCredit';
@@ -446,7 +546,7 @@ export interface ICheqdCreateStatusList2021Args {
446
546
  resourceVersion?: ResourcePayload['version'];
447
547
  alsoKnownAs?: ResourcePayload['alsoKnownAs'];
448
548
  statusListLength?: number;
449
- statusListEncoding?: DefaultStatusList2021Encoding;
549
+ statusListEncoding?: DefaultStatusListEncoding;
450
550
  validUntil?: string;
451
551
  returnSymmetricKey?: boolean;
452
552
  }
@@ -460,15 +560,34 @@ export interface ICheqdCreateUnencryptedStatusList2021Args {
460
560
  fee?: DidStdFee | 'auto' | number;
461
561
  }
462
562
 
463
- export interface ICheqdBroadcastStatusList2021Args {
563
+ export interface ICheqdBroadcastStatusListArgs {
464
564
  kms: string;
465
- payload: StatusList2021ResourcePayload;
565
+ payload: StatusList2021ResourcePayload | BitstringStatusListResourcePayload;
466
566
  network: CheqdNetwork;
467
567
  file?: string;
468
568
  signInputs?: ISignInputs[];
469
569
  fee?: DidStdFee | 'auto' | number;
470
570
  }
471
571
 
572
+ export interface ICheqdCreateBitstringStatusListArgs {
573
+ kms: string;
574
+ issuerDid: string;
575
+ statusListName: string;
576
+ statusPurpose: BitstringStatusListPurposeType | BitstringStatusListPurposeType[];
577
+ statusSize?: number; // bits per credential
578
+ statusMessages?: BitstringStatusMessage[];
579
+ ttl?: number; // time to live in milliseconds
580
+ encrypted: boolean;
581
+ paymentConditions?: PaymentCondition[];
582
+ dkgOptions?: DkgOptions;
583
+ resourceVersion?: ResourcePayload['version'];
584
+ alsoKnownAs?: ResourcePayload['alsoKnownAs'];
585
+ statusListLength?: number;
586
+ statusListEncoding?: DefaultStatusListEncoding;
587
+ validUntil?: string;
588
+ returnSymmetricKey?: boolean;
589
+ }
590
+
472
591
  export interface ICheqdGenerateDidDocArgs {
473
592
  verificationMethod: VerificationMethods;
474
593
  methodSpecificIdAlgo: MethodSpecificIdAlgo;
@@ -490,9 +609,33 @@ export interface ICheqdGenerateVersionIdArgs {
490
609
  export interface ICheqdGenerateStatusList2021Args {
491
610
  length?: number;
492
611
  buffer?: Uint8Array;
493
- bitstringEncoding?: DefaultStatusList2021Encoding;
612
+ bitstringEncoding?: DefaultStatusListEncoding;
613
+ }
614
+
615
+ export interface ICheqdGenerateStatusListArgs {
616
+ length?: number; // Number of entries
617
+ statusSize?: number; // Bits per entry
618
+ buffer?: Buffer;
619
+ bitstringEncoding?: DefaultStatusListEncoding;
494
620
  }
495
621
 
622
+ export interface ICheqdVerifyStatusListCredentialArgs {
623
+ credential: BitstringStatusListCredential;
624
+ verificationArgs?: IVerifyCredentialArgs;
625
+ }
626
+ export interface StatusOptions {
627
+ statusPurpose: BitstringStatusListPurposeType;
628
+ statusListName: string;
629
+ statusListIndex?: number;
630
+ statusListVersion?: string;
631
+ statusListRangeStart?: number;
632
+ statusListRangeEnd?: number;
633
+ indexNotIn?: number[];
634
+ }
635
+ export interface ICheqdIssueCredentialWithStatusListArgs {
636
+ issuanceOptions: ICreateVerifiableCredentialArgs;
637
+ statusOptions: StatusOptions;
638
+ }
496
639
  export interface ICheqdIssueRevocableCredentialWithStatusList2021Args {
497
640
  issuanceOptions: ICreateVerifiableCredentialArgs;
498
641
  statusOptions: {
@@ -519,34 +662,78 @@ export interface ICheqdIssueSuspendableCredentialWithStatusList2021Args {
519
662
  };
520
663
  }
521
664
 
522
- export interface ICheqdVerifyCredentialWithStatusList2021Args {
665
+ export interface ICheqdVerifyCredentialWithStatusListArgs {
523
666
  credential: W3CVerifiableCredential;
524
667
  verificationArgs?: IVerifyCredentialArgs;
525
668
  fetchList?: boolean;
526
669
  dkgOptions?: DkgOptions;
527
- options?: ICheqdStatusList2021Options;
670
+ options?: ICheqdStatusListOptions;
671
+ }
672
+ export interface ICheqdVerifyCredentialWithBitstringArgs {
673
+ credential: BitstringVerifiableCredential;
674
+ verificationArgs?: IVerifyCredentialArgs;
675
+ fetchList?: boolean;
676
+ dkgOptions?: DkgOptions;
677
+ options?: ICheqdStatusListOptions;
528
678
  }
529
679
 
530
- export interface ICheqdVerifyPresentationWithStatusList2021Args {
680
+ export interface ICheqdVerifyPresentationWithStatusListArgs {
531
681
  presentation: VerifiablePresentation;
532
682
  verificationArgs?: IVerifyPresentationArgs;
533
683
  fetchList?: boolean;
534
684
  dkgOptions?: DkgOptions;
535
- options?: ICheqdStatusList2021Options;
685
+ options?: ICheqdStatusListOptions;
536
686
  }
537
687
 
538
- export interface ICheqdCheckCredentialStatusWithStatusList2021Args {
688
+ export interface ICheqdCheckCredentialStatusWithStatusListArgs {
539
689
  credential?: W3CVerifiableCredential;
540
- statusOptions?: ICheqdCheckCredentialWithStatusList2021StatusOptions;
690
+ statusOptions?: ICheqdCheckCredentialStatusOptions;
691
+ verificationOptions?: IVerifyCredentialArgs;
692
+ fetchList?: boolean;
693
+ dkgOptions?: DkgOptions;
694
+ options?: ICheqdStatusListOptions;
695
+ }
696
+
697
+ export interface ICheqdUpdateCredentialWithStatusListArgs {
698
+ credential?: W3CVerifiableCredential;
699
+ newStatus: BitstringStatusValue; // 0=valid, 1=revoked, 2=suspended, 3=unknown
700
+ updateOptions?: ICheqdCredentialStatusUpdateOptions;
701
+ verificationOptions?: IVerifyCredentialArgs;
702
+ fetchList?: boolean;
703
+ publish?: boolean;
704
+ publishEncrypted?: boolean;
705
+ symmetricKey?: string;
706
+ paymentConditions?: PaymentCondition[];
707
+ writeToFile?: boolean;
708
+ returnUpdatedStatusList?: boolean;
709
+ returnSymmetricKey?: boolean;
710
+ returnStatusListMetadata?: boolean;
711
+ dkgOptions?: DkgOptions;
712
+ options?: ICheqdStatusListOptions;
713
+ fee?: DidStdFee | 'auto' | number;
714
+ }
715
+ export interface ICheqdBulkUpdateCredentialWithStatusListArgs {
716
+ credentials?: W3CVerifiableCredential[];
717
+ newStatus: BitstringStatusValue; // 0=valid, 1=revoked, 2=suspended, 3=unknown
718
+ updateOptions?: ICheqdBulkCredentialStatusUpdateOptions;
541
719
  verificationOptions?: IVerifyCredentialArgs;
542
720
  fetchList?: boolean;
721
+ publish?: boolean;
722
+ publishEncrypted?: boolean;
723
+ symmetricKey?: string;
724
+ paymentConditions?: PaymentCondition[];
725
+ writeToFile?: boolean;
726
+ returnUpdatedStatusList?: boolean;
727
+ returnSymmetricKey?: boolean;
728
+ returnStatusListMetadata?: boolean;
543
729
  dkgOptions?: DkgOptions;
544
- options?: ICheqdStatusList2021Options;
730
+ options?: ICheqdStatusListOptions;
731
+ fee?: DidStdFee | 'auto' | number;
545
732
  }
546
733
 
547
- export interface ICheqdRevokeCredentialWithStatusList2021Args {
734
+ export interface ICheqdRevokeCredentialWithStatusListArgs {
548
735
  credential?: W3CVerifiableCredential;
549
- revocationOptions?: ICheqdRevokeCredentialWithStatusList2021Options;
736
+ revocationOptions?: ICheqdCredentialStatusUpdateOptions;
550
737
  verificationOptions?: IVerifyCredentialArgs;
551
738
  fetchList?: boolean;
552
739
  publish?: boolean;
@@ -558,12 +745,12 @@ export interface ICheqdRevokeCredentialWithStatusList2021Args {
558
745
  returnSymmetricKey?: boolean;
559
746
  returnStatusListMetadata?: boolean;
560
747
  dkgOptions?: DkgOptions;
561
- options?: ICheqdStatusList2021Options;
748
+ options?: ICheqdStatusListOptions;
562
749
  }
563
750
 
564
- export interface ICheqdRevokeBulkCredentialsWithStatusList2021Args {
751
+ export interface ICheqdRevokeBulkCredentialsWithStatusListArgs {
565
752
  credentials?: W3CVerifiableCredential[];
566
- revocationOptions?: ICheqdRevokeBulkCredentialsWithStatusList2021Options;
753
+ revocationOptions?: ICheqdBulkCredentialStatusUpdateOptions;
567
754
  verificationOptions?: IVerifyCredentialArgs;
568
755
  fetchList?: boolean;
569
756
  publish?: boolean;
@@ -575,13 +762,13 @@ export interface ICheqdRevokeBulkCredentialsWithStatusList2021Args {
575
762
  returnSymmetricKey?: boolean;
576
763
  returnStatusListMetadata?: boolean;
577
764
  dkgOptions?: DkgOptions;
578
- options?: ICheqdStatusList2021Options;
765
+ options?: ICheqdStatusListOptions;
579
766
  fee?: DidStdFee | 'auto' | number;
580
767
  }
581
768
 
582
- export interface ICheqdSuspendCredentialWithStatusList2021Args {
769
+ export interface ICheqdSuspendCredentialWithStatusListArgs {
583
770
  credential?: W3CVerifiableCredential;
584
- suspensionOptions?: ICheqdSuspendCredentialWithStatusList2021Options;
771
+ suspensionOptions?: ICheqdCredentialStatusUpdateOptions;
585
772
  verificationOptions?: IVerifyCredentialArgs;
586
773
  fetchList?: boolean;
587
774
  publish?: boolean;
@@ -593,13 +780,13 @@ export interface ICheqdSuspendCredentialWithStatusList2021Args {
593
780
  returnSymmetricKey?: boolean;
594
781
  returnStatusListMetadata?: boolean;
595
782
  dkgOptions?: DkgOptions;
596
- options?: ICheqdStatusList2021Options;
783
+ options?: ICheqdStatusListOptions;
597
784
  fee?: DidStdFee | 'auto' | number;
598
785
  }
599
786
 
600
- export interface ICheqdSuspendBulkCredentialsWithStatusList2021Args {
787
+ export interface ICheqdSuspendBulkCredentialsWithStatusListArgs {
601
788
  credentials?: W3CVerifiableCredential[];
602
- suspensionOptions?: ICheqdSuspendBulkCredentialsWithStatusList2021Options;
789
+ suspensionOptions?: ICheqdBulkCredentialStatusUpdateOptions;
603
790
  verificationOptions?: IVerifyCredentialArgs;
604
791
  fetchList?: boolean;
605
792
  publish?: boolean;
@@ -611,13 +798,13 @@ export interface ICheqdSuspendBulkCredentialsWithStatusList2021Args {
611
798
  returnSymmetricKey?: boolean;
612
799
  returnStatusListMetadata?: boolean;
613
800
  dkgOptions?: DkgOptions;
614
- options?: ICheqdStatusList2021Options;
801
+ options?: ICheqdStatusListOptions;
615
802
  fee?: DidStdFee | 'auto' | number;
616
803
  }
617
804
 
618
- export interface ICheqdUnsuspendCredentialWithStatusList2021Args {
805
+ export interface ICheqdUnsuspendCredentialWithStatusListArgs {
619
806
  credential?: W3CVerifiableCredential;
620
- unsuspensionOptions?: ICheqdUnsuspendCredentialWithStatusList2021Options;
807
+ unsuspensionOptions?: ICheqdCredentialStatusUpdateOptions;
621
808
  verificationOptions?: IVerifyCredentialArgs;
622
809
  fetchList?: boolean;
623
810
  publish?: boolean;
@@ -629,13 +816,13 @@ export interface ICheqdUnsuspendCredentialWithStatusList2021Args {
629
816
  returnSymmetricKey?: boolean;
630
817
  returnStatusListMetadata?: boolean;
631
818
  dkgOptions?: DkgOptions;
632
- options?: ICheqdStatusList2021Options;
819
+ options?: ICheqdStatusListOptions;
633
820
  fee?: DidStdFee | 'auto' | number;
634
821
  }
635
822
 
636
- export interface ICheqdUnsuspendBulkCredentialsWithStatusList2021Args {
823
+ export interface ICheqdUnsuspendBulkCredentialsWithStatusListArgs {
637
824
  credentials?: W3CVerifiableCredential[];
638
- unsuspensionOptions?: ICheqdUnsuspendBulkCredentialsWithStatusList2021Options;
825
+ unsuspensionOptions?: ICheqdBulkCredentialStatusUpdateOptions;
639
826
  verificationOptions?: IVerifyCredentialArgs;
640
827
  fetchList?: boolean;
641
828
  publish?: boolean;
@@ -647,7 +834,7 @@ export interface ICheqdUnsuspendBulkCredentialsWithStatusList2021Args {
647
834
  returnSymmetricKey?: boolean;
648
835
  returnStatusListMetadata?: boolean;
649
836
  dkgOptions?: DkgOptions;
650
- options?: ICheqdStatusList2021Options;
837
+ options?: ICheqdStatusListOptions;
651
838
  fee?: DidStdFee | 'auto' | number;
652
839
  }
653
840
 
@@ -688,7 +875,7 @@ export interface ICheqdDelegateCapacityCreditArgs {
688
875
  statement?: string;
689
876
  }
690
877
 
691
- export interface ICheqdStatusList2021Options {
878
+ export interface ICheqdStatusListOptions {
692
879
  statusListFile?: string;
693
880
  statusListInlineBitstring?: string;
694
881
  fee?: DidStdFee | 'auto' | number;
@@ -697,53 +884,32 @@ export interface ICheqdStatusList2021Options {
697
884
  [key: string]: any;
698
885
  }
699
886
 
700
- export interface ICheqdRevokeCredentialWithStatusList2021Options {
701
- issuerDid: string;
702
- statusListName: string;
703
- statusListIndex: number;
704
- statusListVersion?: string;
705
- }
706
-
707
- export interface ICheqdRevokeBulkCredentialsWithStatusList2021Options {
708
- issuerDid: string;
709
- statusListName: string;
710
- statusListIndices: number[];
711
- statusListVersion?: string;
712
- }
713
-
714
- export interface ICheqdSuspendCredentialWithStatusList2021Options {
887
+ export interface ICheqdCredentialStatusUpdateOptions {
715
888
  issuerDid: string;
716
889
  statusListName: string;
717
890
  statusListIndex: number;
718
891
  statusListVersion?: string;
719
892
  }
720
893
 
721
- export interface ICheqdSuspendBulkCredentialsWithStatusList2021Options {
894
+ export interface ICheqdBulkCredentialStatusUpdateOptions {
722
895
  issuerDid: string;
723
896
  statusListName: string;
724
897
  statusListIndices: number[];
725
898
  statusListVersion?: string;
726
899
  }
727
900
 
728
- export interface ICheqdUnsuspendCredentialWithStatusList2021Options {
729
- issuerDid: string;
730
- statusListName: string;
731
- statusListIndex: number;
732
- statusListVersion?: string;
733
- }
734
-
735
- export interface ICheqdUnsuspendBulkCredentialsWithStatusList2021Options {
736
- issuerDid: string;
737
- statusListName: string;
738
- statusListIndices: number[];
739
- statusListVersion?: string;
901
+ export enum BitstringStatusValue {
902
+ VALID = 0, // 0x0 - valid
903
+ REVOKED = 1, // 0x1 - revoked
904
+ SUSPENDED = 2, // 0x2 - suspended
905
+ UNKNOWN = 3, // 0x3 - unknown
740
906
  }
741
907
 
742
- export interface ICheqdCheckCredentialWithStatusList2021StatusOptions {
908
+ export interface ICheqdCheckCredentialStatusOptions {
743
909
  issuerDid: string;
744
910
  statusListName: string;
745
911
  statusListIndex: number;
746
- statusPurpose: DefaultStatusList2021StatusPurposeType;
912
+ statusPurpose: DefaultStatusList2021StatusPurposeType | BitstringStatusListPurposeType;
747
913
  statusListVersion?: string;
748
914
  }
749
915
 
@@ -762,10 +928,7 @@ export interface ICheqd extends IPluginMethodMap {
762
928
  args: ICheqdCreateStatusList2021Args,
763
929
  context: IContext
764
930
  ) => Promise<CreateStatusList2021Result>;
765
- [BroadcastStatusList2021MethodName]: (
766
- args: ICheqdBroadcastStatusList2021Args,
767
- context: IContext
768
- ) => Promise<boolean>;
931
+ [BroadcastStatusList2021MethodName]: (args: ICheqdBroadcastStatusListArgs, context: IContext) => Promise<boolean>;
769
932
  [GenerateDidDocMethodName]: (args: ICheqdGenerateDidDocArgs, context: IContext) => Promise<TExportedDIDDocWithKeys>;
770
933
  [GenerateDidDocWithLinkedResourceMethodName]: (
771
934
  args: ICheqdGenerateDidDocWithLinkedResourceArgs,
@@ -773,6 +936,20 @@ export interface ICheqd extends IPluginMethodMap {
773
936
  ) => Promise<TExportedDIDDocWithLinkedResourceWithKeys>;
774
937
  [GenerateKeyPairMethodName]: (args: ICheqdGenerateKeyPairArgs, context: IContext) => Promise<TImportableEd25519Key>;
775
938
  [GenerateVersionIdMethodName]: (args: ICheqdGenerateVersionIdArgs, context: IContext) => Promise<string>;
939
+ [CreateStatusListMethodName]: (
940
+ args: ICheqdCreateBitstringStatusListArgs,
941
+ context: IContext
942
+ ) => Promise<CreateStatusListResult>;
943
+ [BroadcastStatusListMethodName]: (args: ICheqdBroadcastStatusListArgs, context: IContext) => Promise<boolean>;
944
+ [GenerateStatusListMethodName]: (args: ICheqdGenerateStatusListArgs, context: IContext) => Promise<string>;
945
+ [VerifyStatusListCredentialMethodName]: (
946
+ args: ICheqdVerifyStatusListCredentialArgs,
947
+ context: IContext
948
+ ) => Promise<VerificationResult>;
949
+ [IssueCredentialWithStatusListMethodName]: (
950
+ args: ICheqdIssueCredentialWithStatusListArgs,
951
+ context: IContext
952
+ ) => Promise<BitstringVerifiableCredential>;
776
953
  [GenerateStatusList2021MethodName]: (args: ICheqdGenerateStatusList2021Args, context: IContext) => Promise<string>;
777
954
  [IssueRevocableCredentialWithStatusList2021MethodName]: (
778
955
  args: ICheqdIssueRevocableCredentialWithStatusList2021Args,
@@ -783,39 +960,55 @@ export interface ICheqd extends IPluginMethodMap {
783
960
  context: IContext
784
961
  ) => Promise<VerifiableCredential>;
785
962
  [VerifyCredentialMethodName]: (
786
- args: ICheqdVerifyCredentialWithStatusList2021Args,
963
+ args: ICheqdVerifyCredentialWithStatusListArgs,
964
+ context: IContext
965
+ ) => Promise<VerificationResult>;
966
+ [VerifyCredentialWithStatusListMethodName]: (
967
+ args: ICheqdVerifyCredentialWithBitstringArgs,
787
968
  context: IContext
788
969
  ) => Promise<VerificationResult>;
789
970
  [VerifyPresentationMethodName]: (
790
- args: ICheqdVerifyPresentationWithStatusList2021Args,
971
+ args: ICheqdVerifyPresentationWithStatusListArgs,
791
972
  context: IContext
792
973
  ) => Promise<VerificationResult>;
793
974
  [CheckCredentialStatusMethodName]: (
794
- args: ICheqdCheckCredentialStatusWithStatusList2021Args,
975
+ args: ICheqdCheckCredentialStatusWithStatusListArgs,
795
976
  context: IContext
796
977
  ) => Promise<StatusCheckResult>;
978
+ [VerifyPresentationWithStatusListMethodName]: (
979
+ args: ICheqdVerifyPresentationWithStatusListArgs,
980
+ context: IContext
981
+ ) => Promise<BitstringVerificationResult>;
982
+ [UpdateCredentialWithStatusListMethodName]: (
983
+ args: ICheqdUpdateCredentialWithStatusListArgs,
984
+ context: IContext
985
+ ) => Promise<BitstringUpdateResult>;
986
+ [BulkUpdateCredentialsWithStatusListMethodName]: (
987
+ args: ICheqdBulkUpdateCredentialWithStatusListArgs,
988
+ context: IContext
989
+ ) => Promise<BulkBitstringUpdateResult>;
797
990
  [RevokeCredentialMethodName]: (
798
- args: ICheqdRevokeCredentialWithStatusList2021Args,
991
+ args: ICheqdRevokeCredentialWithStatusListArgs,
799
992
  context: IContext
800
993
  ) => Promise<RevocationResult>;
801
994
  [RevokeCredentialsMethodName]: (
802
- args: ICheqdRevokeBulkCredentialsWithStatusList2021Args,
995
+ args: ICheqdRevokeBulkCredentialsWithStatusListArgs,
803
996
  context: IContext
804
997
  ) => Promise<BulkRevocationResult>;
805
998
  [SuspendCredentialMethodName]: (
806
- args: ICheqdSuspendCredentialWithStatusList2021Args,
999
+ args: ICheqdSuspendCredentialWithStatusListArgs,
807
1000
  context: IContext
808
1001
  ) => Promise<SuspensionResult>;
809
1002
  [SuspendCredentialsMethodName]: (
810
- args: ICheqdSuspendBulkCredentialsWithStatusList2021Args,
1003
+ args: ICheqdSuspendBulkCredentialsWithStatusListArgs,
811
1004
  context: IContext
812
1005
  ) => Promise<BulkSuspensionResult>;
813
1006
  [UnsuspendCredentialMethodName]: (
814
- args: ICheqdUnsuspendCredentialWithStatusList2021Args,
1007
+ args: ICheqdUnsuspendCredentialWithStatusListArgs,
815
1008
  context: IContext
816
1009
  ) => Promise<UnsuspensionResult>;
817
1010
  [UnsuspendCredentialsMethodName]: (
818
- args: ICheqdUnsuspendBulkCredentialsWithStatusList2021Args,
1011
+ args: ICheqdUnsuspendBulkCredentialsWithStatusListArgs,
819
1012
  context: IContext
820
1013
  ) => Promise<BulkUnsuspensionResult>;
821
1014
  [TransactSendTokensMethodName]: (
@@ -922,6 +1115,22 @@ export class Cheqd implements IAgentPlugin {
922
1115
  type: 'object',
923
1116
  },
924
1117
  },
1118
+ cheqdCreateStatusList: {
1119
+ description: 'Create a new Bitstring Status List',
1120
+ arguments: {
1121
+ type: 'object',
1122
+ properties: {
1123
+ args: {
1124
+ type: 'object',
1125
+ description: 'A cheqdCreateBitstringStatusListArgs object as any for extensibility',
1126
+ },
1127
+ },
1128
+ required: ['args'],
1129
+ },
1130
+ returnType: {
1131
+ type: 'object',
1132
+ },
1133
+ },
925
1134
  cheqdBroadcastStatusList2021: {
926
1135
  description: 'Broadcast a Status List 2021 to cheqd ledger',
927
1136
  arguments: {
@@ -929,7 +1138,23 @@ export class Cheqd implements IAgentPlugin {
929
1138
  properties: {
930
1139
  args: {
931
1140
  type: 'object',
932
- description: 'A cheqdBroadcastStatusList2021Args object as any for extensibility',
1141
+ description: 'A cheqdBroadcastStatusListArgs object as any for extensibility',
1142
+ },
1143
+ },
1144
+ required: ['args'],
1145
+ },
1146
+ returnType: {
1147
+ type: 'object',
1148
+ },
1149
+ },
1150
+ cheqdBroadcastStatusList: {
1151
+ description: 'Broadcast a Bitstring Status List to cheqd ledger',
1152
+ arguments: {
1153
+ type: 'object',
1154
+ properties: {
1155
+ args: {
1156
+ type: 'object',
1157
+ description: 'A cheqdBroadcastStatusListArgs object as any for extensibility',
933
1158
  },
934
1159
  },
935
1160
  required: ['args'],
@@ -1016,6 +1241,38 @@ export class Cheqd implements IAgentPlugin {
1016
1241
  type: 'string',
1017
1242
  },
1018
1243
  },
1244
+ cheqdGenerateStatusList: {
1245
+ description: 'Generate a new Bitstring Status List',
1246
+ arguments: {
1247
+ type: 'object',
1248
+ properties: {
1249
+ args: {
1250
+ type: 'object',
1251
+ description: 'A cheqdGenerateStatusListArgs object as any for extensibility',
1252
+ },
1253
+ },
1254
+ },
1255
+ returnType: {
1256
+ type: 'string',
1257
+ },
1258
+ },
1259
+ cheqdIssueCredentialWithStatusList: {
1260
+ description:
1261
+ 'Issue a revocable or suspendable credential with a Bitstring Status List as credential status registry',
1262
+ arguments: {
1263
+ type: 'object',
1264
+ properties: {
1265
+ args: {
1266
+ type: 'object',
1267
+ description: 'A cheqdIssueCredentialWithStatusListArgs object as any for extensibility',
1268
+ },
1269
+ },
1270
+ required: ['args'],
1271
+ },
1272
+ returnType: {
1273
+ type: 'object',
1274
+ },
1275
+ },
1019
1276
  cheqdIssueRevocableCredentialWithStatusList2021: {
1020
1277
  description: 'Issue a revocable credential with a Status List 2021 as credential status registry',
1021
1278
  arguments: {
@@ -1024,7 +1281,7 @@ export class Cheqd implements IAgentPlugin {
1024
1281
  args: {
1025
1282
  type: 'object',
1026
1283
  description:
1027
- 'A cheqdIssueCredentialWithStatusList2021Args object as any for extensibility',
1284
+ 'A cheqdIssueRevocableCredentialWithStatusList2021Args object as any for extensibility',
1028
1285
  },
1029
1286
  },
1030
1287
  required: ['args'],
@@ -1041,7 +1298,7 @@ export class Cheqd implements IAgentPlugin {
1041
1298
  args: {
1042
1299
  type: 'object',
1043
1300
  description:
1044
- 'A cheqdIssueCredentialWithStatusList2021Args object as any for extensibility',
1301
+ 'A cheqdIssueSuspendableCredentialWithStatusList2021Args object as any for extensibility',
1045
1302
  },
1046
1303
  },
1047
1304
  required: ['args'],
@@ -1059,7 +1316,25 @@ export class Cheqd implements IAgentPlugin {
1059
1316
  args: {
1060
1317
  type: 'object',
1061
1318
  description:
1062
- 'A cheqdVerifyCredentialWithStatusList2021Args object as any for extensibility',
1319
+ 'A cheqdVerifyCredentialWithStatusListArgs object as any for extensibility',
1320
+ },
1321
+ },
1322
+ required: ['args'],
1323
+ },
1324
+ returnType: {
1325
+ type: 'object',
1326
+ },
1327
+ },
1328
+ cheqdVerifyCredentialWithStatusList: {
1329
+ description:
1330
+ 'Verify a credential, enhanced by revocation / suspension check with a Bitstring Status List as credential status registry',
1331
+ arguments: {
1332
+ type: 'object',
1333
+ properties: {
1334
+ args: {
1335
+ type: 'object',
1336
+ description:
1337
+ 'A cheqdVerifyCredentialWithStatusListArgs object as any for extensibility',
1063
1338
  },
1064
1339
  },
1065
1340
  required: ['args'],
@@ -1077,7 +1352,7 @@ export class Cheqd implements IAgentPlugin {
1077
1352
  args: {
1078
1353
  type: 'object',
1079
1354
  description:
1080
- 'A cheqdVerifyPresentationWithStatusList2021Args object as any for extensibility',
1355
+ 'A cheqdVerifyPresentationWithStatusListArgs object as any for extensibility',
1081
1356
  },
1082
1357
  },
1083
1358
  required: ['args'],
@@ -1095,7 +1370,7 @@ export class Cheqd implements IAgentPlugin {
1095
1370
  args: {
1096
1371
  type: 'object',
1097
1372
  description:
1098
- 'A cheqdCheckCredentialStatusWithStatusList2021Args object as any for extensibility',
1373
+ 'A cheqdCheckCredentialStatusWithStatusListArgs object as any for extensibility',
1099
1374
  },
1100
1375
  },
1101
1376
  required: ['args'],
@@ -1112,7 +1387,7 @@ export class Cheqd implements IAgentPlugin {
1112
1387
  args: {
1113
1388
  type: 'object',
1114
1389
  description:
1115
- 'A cheqdRevokeCredentialWithStatusList2021Args object as any for extensibility',
1390
+ 'A cheqdRevokeCredentialWithStatusListArgs object as any for extensibility',
1116
1391
  },
1117
1392
  },
1118
1393
  required: ['args'],
@@ -1129,7 +1404,7 @@ export class Cheqd implements IAgentPlugin {
1129
1404
  args: {
1130
1405
  type: 'object',
1131
1406
  description:
1132
- 'A cheqdRevokeBulkCredentialsWithStatusList2021Args object as any for extensibility',
1407
+ 'A cheqdRevokeBulkCredentialsWithStatusListArgs object as any for extensibility',
1133
1408
  },
1134
1409
  },
1135
1410
  required: ['args'],
@@ -1146,7 +1421,7 @@ export class Cheqd implements IAgentPlugin {
1146
1421
  args: {
1147
1422
  type: 'object',
1148
1423
  description:
1149
- 'A cheqdSuspendCredentialWithStatusList2021Args object as any for extensibility',
1424
+ 'A cheqdSuspendCredentialWithStatusListArgs object as any for extensibility',
1150
1425
  },
1151
1426
  },
1152
1427
  required: ['args'],
@@ -1164,7 +1439,7 @@ export class Cheqd implements IAgentPlugin {
1164
1439
  args: {
1165
1440
  type: 'object',
1166
1441
  description:
1167
- 'A cheqdSuspendBulkCredentialsWithStatusList2021Args object as any for extensibility',
1442
+ 'A cheqdSuspendBulkCredentialsWithStatusListArgs object as any for extensibility',
1168
1443
  },
1169
1444
  },
1170
1445
  required: ['args'],
@@ -1181,7 +1456,7 @@ export class Cheqd implements IAgentPlugin {
1181
1456
  args: {
1182
1457
  type: 'object',
1183
1458
  description:
1184
- 'cheqdUnsuspendCredentialWithStatusList2021Args object as any for extensibility',
1459
+ 'cheqdUnsuspendCredentialWithStatusListArgs object as any for extensibility',
1185
1460
  },
1186
1461
  },
1187
1462
  required: ['args'],
@@ -1199,7 +1474,7 @@ export class Cheqd implements IAgentPlugin {
1199
1474
  args: {
1200
1475
  type: 'object',
1201
1476
  description:
1202
- 'A cheqdUnsuspendBulkCredentialsWithStatusList2021Args object as any for extensibility',
1477
+ 'A cheqdUnsuspendBulkCredentialsWithStatusListArgs object as any for extensibility',
1203
1478
  },
1204
1479
  },
1205
1480
  required: ['args'],
@@ -1246,9 +1521,19 @@ export class Cheqd implements IAgentPlugin {
1246
1521
  private readonly supportedDidProviders: CheqdDIDProvider[];
1247
1522
  private didProvider: CheqdDIDProvider;
1248
1523
  private providerId: string;
1524
+ // Deprecate below constants in future versions
1249
1525
  static readonly defaultStatusList2021Length: number = 16 * 1024 * 8; // 16KB in bits or 131072 bits / entries
1250
1526
  static readonly defaultContextV1 = 'https://www.w3.org/2018/credentials/v1';
1251
1527
  static readonly statusList2021Context = 'https://w3id.org/vc-status-list-2021/v1';
1528
+ // END: Deprecate
1529
+ static readonly DefaultBitstringContexts = {
1530
+ v2: 'https://www.w3.org/ns/credentials/v2',
1531
+ statusList: 'https://www.w3.org/ns/credentials/status/v1',
1532
+ };
1533
+ // Default bitstring status list size in bits
1534
+ static readonly DefaultBitstringStatusSize: number = 2; // 2 bits per credential (0, 1, 2, 3)
1535
+ // Minimum bitstring length for compliance
1536
+ static readonly DefaultBitstringLength: number = 16 * 1024 * 8; // 16KB in bits or 131072 bits (spec minimum)
1252
1537
 
1253
1538
  constructor(args: { providers: CheqdDIDProvider[] }) {
1254
1539
  if (typeof args.providers !== 'object') {
@@ -1266,18 +1551,27 @@ export class Cheqd implements IAgentPlugin {
1266
1551
  [CreateResourceMethodName]: this.CreateResource.bind(this),
1267
1552
  [CreateStatusList2021MethodName]: this.CreateStatusList2021.bind(this),
1268
1553
  [BroadcastStatusList2021MethodName]: this.BroadcastStatusList2021.bind(this),
1554
+ [CreateStatusListMethodName]: this.CreateBitstringStatusList.bind(this),
1555
+ [BroadcastStatusListMethodName]: this.BroadcastBitstringStatusList.bind(this),
1269
1556
  [GenerateDidDocMethodName]: this.GenerateDidDoc.bind(this),
1270
1557
  [GenerateDidDocWithLinkedResourceMethodName]: this.GenerateDidDocWithLinkedResource.bind(this),
1271
1558
  [GenerateKeyPairMethodName]: this.GenerateIdentityKeys.bind(this),
1272
1559
  [GenerateVersionIdMethodName]: this.GenerateVersionId.bind(this),
1273
1560
  [GenerateStatusList2021MethodName]: this.GenerateStatusList2021.bind(this),
1561
+ [GenerateStatusListMethodName]: this.GenerateBitstringStatusList.bind(this),
1562
+ [VerifyStatusListCredentialMethodName]: this.VerifyStatusListCredential.bind(this),
1563
+ [IssueCredentialWithStatusListMethodName]: this.IssueCredentialWithBitstringStatusList.bind(this),
1274
1564
  [IssueRevocableCredentialWithStatusList2021MethodName]:
1275
1565
  this.IssueRevocableCredentialWithStatusList2021.bind(this),
1276
1566
  [IssueSuspendableCredentialWithStatusList2021MethodName]:
1277
1567
  this.IssueSuspendableCredentialWithStatusList2021.bind(this),
1278
1568
  [VerifyCredentialMethodName]: this.VerifyCredentialWithStatusList2021.bind(this),
1569
+ [VerifyCredentialWithStatusListMethodName]: this.VerifyCredentialWithBitstringStatusList.bind(this),
1279
1570
  [VerifyPresentationMethodName]: this.VerifyPresentationWithStatusList2021.bind(this),
1280
1571
  [CheckCredentialStatusMethodName]: this.CheckCredentialStatusWithStatusList2021.bind(this),
1572
+ [VerifyPresentationWithStatusListMethodName]: this.VerifyPresentationWithBitstringStatusList.bind(this),
1573
+ [UpdateCredentialWithStatusListMethodName]: this.UpdateCredentialWithStatusList.bind(this),
1574
+ [BulkUpdateCredentialsWithStatusListMethodName]: this.BulkUpdateCredentialsWithStatusList.bind(this),
1281
1575
  [RevokeCredentialMethodName]: this.RevokeCredentialWithStatusList2021.bind(this),
1282
1576
  [RevokeCredentialsMethodName]: this.RevokeBulkCredentialsWithStatusList2021.bind(this),
1283
1577
  [SuspendCredentialMethodName]: this.SuspendCredentialWithStatusList2021.bind(this),
@@ -1467,10 +1761,10 @@ export class Cheqd implements IAgentPlugin {
1467
1761
  throw new Error('[did-provider-cheqd]: statusListEncoding must be string');
1468
1762
  }
1469
1763
 
1470
- if (!Object.values(DefaultStatusList2021Encodings).includes(args.statusListEncoding)) {
1764
+ if (!Object.values(DefaultStatusListEncodings).includes(args.statusListEncoding)) {
1471
1765
  throw new Error(
1472
1766
  `[did-provider-cheqd]: statusListEncoding must be one of ${Object.values(
1473
- DefaultStatusList2021Encodings
1767
+ DefaultStatusListEncodings
1474
1768
  ).join(', ')}`
1475
1769
  );
1476
1770
  }
@@ -1549,7 +1843,7 @@ export class Cheqd implements IAgentPlugin {
1549
1843
  // generate bitstring
1550
1844
  const bitstring = await context.agent[GenerateStatusList2021MethodName]({
1551
1845
  length: args?.statusListLength || Cheqd.defaultStatusList2021Length,
1552
- bitstringEncoding: args?.statusListEncoding || DefaultStatusList2021Encodings.base64url,
1846
+ bitstringEncoding: args?.statusListEncoding || DefaultStatusListEncodings.base64url,
1553
1847
  });
1554
1848
 
1555
1849
  // construct data and metadata tuple
@@ -1558,7 +1852,7 @@ export class Cheqd implements IAgentPlugin {
1558
1852
  // encrypt bitstring - case: symmetric
1559
1853
  const { encryptedString: symmetricEncryptionCiphertext, symmetricKey } =
1560
1854
  await LitProtocol.encryptDirect(
1561
- fromString(bitstring, args?.statusListEncoding || DefaultStatusList2021Encodings.base64url)
1855
+ fromString(bitstring, args?.statusListEncoding || DefaultStatusListEncodings.base64url)
1562
1856
  );
1563
1857
 
1564
1858
  // instantiate dkg-threshold client, in which case lit-protocol is used
@@ -1590,7 +1884,7 @@ export class Cheqd implements IAgentPlugin {
1590
1884
 
1591
1885
  // encrypt bitstring - case: threshold
1592
1886
  const { encryptedString: thresholdEncryptionCiphertext, stringHash } = await lit.encrypt(
1593
- fromString(bitstring, args?.statusListEncoding || DefaultStatusList2021Encodings.base64url),
1887
+ fromString(bitstring, args?.statusListEncoding || DefaultStatusListEncodings.base64url),
1594
1888
  unifiedAccessControlConditions
1595
1889
  );
1596
1890
 
@@ -1614,7 +1908,7 @@ export class Cheqd implements IAgentPlugin {
1614
1908
  metadata: {
1615
1909
  type: DefaultStatusList2021ResourceTypes.revocation,
1616
1910
  encrypted: true,
1617
- encoding: args?.statusListEncoding || DefaultStatusList2021Encodings.base64url,
1911
+ encoding: args?.statusListEncoding || DefaultStatusListEncodings.base64url,
1618
1912
  statusListHash: stringHash,
1619
1913
  paymentConditions: args.paymentConditions,
1620
1914
  },
@@ -1638,7 +1932,7 @@ export class Cheqd implements IAgentPlugin {
1638
1932
  metadata: {
1639
1933
  type: DefaultStatusList2021ResourceTypes.suspension,
1640
1934
  encrypted: true,
1641
- encoding: args?.statusListEncoding || DefaultStatusList2021Encodings.base64url,
1935
+ encoding: args?.statusListEncoding || DefaultStatusListEncodings.base64url,
1642
1936
  statusListHash: stringHash,
1643
1937
  paymentConditions: args.paymentConditions,
1644
1938
  },
@@ -1668,7 +1962,7 @@ export class Cheqd implements IAgentPlugin {
1668
1962
  metadata: {
1669
1963
  type: DefaultStatusList2021ResourceTypes.revocation,
1670
1964
  encrypted: false,
1671
- encoding: args?.statusListEncoding || DefaultStatusList2021Encodings.base64url,
1965
+ encoding: args?.statusListEncoding || DefaultStatusListEncodings.base64url,
1672
1966
  },
1673
1967
  } satisfies StatusList2021Revocation,
1674
1968
  undefined,
@@ -1685,7 +1979,7 @@ export class Cheqd implements IAgentPlugin {
1685
1979
  metadata: {
1686
1980
  type: DefaultStatusList2021ResourceTypes.suspension,
1687
1981
  encrypted: false,
1688
- encoding: args?.statusListEncoding || DefaultStatusList2021Encodings.base64url,
1982
+ encoding: args?.statusListEncoding || DefaultStatusListEncodings.base64url,
1689
1983
  },
1690
1984
  } satisfies StatusList2021Suspension,
1691
1985
  undefined,
@@ -1714,7 +2008,7 @@ export class Cheqd implements IAgentPlugin {
1714
2008
  network: network as CheqdNetwork,
1715
2009
  }),
1716
2010
  resource: data[0],
1717
- resourceMetadata: await Cheqd.fetchStatusList2021Metadata({
2011
+ resourceMetadata: await Cheqd.fetchStatusListMetadata({
1718
2012
  credentialStatus: {
1719
2013
  id: `${DefaultResolverUrl}${args.issuerDid}?resourceName=${args.statusListName}&resourceType=${
1720
2014
  DefaultStatusList2021ResourceTypes[args.statusPurpose]
@@ -1727,7 +2021,7 @@ export class Cheqd implements IAgentPlugin {
1727
2021
  } satisfies CreateStatusList2021Result;
1728
2022
  }
1729
2023
 
1730
- private async BroadcastStatusList2021(args: ICheqdBroadcastStatusList2021Args, context: IContext) {
2024
+ private async BroadcastStatusList2021(args: ICheqdBroadcastStatusListArgs, context: IContext) {
1731
2025
  if (typeof args.kms !== 'string') {
1732
2026
  throw new Error('[did-provider-cheqd]: kms is required');
1733
2027
  }
@@ -1751,11 +2045,10 @@ export class Cheqd implements IAgentPlugin {
1751
2045
  // TODO: validate data as per bitstring
1752
2046
 
1753
2047
  // validate resource type
1754
- if (!Object.values(DefaultStatusList2021ResourceTypes).includes(args?.payload?.resourceType)) {
2048
+ const allowedTypes = [...Object.values(DefaultStatusList2021ResourceTypes), 'BitstringStatusListCredential'];
2049
+ if (!Object.values(allowedTypes).includes(args?.payload?.resourceType)) {
1755
2050
  throw new Error(
1756
- `[did-provider-cheqd]: resourceType must be one of ${Object.values(
1757
- DefaultStatusList2021ResourceTypes
1758
- ).join(', ')}`
2051
+ `[did-provider-cheqd]: resourceType must be one of ${Object.values(allowedTypes).join(', ')}`
1759
2052
  );
1760
2053
  }
1761
2054
 
@@ -1779,69 +2072,527 @@ export class Cheqd implements IAgentPlugin {
1779
2072
  );
1780
2073
  }
1781
2074
 
1782
- private async GenerateDidDoc(args: ICheqdGenerateDidDocArgs, context: IContext): Promise<TExportedDIDDocWithKeys> {
1783
- if (typeof args.verificationMethod !== 'string') {
1784
- throw new Error('[did-provider-cheqd]: verificationMethod is required');
2075
+ private async CreateBitstringStatusList(args: ICheqdCreateBitstringStatusListArgs, context: IContext) {
2076
+ if (typeof args.kms !== 'string') {
2077
+ throw new Error('[did-provider-cheqd]: kms is required');
1785
2078
  }
1786
-
1787
- if (typeof args.methodSpecificIdAlgo !== 'string') {
1788
- throw new Error('[did-provider-cheqd]: methodSpecificIdAlgo is required');
2079
+ if (typeof args.issuerDid !== 'string' || !args.issuerDid) {
2080
+ throw new Error('[did-provider-cheqd]: issuerDid is required');
1789
2081
  }
1790
-
1791
- if (typeof args.network !== 'string') {
1792
- throw new Error('[did-provider-cheqd]: network is required');
2082
+ if (typeof args.statusListName !== 'string' || !args.statusListName) {
2083
+ throw new Error('[did-provider-cheqd]: statusListName is required');
1793
2084
  }
1794
-
1795
- const keyPair = createKeyPairBase64();
1796
- const keyPairHex: IKeyPair = {
1797
- publicKey: toString(fromString(keyPair.publicKey, 'base64'), 'hex'),
1798
- privateKey: toString(fromString(keyPair.privateKey, 'base64'), 'hex'),
1799
- };
1800
- const verificationKeys = createVerificationKeys(
1801
- keyPair.publicKey,
1802
- args.methodSpecificIdAlgo,
1803
- 'key-1',
1804
- args.network
1805
- );
1806
- const verificationMethods = createDidVerificationMethod([args.verificationMethod], [verificationKeys]);
1807
-
1808
- return {
1809
- didDoc: createDidPayload(verificationMethods, [verificationKeys]),
1810
- versionId: v4(),
1811
- keys: [
1812
- {
1813
- publicKeyHex: keyPairHex.publicKey,
1814
- privateKeyHex: keyPairHex.privateKey,
1815
- kid: keyPairHex.publicKey,
1816
- type: 'Ed25519',
1817
- },
1818
- ],
1819
- };
1820
- }
1821
-
1822
- private async GenerateDidDocWithLinkedResource(
1823
- args: any,
1824
- context: IContext
1825
- ): Promise<TExportedDIDDocWithLinkedResourceWithKeys> {
1826
- if (typeof args.verificationMethod !== 'string') {
1827
- throw new Error('[did-provider-cheqd]: verificationMethod is required');
2085
+ if (!args.statusPurpose) {
2086
+ throw new Error('[did-provider-cheqd]: statusPurpose is required');
1828
2087
  }
1829
-
1830
- if (typeof args.methodSpecificIdAlgo !== 'string') {
1831
- throw new Error('[did-provider-cheqd]: methodSpecificIdAlgo is required');
2088
+ if (typeof args.encrypted === 'undefined') {
2089
+ throw new Error('[did-provider-cheqd]: encrypted is required');
1832
2090
  }
1833
-
1834
- if (typeof args.network !== 'string') {
1835
- throw new Error('[did-provider-cheqd]: network is required');
2091
+ // validate statusPurpose
2092
+ const statusPurpose = Array.isArray(args.statusPurpose) ? args.statusPurpose[0] : args.statusPurpose;
2093
+ if (!Object.values(BitstringStatusPurposeTypes).includes(statusPurpose)) {
2094
+ throw new Error(
2095
+ `[did-provider-cheqd]: statusPurpose must be in ${Object.values(BitstringStatusPurposeTypes).join(
2096
+ ', '
2097
+ )}`
2098
+ );
1836
2099
  }
1837
-
1838
- const keyPair = createKeyPairBase64();
1839
- const keyPairHex: IKeyPair = {
1840
- publicKey: toString(fromString(keyPair.publicKey, 'base64'), 'hex'),
1841
- privateKey: toString(fromString(keyPair.privateKey, 'base64'), 'hex'),
1842
- };
1843
- const verificationKeys = createVerificationKeys(
1844
- keyPair.publicKey,
2100
+ // validate statusListLength
2101
+ if (args?.statusListLength) {
2102
+ if (typeof args.statusListLength !== 'number') {
2103
+ throw new Error('[did-provider-cheqd]: statusListLength must be number');
2104
+ }
2105
+ if (args.statusListLength < Cheqd.DefaultBitstringLength) {
2106
+ throw new Error(
2107
+ `[did-provider-cheqd]: statusListLength must be greater than or equal to ${Cheqd.DefaultBitstringLength} number of entries`
2108
+ );
2109
+ }
2110
+ }
2111
+ // validate statusListEncoding, W3C spec only supports base64url encoding
2112
+ if (args?.statusListEncoding) {
2113
+ if (typeof args.statusListEncoding !== 'string') {
2114
+ throw new Error('[did-provider-cheqd]: statusListEncoding must be string');
2115
+ }
2116
+
2117
+ if (args.statusListEncoding !== DefaultStatusListEncodings.base64url) {
2118
+ throw new Error(
2119
+ `[did-provider-cheqd]: statusListEncoding must be ${DefaultStatusListEncodings.base64url}`
2120
+ );
2121
+ }
2122
+ }
2123
+ // validate validUntil
2124
+ if (args?.validUntil) {
2125
+ if (typeof args.validUntil !== 'string') {
2126
+ throw new Error('[did-provider-cheqd]: validUntil must be string');
2127
+ }
2128
+
2129
+ if (new Date() <= new Date(args.validUntil)) {
2130
+ throw new Error('[did-provider-cheqd]: validUntil must be greater than current date');
2131
+ }
2132
+ }
2133
+ // validate args in pairs - case: encrypted
2134
+ if (args.encrypted) {
2135
+ // validate paymentConditions
2136
+ if (
2137
+ !args?.paymentConditions ||
2138
+ !args?.paymentConditions?.length ||
2139
+ !Array.isArray(args?.paymentConditions) ||
2140
+ args?.paymentConditions.length === 0
2141
+ ) {
2142
+ throw new Error('[did-provider-cheqd]: paymentConditions is required');
2143
+ }
2144
+
2145
+ if (
2146
+ !args?.paymentConditions?.every(
2147
+ (condition) =>
2148
+ condition.feePaymentAddress && condition.feePaymentAmount && condition.intervalInSeconds
2149
+ )
2150
+ ) {
2151
+ throw new Error(
2152
+ '[did-provider-cheqd]: paymentConditions must contain feePaymentAddress and feeAmount and intervalInSeconds'
2153
+ );
2154
+ }
2155
+
2156
+ if (
2157
+ !args?.paymentConditions?.every(
2158
+ (condition) =>
2159
+ typeof condition.feePaymentAddress === 'string' &&
2160
+ typeof condition.feePaymentAmount === 'string' &&
2161
+ typeof condition.intervalInSeconds === 'number'
2162
+ )
2163
+ ) {
2164
+ throw new Error(
2165
+ '[did-provider-cheqd]: feePaymentAddress and feePaymentAmount must be string and intervalInSeconds must be number'
2166
+ );
2167
+ }
2168
+
2169
+ if (
2170
+ !args?.paymentConditions?.every(
2171
+ (condition) => condition.type === AccessControlConditionTypes.timelockPayment
2172
+ )
2173
+ ) {
2174
+ throw new Error('[did-provider-cheqd]: paymentConditions must be of type timelockPayment');
2175
+ }
2176
+ }
2177
+ // get network
2178
+ const network = args.issuerDid.split(':')[2];
2179
+ // define provider
2180
+ const provider = (function (that) {
2181
+ // switch on network
2182
+ return (
2183
+ that.supportedDidProviders.find((provider) => provider.network === network) ||
2184
+ (function () {
2185
+ throw new Error(`[did-provider-cheqd]: no relevant providers found`);
2186
+ })()
2187
+ );
2188
+ })(this);
2189
+ // generate bitstring
2190
+ const bitstring = await context.agent[GenerateStatusListMethodName]({
2191
+ statusSize: args?.statusSize,
2192
+ length: args?.statusListLength,
2193
+ bitstringEncoding: args?.statusListEncoding || DefaultStatusListEncodings.base64url,
2194
+ });
2195
+ // Generate proof without credentialSubject.encodedList property
2196
+ const issuanceOptions = {
2197
+ credential: {
2198
+ '@context': [Cheqd.defaultContextV1], // TODO: use v2 context when v2 credential support enabled
2199
+ type: ['VerifiableCredential', BitstringStatusListResourceType],
2200
+ issuer: args.issuerDid,
2201
+ issuanceDate: new Date().toISOString(),
2202
+ expirationDate: args?.validUntil,
2203
+ credentialSubject: {
2204
+ type: 'BitstringStatusList',
2205
+ statusPurpose: args.statusPurpose,
2206
+ ttl: args?.ttl,
2207
+ },
2208
+ },
2209
+ proofFormat: 'jwt',
2210
+ } as ICreateVerifiableCredentialArgs;
2211
+ const issued = await context.agent.createVerifiableCredential(issuanceOptions);
2212
+ // construct data and metadata tuple
2213
+ const data = args.encrypted
2214
+ ? await (async function (that: Cheqd) {
2215
+ // encrypt bitstring - case: symmetric
2216
+ const { encryptedString: symmetricEncryptionCiphertext, symmetricKey } =
2217
+ await LitProtocol.encryptDirect(
2218
+ fromString(bitstring, args?.statusListEncoding || DefaultStatusListEncodings.base64url)
2219
+ );
2220
+
2221
+ // instantiate dkg-threshold client, in which case lit-protocol is used
2222
+ const lit = await provider.instantiateDkgThresholdProtocolClient({});
2223
+
2224
+ // construct access control conditions
2225
+ const unifiedAccessControlConditions = await Promise.all(
2226
+ args.paymentConditions!.map(async (condition) => {
2227
+ switch (condition.type) {
2228
+ case AccessControlConditionTypes.timelockPayment:
2229
+ return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock(
2230
+ {
2231
+ key: '$.tx_responses.*.timestamp',
2232
+ comparator: '<=',
2233
+ value: `${condition.intervalInSeconds}`,
2234
+ },
2235
+ condition.feePaymentAmount,
2236
+ condition.feePaymentAddress,
2237
+ condition?.blockHeight,
2238
+ args?.dkgOptions?.chain || that.didProvider.dkgOptions.chain
2239
+ );
2240
+ default:
2241
+ throw new Error(
2242
+ `[did-provider-cheqd]: unsupported access control condition type ${condition.type}`
2243
+ );
2244
+ }
2245
+ })
2246
+ );
2247
+ // encrypt bitstring - case: threshold
2248
+ const { encryptedString: thresholdEncryptionCiphertext, stringHash } = await lit.encrypt(
2249
+ fromString(bitstring, args?.statusListEncoding || DefaultStatusListEncodings.base64url),
2250
+ unifiedAccessControlConditions
2251
+ );
2252
+ // construct encoded list
2253
+ const { encodedList, symmetricLength } = await encodeWithMetadata(
2254
+ symmetricEncryptionCiphertext,
2255
+ thresholdEncryptionCiphertext
2256
+ );
2257
+ issued.credentialSubject = {
2258
+ type: 'BitstringStatusList',
2259
+ statusPurpose: args.statusPurpose,
2260
+ encodedList,
2261
+ ttl: args?.ttl,
2262
+ };
2263
+
2264
+ // return result tuple
2265
+ return [
2266
+ {
2267
+ bitstringStatusListCredential: issued as BitstringStatusListCredential,
2268
+ metadata: {
2269
+ encrypted: true,
2270
+ encoding: args?.statusListEncoding || DefaultStatusListEncodings.base64url,
2271
+ length: args?.statusListLength || Cheqd.DefaultBitstringLength,
2272
+ statusSize: args?.statusSize,
2273
+ statusMessages: args?.statusMessages || [],
2274
+ statusListHash: stringHash,
2275
+ symmetricLength,
2276
+ paymentConditions: args.paymentConditions,
2277
+ },
2278
+ } satisfies BitstringStatusList,
2279
+ {
2280
+ symmetricEncryptionCiphertext: await blobToHexString(symmetricEncryptionCiphertext),
2281
+ thresholdEncryptionCiphertext: toString(thresholdEncryptionCiphertext, 'hex'),
2282
+ stringHash,
2283
+ symmetricKey: toString(symmetricKey, 'hex'),
2284
+ },
2285
+ ] satisfies [BitstringStatusList, EncryptionResult];
2286
+ })(this)
2287
+ : await (async function () {
2288
+ issued.credentialSubject = {
2289
+ type: 'BitstringStatusList',
2290
+ statusPurpose: args.statusPurpose,
2291
+ encodedList: bitstring,
2292
+ ttl: args?.ttl,
2293
+ };
2294
+ return [
2295
+ {
2296
+ bitstringStatusListCredential: issued as BitstringStatusListCredential,
2297
+ metadata: {
2298
+ encrypted: false,
2299
+ encoding: args?.statusListEncoding || DefaultStatusListEncodings.base64url,
2300
+ length: args?.statusListLength || Cheqd.DefaultBitstringLength,
2301
+ statusSize: args?.statusSize,
2302
+ statusMessages: args?.statusMessages || [],
2303
+ },
2304
+ } satisfies BitstringStatusList,
2305
+ undefined,
2306
+ ] satisfies [BitstringStatusList, undefined];
2307
+ })();
2308
+
2309
+ // construct payload
2310
+ const payload = {
2311
+ id: v4(),
2312
+ collectionId: args.issuerDid.split(':').reverse()[0],
2313
+ name: args.statusListName,
2314
+ resourceType: BitstringStatusListResourceType,
2315
+ version: args?.resourceVersion || new Date().toISOString(),
2316
+ alsoKnownAs: args?.alsoKnownAs || [],
2317
+ data: fromString(JSON.stringify(data[0]), 'utf-8'),
2318
+ } satisfies BitstringStatusListResourcePayload;
2319
+
2320
+ // return result
2321
+ return {
2322
+ created: await context.agent[BroadcastStatusListMethodName]({
2323
+ kms: args.kms,
2324
+ payload,
2325
+ network: network as CheqdNetwork,
2326
+ }),
2327
+ resource: data[0],
2328
+ resourceMetadata: await Cheqd.fetchStatusListMetadata({
2329
+ credentialStatus: {
2330
+ id: `${DefaultResolverUrl}${args.issuerDid}?resourceName=${args.statusListName}&resourceType=${
2331
+ BitstringStatusListResourceType
2332
+ }`,
2333
+ },
2334
+ } as VerifiableCredential),
2335
+ encrypted: args.encrypted,
2336
+ symmetricKey: args.encrypted && args.returnSymmetricKey ? data[1]?.symmetricKey : undefined,
2337
+ } satisfies CreateStatusListResult;
2338
+ }
2339
+ private async BroadcastBitstringStatusList(args: ICheqdBroadcastStatusListArgs, context: IContext) {
2340
+ if (typeof args.kms !== 'string') {
2341
+ throw new Error('[did-provider-cheqd]: kms is required');
2342
+ }
2343
+
2344
+ if (typeof args.payload !== 'object') {
2345
+ throw new Error('[did-provider-cheqd]: payload object is required');
2346
+ }
2347
+
2348
+ if (typeof args.network !== 'string') {
2349
+ throw new Error('[did-provider-cheqd]: network is required');
2350
+ }
2351
+
2352
+ if (args?.file) {
2353
+ args.payload.data = await Cheqd.getFile(args.file);
2354
+ }
2355
+
2356
+ if (typeof args?.payload?.data === 'string') {
2357
+ args.payload.data = fromString(args.payload.data, 'base64');
2358
+ }
2359
+ // Validate that data is present
2360
+ if (!args.payload.data) {
2361
+ throw new Error('[did-provider-cheqd]: payload.data is required for Bitstring Status List');
2362
+ }
2363
+
2364
+ // Validate and parse the Bitstring Status List data
2365
+ await this.validateBitstringStatusListPayload(args.payload as BitstringStatusListResourcePayload);
2366
+
2367
+ // Validate against resource type
2368
+ if (args?.payload?.resourceType !== BitstringStatusListResourceType) {
2369
+ throw new Error(`[did-provider-cheqd]: resourceType must be ${BitstringStatusListResourceType}`);
2370
+ }
2371
+
2372
+ this.providerId = Cheqd.generateProviderId(args.network);
2373
+ this.didProvider = await Cheqd.getProviderFromNetwork(args.network, this.supportedDidProviders);
2374
+
2375
+ return await this.didProvider.createResource(
2376
+ {
2377
+ options: {
2378
+ kms: args.kms,
2379
+ payload: args.payload,
2380
+ signInputs: args.signInputs,
2381
+ fee:
2382
+ args?.fee ||
2383
+ (await ResourceModule.generateCreateResourceJsonFees(
2384
+ (await this.didProvider.getWalletAccounts())[0].address
2385
+ )),
2386
+ },
2387
+ },
2388
+ context
2389
+ );
2390
+ }
2391
+ /**
2392
+ * Validate Bitstring Status List payload structure and content
2393
+ */
2394
+ private async validateBitstringStatusListPayload(payload: BitstringStatusListResourcePayload): Promise<void> {
2395
+ if (!payload.data) {
2396
+ throw new Error('[did-provider-cheqd]: payload.data is required');
2397
+ }
2398
+ let bitstringData: BitstringStatusList;
2399
+ try {
2400
+ // Parse the data as BitstringStatusList
2401
+ const dataString = typeof payload.data === 'string' ? payload.data : toString(payload.data, 'utf-8');
2402
+ bitstringData = JSON.parse(dataString) as BitstringStatusList;
2403
+ } catch (error) {
2404
+ throw new Error(
2405
+ `[did-provider-cheqd]: Invalid BitstringStatusList data format: ${(error as Error).message}`
2406
+ );
2407
+ }
2408
+ const metadata = bitstringData.metadata;
2409
+ const bitstringCredential = bitstringData.bitstringStatusListCredential;
2410
+ // Validate required properties
2411
+ if (!bitstringCredential.credentialSubject.statusPurpose) {
2412
+ throw new Error('[did-provider-cheqd]: statusPurpose is required');
2413
+ }
2414
+
2415
+ if (!bitstringCredential.credentialSubject.encodedList) {
2416
+ throw new Error('[did-provider-cheqd]: encodedList is required');
2417
+ }
2418
+
2419
+ if (!bitstringCredential.issuanceDate) {
2420
+ throw new Error('[did-provider-cheqd]: issuanceDate is required');
2421
+ }
2422
+ // Validate status purpose
2423
+ const statusPurpose = Array.isArray(bitstringCredential.credentialSubject.statusPurpose)
2424
+ ? bitstringCredential.credentialSubject.statusPurpose[0]
2425
+ : bitstringCredential.credentialSubject.statusPurpose;
2426
+ if (!Object.values(BitstringStatusPurposeTypes).includes(statusPurpose)) {
2427
+ throw new Error(
2428
+ `[did-provider-cheqd]: Invalid statusPurpose. Must be in: ${Object.values(
2429
+ BitstringStatusPurposeTypes
2430
+ ).join(', ')}`
2431
+ );
2432
+ }
2433
+ // Validate encoded list format (should be base64url encoded)
2434
+ if (!isValidEncodedBitstring(bitstringCredential.credentialSubject.encodedList)) {
2435
+ throw new Error(
2436
+ '[did-provider-cheqd]: Invalid encodedList format. Must be base64url encoded GZIP compressed bitstring'
2437
+ );
2438
+ }
2439
+ // Validate dates
2440
+ try {
2441
+ new Date(bitstringCredential.issuanceDate);
2442
+ if (bitstringCredential.expirationDate) {
2443
+ const validUntil = new Date(bitstringCredential.expirationDate);
2444
+ const validFrom = new Date(bitstringCredential.issuanceDate);
2445
+ if (validUntil <= validFrom) {
2446
+ throw new Error('[did-provider-cheqd]: expirationDate must be after issuanceDate');
2447
+ }
2448
+ }
2449
+ } catch (error) {
2450
+ throw new Error(`[did-provider-cheqd]: Invalid date format: ${(error as Error).message}`);
2451
+ }
2452
+ // Validate status size if present
2453
+ if (metadata.statusSize !== undefined) {
2454
+ if (![1, 2, 4, 8].includes(metadata.statusSize)) {
2455
+ throw new Error('[did-provider-cheqd]: statusSize must be 1, 2, 4, or 8 bits');
2456
+ }
2457
+
2458
+ // Validate status messages for multi-bit status
2459
+ if (metadata.statusSize > 1) {
2460
+ await this.validateStatusMessagesInPayload(metadata.statusMessages, metadata.statusSize);
2461
+ }
2462
+ }
2463
+
2464
+ // Validate TTL if present
2465
+ if (bitstringCredential.credentialSubject.ttl !== undefined) {
2466
+ if (
2467
+ typeof bitstringCredential.credentialSubject.ttl !== 'number' ||
2468
+ bitstringCredential.credentialSubject.ttl < 0
2469
+ ) {
2470
+ throw new Error('[did-provider-cheqd]: ttl must be a non-negative number');
2471
+ }
2472
+ }
2473
+ }
2474
+
2475
+ /**
2476
+ * Validate status messages for multi-bit status
2477
+ */
2478
+ private async validateStatusMessagesInPayload(
2479
+ statusMessages: BitstringStatusMessage[] | undefined,
2480
+ statusSize: number
2481
+ ): Promise<void> {
2482
+ if (statusSize <= 1) {
2483
+ return; // No validation needed for single-bit status
2484
+ }
2485
+
2486
+ const expectedMessageCount = Math.pow(2, statusSize);
2487
+
2488
+ if (!statusMessages || statusMessages.length === 0) {
2489
+ throw new Error(
2490
+ `[did-provider-cheqd]: statusMessages is required for ${statusSize}-bit status (expected ${expectedMessageCount} messages)`
2491
+ );
2492
+ }
2493
+
2494
+ if (statusMessages.length !== expectedMessageCount) {
2495
+ throw new Error(
2496
+ `[did-provider-cheqd]: statusMessages must have exactly ${expectedMessageCount} entries for ${statusSize}-bit status`
2497
+ );
2498
+ }
2499
+
2500
+ // Validate each status message
2501
+ const expectedStatuses = new Set<string>();
2502
+ for (let i = 0; i < expectedMessageCount; i++) {
2503
+ expectedStatuses.add(`0x${i.toString(16).toLowerCase()}`);
2504
+ }
2505
+
2506
+ const actualStatuses = new Set(statusMessages.map((msg) => msg.status));
2507
+
2508
+ for (const expected of expectedStatuses) {
2509
+ if (!actualStatuses.has(expected)) {
2510
+ throw new Error(`[did-provider-cheqd]: Missing status message for value ${expected}`);
2511
+ }
2512
+ }
2513
+
2514
+ // Validate message format
2515
+ for (const statusMsg of statusMessages) {
2516
+ if (!statusMsg.status || !statusMsg.message) {
2517
+ throw new Error(
2518
+ '[did-provider-cheqd]: Each status message must have both status and message properties'
2519
+ );
2520
+ }
2521
+
2522
+ if (typeof statusMsg.status !== 'string' || typeof statusMsg.message !== 'string') {
2523
+ throw new Error('[did-provider-cheqd]: status and message must be strings');
2524
+ }
2525
+
2526
+ if (!statusMsg.status.match(/^0x[0-9a-f]+$/i)) {
2527
+ throw new Error(
2528
+ `[did-provider-cheqd]: Invalid status format ${statusMsg.status}. Must be hex prefixed with 0x`
2529
+ );
2530
+ }
2531
+ }
2532
+ }
2533
+ private async GenerateDidDoc(args: ICheqdGenerateDidDocArgs, context: IContext): Promise<TExportedDIDDocWithKeys> {
2534
+ if (typeof args.verificationMethod !== 'string') {
2535
+ throw new Error('[did-provider-cheqd]: verificationMethod is required');
2536
+ }
2537
+
2538
+ if (typeof args.methodSpecificIdAlgo !== 'string') {
2539
+ throw new Error('[did-provider-cheqd]: methodSpecificIdAlgo is required');
2540
+ }
2541
+
2542
+ if (typeof args.network !== 'string') {
2543
+ throw new Error('[did-provider-cheqd]: network is required');
2544
+ }
2545
+
2546
+ const keyPair = createKeyPairBase64();
2547
+ const keyPairHex: IKeyPair = {
2548
+ publicKey: toString(fromString(keyPair.publicKey, 'base64'), 'hex'),
2549
+ privateKey: toString(fromString(keyPair.privateKey, 'base64'), 'hex'),
2550
+ };
2551
+ const verificationKeys = createVerificationKeys(
2552
+ keyPair.publicKey,
2553
+ args.methodSpecificIdAlgo,
2554
+ 'key-1',
2555
+ args.network
2556
+ );
2557
+ const verificationMethods = createDidVerificationMethod([args.verificationMethod], [verificationKeys]);
2558
+
2559
+ return {
2560
+ didDoc: createDidPayload(verificationMethods, [verificationKeys]),
2561
+ versionId: v4(),
2562
+ keys: [
2563
+ {
2564
+ publicKeyHex: keyPairHex.publicKey,
2565
+ privateKeyHex: keyPairHex.privateKey,
2566
+ kid: keyPairHex.publicKey,
2567
+ type: 'Ed25519',
2568
+ },
2569
+ ],
2570
+ };
2571
+ }
2572
+
2573
+ private async GenerateDidDocWithLinkedResource(
2574
+ args: any,
2575
+ context: IContext
2576
+ ): Promise<TExportedDIDDocWithLinkedResourceWithKeys> {
2577
+ if (typeof args.verificationMethod !== 'string') {
2578
+ throw new Error('[did-provider-cheqd]: verificationMethod is required');
2579
+ }
2580
+
2581
+ if (typeof args.methodSpecificIdAlgo !== 'string') {
2582
+ throw new Error('[did-provider-cheqd]: methodSpecificIdAlgo is required');
2583
+ }
2584
+
2585
+ if (typeof args.network !== 'string') {
2586
+ throw new Error('[did-provider-cheqd]: network is required');
2587
+ }
2588
+
2589
+ const keyPair = createKeyPairBase64();
2590
+ const keyPairHex: IKeyPair = {
2591
+ publicKey: toString(fromString(keyPair.publicKey, 'base64'), 'hex'),
2592
+ privateKey: toString(fromString(keyPair.privateKey, 'base64'), 'hex'),
2593
+ };
2594
+ const verificationKeys = createVerificationKeys(
2595
+ keyPair.publicKey,
1845
2596
  args.methodSpecificIdAlgo,
1846
2597
  'key-1',
1847
2598
  args.network
@@ -1905,6 +2656,187 @@ export class Cheqd implements IAgentPlugin {
1905
2656
  return encoded;
1906
2657
  }
1907
2658
  }
2659
+ private async GenerateBitstringStatusList(args: ICheqdGenerateStatusListArgs, context: IContext): Promise<string> {
2660
+ const statusSize = args?.statusSize || 1; // default to 1 bit per entry // TODO change to 2 bits per entry after StatusList2021 is removed
2661
+ const length = args?.length || Cheqd.DefaultBitstringLength; // default to 131072
2662
+ // Total number of bits = entries * bits per entry
2663
+ const totalBits = length * statusSize;
2664
+ // Ensure bitstring is byte-aligned (i.e., multiple of 8 bits)
2665
+ const alignedLength = Math.ceil(totalBits / 8) * 8;
2666
+
2667
+ const bitstring: DBBitstring = args?.buffer
2668
+ ? new DBBitstring({ buffer: args.buffer })
2669
+ : new DBBitstring({ length: alignedLength });
2670
+
2671
+ // get compressed bits
2672
+ const compressed = await bitstring.compressBits();
2673
+ switch (args?.bitstringEncoding) {
2674
+ case 'hex':
2675
+ return toString(compressed, 'hex');
2676
+ case 'base64url':
2677
+ default:
2678
+ return toString(compressed, 'base64url');
2679
+ }
2680
+ }
2681
+
2682
+ private async VerifyStatusListCredential(
2683
+ args: ICheqdVerifyStatusListCredentialArgs,
2684
+ context: IContext
2685
+ ): Promise<VerificationResult> {
2686
+ // if jwt credential, decode it
2687
+ const credentialObj =
2688
+ typeof args.credential === 'string' ? await Cheqd.decodeCredentialJWT(args.credential) : args.credential;
2689
+ // Validate required fields
2690
+ if (!credentialObj || typeof credentialObj !== 'object') {
2691
+ return {
2692
+ verified: false,
2693
+ error: { message: 'Invalid credential format' },
2694
+ };
2695
+ }
2696
+ const { credentialSubject, ...rest } = credentialObj;
2697
+ // Validate credentialSubject and encodedList
2698
+ if (!credentialSubject?.encodedList) {
2699
+ return {
2700
+ verified: false,
2701
+ error: { message: 'Missing encodedList in credentialSubject' },
2702
+ };
2703
+ }
2704
+ // Validate that this is indeed a status list credential
2705
+ if (!credentialObj.type || !credentialObj.type.includes('BitstringStatusListCredential')) {
2706
+ return {
2707
+ verified: false,
2708
+ error: { message: 'Credential is not a BitstringStatusListCredential' },
2709
+ };
2710
+ }
2711
+ // Extract encodedList and create credential without it for verification
2712
+ const { encodedList, ...restCredentialSubject } = credentialSubject || {};
2713
+ // Create formatted credential for verification without encodedList
2714
+ const formattedCredential: VerifiableCredential = {
2715
+ credentialSubject: restCredentialSubject,
2716
+ ...rest,
2717
+ };
2718
+ // verify default policies
2719
+ const verificationResult = await context.agent.verifyCredential({
2720
+ ...args?.verificationArgs,
2721
+ credential: formattedCredential,
2722
+ policies: {
2723
+ ...args?.verificationArgs?.policies,
2724
+ // Disable credentialStatus check for status list credentials to avoid circular dependency
2725
+ credentialStatus: false,
2726
+ },
2727
+ } satisfies IVerifyCredentialArgs);
2728
+ // Additional validation for BitstringStatusListCredential
2729
+ if (verificationResult.verified) {
2730
+ // Basic validation that encodedList is properly formatted
2731
+ if (typeof encodedList !== 'string' || !encodedList) {
2732
+ return {
2733
+ verified: false,
2734
+ error: { message: 'Invalid encodedList format' },
2735
+ };
2736
+ }
2737
+ // Validate encodedList format (should be base64url encoded)
2738
+ if (!isValidEncodedBitstring(encodedList)) {
2739
+ return {
2740
+ verified: false,
2741
+ error: { message: 'EncodedList validation failed' },
2742
+ };
2743
+ }
2744
+
2745
+ // Validate statusPurpose is a valid value
2746
+ const statusPurpose = Array.isArray(credentialObj.credentialSubject.statusPurpose)
2747
+ ? credentialObj.credentialSubject.statusPurpose[0]
2748
+ : credentialObj.credentialSubject.statusPurpose;
2749
+ if (!Object.values(BitstringStatusPurposeTypes).includes(statusPurpose)) {
2750
+ return {
2751
+ verified: false,
2752
+ error: { message: `Invalid statusPurpose: ${credentialObj.credentialSubject.statusPurpose}` },
2753
+ };
2754
+ }
2755
+
2756
+ // If ttl is provided, validate it's a positive number
2757
+ if (
2758
+ restCredentialSubject.ttl !== undefined &&
2759
+ (typeof restCredentialSubject.ttl !== 'number' || restCredentialSubject.ttl <= 0)
2760
+ ) {
2761
+ return {
2762
+ verified: false,
2763
+ error: { message: 'Invalid ttl value' },
2764
+ };
2765
+ }
2766
+ }
2767
+
2768
+ return { verified: verificationResult.verified, error: verificationResult.error };
2769
+ }
2770
+
2771
+ private async IssueCredentialWithBitstringStatusList(
2772
+ args: ICheqdIssueCredentialWithStatusListArgs,
2773
+ context: IContext
2774
+ ): Promise<BitstringVerifiableCredential> {
2775
+ // validate resource type
2776
+ const allowedTypes: Array<'refresh' | 'message'> = ['refresh', 'message'];
2777
+ if (!allowedTypes.includes(args.statusOptions.statusPurpose as 'refresh' | 'message')) {
2778
+ throw new Error(
2779
+ `[did-provider-cheqd]: statusPurpose while issuance must be one of ${allowedTypes.join(', ')}`
2780
+ );
2781
+ }
2782
+ // construct issuer
2783
+ const issuer = (args.issuanceOptions.credential.issuer as { id: string }).id
2784
+ ? (args.issuanceOptions.credential.issuer as { id: string }).id
2785
+ : (args.issuanceOptions.credential.issuer as string);
2786
+ // generate status list credential
2787
+ const statusListCredential = `${DefaultResolverUrl}${issuer}?resourceName=${args.statusOptions.statusListName}&resourceType=${BitstringStatusListResourceType}`;
2788
+ // get latest status list
2789
+ const statuslist = await Cheqd.fetchBitstringStatusList({
2790
+ credentialStatus: {
2791
+ id: statusListCredential,
2792
+ },
2793
+ } as VerifiableCredential);
2794
+ // Validate statusPurpose with statusList.statusPurpose
2795
+ const sl_statusPurpose = statuslist.bitstringStatusListCredential.credentialSubject.statusPurpose;
2796
+ if (!Object.values(sl_statusPurpose).includes(args.statusOptions.statusPurpose)) {
2797
+ throw new Error(
2798
+ `[did-provider-cheqd]: statusPurpose must be one of ${Object.values(sl_statusPurpose).join(', ')}`
2799
+ );
2800
+ }
2801
+ // If statusPurpose is 'message', statusMessages and statusSize MUST be present in Credential
2802
+ if (args.statusOptions.statusPurpose === BitstringStatusPurposeTypes.message) {
2803
+ if (!statuslist.metadata.statusSize || !statuslist.metadata.statusMessages) {
2804
+ throw new Error(
2805
+ '[did-provider-cheqd]: statusMessages and statusSize must be present for statusPurpose="message"'
2806
+ );
2807
+ }
2808
+ }
2809
+
2810
+ // generate index
2811
+ const statusListIndex = await generateRandomStatusListIndex(args.statusOptions, {
2812
+ statusSize: statuslist.metadata.statusSize,
2813
+ length: statuslist.metadata.length,
2814
+ });
2815
+
2816
+ // construct credential status
2817
+ const credentialStatus: BitstringStatusListEntry = {
2818
+ id: `${statusListCredential}#${statusListIndex}`,
2819
+ type: 'BitstringStatusListEntry',
2820
+ statusPurpose: args.statusOptions.statusPurpose || BitstringStatusPurposeTypes.message,
2821
+ statusListIndex: `${statusListIndex}`,
2822
+ statusListCredential,
2823
+ statusSize: statuslist.metadata.statusSize || 1,
2824
+ statusMessage: statuslist.metadata.statusMessages || [],
2825
+ };
2826
+
2827
+ // add credential status to credential
2828
+ args.issuanceOptions.credential.credentialStatus = credentialStatus;
2829
+
2830
+ // add relevant context
2831
+ args.issuanceOptions.credential['@context'] = this.addBitstringStatusListContexts(
2832
+ args.issuanceOptions.credential
2833
+ );
2834
+ // TODO: update Veramo so that default "https://www.w3.org/2018/credentials/v1" is not added in context
2835
+ // create a credential
2836
+ const credential = await context.agent.createVerifiableCredential(args.issuanceOptions);
2837
+
2838
+ return credential as BitstringVerifiableCredential;
2839
+ }
1908
2840
 
1909
2841
  private async IssueRevocableCredentialWithStatusList2021(
1910
2842
  args: ICheqdIssueRevocableCredentialWithStatusList2021Args,
@@ -1939,27 +2871,7 @@ export class Cheqd implements IAgentPlugin {
1939
2871
  args.issuanceOptions.credential.credentialStatus = credentialStatus;
1940
2872
 
1941
2873
  // add relevant context
1942
- args.issuanceOptions.credential['@context'] = (function () {
1943
- // if no context is provided, add default context
1944
- if (!args.issuanceOptions.credential['@context']) {
1945
- return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
1946
- }
1947
-
1948
- // if context is provided as an array, add default context if it is not already present
1949
- if (Array.isArray(args.issuanceOptions.credential['@context'])) {
1950
- if (args.issuanceOptions.credential['@context'].length === 0) {
1951
- return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
1952
- }
1953
-
1954
- if (!args.issuanceOptions.credential['@context'].includes(Cheqd.statusList2021Context)) {
1955
- return [...args.issuanceOptions.credential['@context'], Cheqd.statusList2021Context];
1956
- }
1957
- }
1958
-
1959
- // if context is provided as a string, add default context if it is not already present
1960
- if (typeof args.issuanceOptions.credential['@context'] === 'string')
1961
- return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
1962
- })();
2874
+ args.issuanceOptions.credential['@context'] = this.addStatusList2021Contexts(args.issuanceOptions.credential);
1963
2875
 
1964
2876
  // create a credential
1965
2877
  const credential = await context.agent.createVerifiableCredential(args.issuanceOptions);
@@ -2000,36 +2912,39 @@ export class Cheqd implements IAgentPlugin {
2000
2912
  args.issuanceOptions.credential.credentialStatus = credentialStatus;
2001
2913
 
2002
2914
  // add relevant context
2003
- args.issuanceOptions.credential['@context'] = (function () {
2004
- // if no context is provided, add default context
2005
- if (!args.issuanceOptions.credential['@context']) {
2006
- return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
2007
- }
2008
-
2009
- // if context is provided as an array, add default context if it is not already present
2010
- if (Array.isArray(args.issuanceOptions.credential['@context'])) {
2011
- if (args.issuanceOptions.credential['@context'].length === 0) {
2012
- return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
2013
- }
2014
-
2015
- if (!args.issuanceOptions.credential['@context'].includes(Cheqd.statusList2021Context)) {
2016
- return [...args.issuanceOptions.credential['@context'], Cheqd.statusList2021Context];
2017
- }
2018
- }
2019
-
2020
- // if context is provided as a string, add default context if it is not already present
2021
- if (typeof args.issuanceOptions.credential['@context'] === 'string')
2022
- return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
2023
- })();
2915
+ args.issuanceOptions.credential['@context'] = this.addStatusList2021Contexts(args.issuanceOptions.credential);
2024
2916
 
2025
2917
  // create a credential
2026
2918
  const credential = await context.agent.createVerifiableCredential(args.issuanceOptions);
2027
2919
 
2028
2920
  return credential;
2029
2921
  }
2922
+ private addStatusList2021Contexts(credential: any): string[] {
2923
+ const contexts = credential['@context'] || [];
2924
+ // if context is provided as an array, add default context if it is not already present
2925
+ if (Array.isArray(contexts)) {
2926
+ const requiredContexts = [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
2927
+ const missingContexts = requiredContexts.filter((ctx) => !contexts.includes(ctx));
2928
+ return [...contexts, ...missingContexts];
2929
+ }
2930
+ // if no context return default context
2931
+ return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
2932
+ }
2933
+ private addBitstringStatusListContexts(credential: any): string[] {
2934
+ const contexts = credential['@context'] || [];
2935
+ // if context is provided as an array, add default context if it is not already present
2936
+ if (Array.isArray(contexts)) {
2937
+ // TODO: Credential V1 context is used now, replace when V2 is implemented
2938
+ const requiredContexts = [Cheqd.defaultContextV1, Cheqd.DefaultBitstringContexts.statusList];
2939
+ const missingContexts = requiredContexts.filter((ctx) => !contexts.includes(ctx));
2940
+ return [...contexts, ...missingContexts];
2941
+ }
2942
+ // if no context return default context
2943
+ return [Cheqd.DefaultBitstringContexts.v2, Cheqd.DefaultBitstringContexts.statusList];
2944
+ }
2030
2945
 
2031
2946
  private async VerifyCredentialWithStatusList2021(
2032
- args: ICheqdVerifyCredentialWithStatusList2021Args,
2947
+ args: ICheqdVerifyCredentialWithStatusListArgs,
2033
2948
  context: IContext
2034
2949
  ): Promise<VerificationResult> {
2035
2950
  // verify default policies
@@ -2041,7 +2956,6 @@ export class Cheqd implements IAgentPlugin {
2041
2956
  credentialStatus: false,
2042
2957
  },
2043
2958
  } satisfies IVerifyCredentialArgs);
2044
-
2045
2959
  // early return if verification failed
2046
2960
  if (!verificationResult.verified) {
2047
2961
  return { verified: false, error: verificationResult.error };
@@ -2058,33 +2972,345 @@ export class Cheqd implements IAgentPlugin {
2058
2972
  // define provider, if applicable
2059
2973
  this.didProvider = await Cheqd.getProviderFromDidUrl(issuer, this.supportedDidProviders);
2060
2974
 
2061
- // define provider id, if applicable
2062
- this.providerId = Cheqd.generateProviderId(issuer);
2975
+ // define provider id, if applicable
2976
+ this.providerId = Cheqd.generateProviderId(issuer);
2977
+
2978
+ // define dkg options, if provided
2979
+ args.dkgOptions ||= this.didProvider.dkgOptions;
2980
+
2981
+ // verify credential status
2982
+ switch (credential.credentialStatus?.statusPurpose) {
2983
+ case DefaultStatusList2021StatusPurposeTypes.revocation:
2984
+ return {
2985
+ ...verificationResult,
2986
+ revoked: await Cheqd.checkRevoked(credential, { ...args.options, topArgs: args }),
2987
+ };
2988
+ case DefaultStatusList2021StatusPurposeTypes.suspension:
2989
+ return {
2990
+ ...verificationResult,
2991
+ suspended: await Cheqd.checkSuspended(credential, { ...args.options, topArgs: args }),
2992
+ };
2993
+ default:
2994
+ throw new Error(
2995
+ `[did-provider-cheqd]: verify credential: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`
2996
+ );
2997
+ }
2998
+ }
2999
+ private async VerifyCredentialWithBitstringStatusList(
3000
+ args: ICheqdVerifyCredentialWithBitstringArgs,
3001
+ context: IContext
3002
+ ): Promise<BitstringVerificationResult> {
3003
+ // verify default policies
3004
+ const verificationResult = await context.agent.verifyCredential({
3005
+ ...args?.verificationArgs,
3006
+ credential: args.credential,
3007
+ policies: {
3008
+ ...args?.verificationArgs?.policies,
3009
+ credentialStatus: false,
3010
+ },
3011
+ } satisfies IVerifyCredentialArgs);
3012
+ // if jwt credential, decode it
3013
+ const credential =
3014
+ typeof args.credential === 'string' ? await Cheqd.decodeCredentialJWT(args.credential) : args.credential;
3015
+ // early return if verification failed
3016
+ if (!verificationResult.verified) {
3017
+ return {
3018
+ verified: false,
3019
+ status: 1,
3020
+ purpose: credential.credentialStatus?.statusPurpose,
3021
+ valid: false,
3022
+ error: verificationResult.error,
3023
+ };
3024
+ }
3025
+
3026
+ // define issuer
3027
+ const issuer =
3028
+ typeof credential.issuer === 'string' ? credential.issuer : (credential.issuer as { id: string }).id;
3029
+
3030
+ // define provider, if applicable
3031
+ this.didProvider = await Cheqd.getProviderFromDidUrl(issuer, this.supportedDidProviders);
3032
+
3033
+ // define provider id, if applicable
3034
+ this.providerId = Cheqd.generateProviderId(issuer);
3035
+
3036
+ // define dkg options, if provided
3037
+ args.dkgOptions ||= this.didProvider.dkgOptions;
3038
+
3039
+ // Fetch and verify the Bitstring status list VC
3040
+ let publishedList: BitstringStatusList;
3041
+ try {
3042
+ publishedList = await Cheqd.fetchBitstringStatusList({
3043
+ credentialStatus: {
3044
+ id: credential.credentialStatus?.statusListCredential,
3045
+ },
3046
+ } as VerifiableCredential);
3047
+ } catch {
3048
+ throw new Error('[did-provider-cheqd]: STATUS_RETRIEVAL_ERROR');
3049
+ }
3050
+ // Validate proof on the Bitstring status list VC
3051
+ const checkCredential = await this.VerifyStatusListCredential(
3052
+ { credential: publishedList.bitstringStatusListCredential },
3053
+ context
3054
+ );
3055
+ if (!checkCredential.verified) {
3056
+ throw new Error('[did-provider-cheqd]: STATUS_VERIFICATION_ERROR');
3057
+ }
3058
+ const validationResult = await Cheqd.validateBitstringStatus(
3059
+ credential as BitstringVerifiableCredential,
3060
+ publishedList,
3061
+ {
3062
+ ...args.options,
3063
+ topArgs: args,
3064
+ instantiateDkgClient: () => this.didProvider.instantiateDkgThresholdProtocolClient(),
3065
+ }
3066
+ );
3067
+
3068
+ // verify credential status
3069
+ switch (credential.credentialStatus?.statusPurpose) {
3070
+ case BitstringStatusPurposeTypes.revocation:
3071
+ return {
3072
+ ...verificationResult,
3073
+ revoked: !validationResult.valid,
3074
+ ...validationResult,
3075
+ };
3076
+ case BitstringStatusPurposeTypes.suspension:
3077
+ return {
3078
+ ...verificationResult,
3079
+ suspended: !validationResult.valid,
3080
+ ...validationResult,
3081
+ };
3082
+ case BitstringStatusPurposeTypes.message:
3083
+ case BitstringStatusPurposeTypes.refresh:
3084
+ return { ...verificationResult, ...validationResult };
3085
+ default:
3086
+ throw new Error(
3087
+ `[did-provider-cheqd]: verify credential: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`
3088
+ );
3089
+ }
3090
+ }
3091
+
3092
+ static async validateBitstringStatus(
3093
+ vcToValidate: BitstringVerifiableCredential,
3094
+ publishedList: BitstringStatusList,
3095
+ options: ICheqdStatusListOptions = { fetchList: true }
3096
+ ): Promise<BitstringValidationResult> {
3097
+ if (!vcToValidate?.credentialStatus) {
3098
+ throw new Error('[did-provider-cheqd]: CREDENTIAL_STATUS_MISSING');
3099
+ }
3100
+
3101
+ // validate dkgOptions
3102
+ if (!options?.topArgs?.dkgOptions) {
3103
+ throw new Error('[did-provider-cheqd]: dkgOptions is required');
3104
+ }
3105
+
3106
+ const statusEntry = vcToValidate.credentialStatus;
3107
+ const {
3108
+ statusPurpose,
3109
+ statusListIndex,
3110
+ statusSize = 1, // default to 1 if not given
3111
+ } = statusEntry;
3112
+
3113
+ // Validate statusPurpose match in Bitstring statuslist VC
3114
+ const listSubject = publishedList?.bitstringStatusListCredential.credentialSubject;
3115
+ const purposesDeclared = Array.isArray(listSubject?.statusPurpose)
3116
+ ? listSubject.statusPurpose
3117
+ : [listSubject?.statusPurpose];
3118
+ if (!purposesDeclared.includes(statusPurpose)) {
3119
+ throw new Error(
3120
+ "[did-provider-cheqd]: STATUS_VERIFICATION_ERROR 'statusPurpose' does not match Bitstring Status List 'statusPurpose'"
3121
+ );
3122
+ }
3123
+
3124
+ // Extract and decompress the bitstring
3125
+ const encoded = listSubject?.encodedList;
3126
+ if (!encoded) {
3127
+ throw new Error('[did-provider-cheqd]: STATUS_LIST_MISSING_ENCODED');
3128
+ }
3129
+ // validate encoded list
3130
+ if (!isValidEncodedBitstring(encoded))
3131
+ throw new Error(
3132
+ '[did-provider-cheqd]: Invalid encodedList format. Must be base64url encoded GZIP compressed bitstring'
3133
+ );
3134
+
3135
+ // fetch bitstring status list inscribed in credential
3136
+ const bitstringStatusList: string = await Cheqd.fetchAndDecryptBitstring(publishedList, options);
3137
+
3138
+ // Expand bitstring and validate size
3139
+ const decompressedBuffer = await DBBitstring.decodeBits({ encoded: bitstringStatusList });
3140
+ const decompressedBitstring = new DBBitstring({ buffer: decompressedBuffer });
3141
+ const totalBits = decompressedBitstring.length;
3142
+ const numEntries = Math.floor(totalBits / statusSize);
3143
+
3144
+ if (numEntries < Cheqd.DefaultBitstringLength) {
3145
+ throw new Error('[did-provider-cheqd]: STATUS_LIST_LENGTH_ERROR');
3146
+ }
3147
+
3148
+ // Compute index
3149
+ const index = parseInt(statusListIndex, 10);
3150
+ const bitPosition = index * statusSize;
3151
+
3152
+ if (bitPosition + statusSize > totalBits) {
3153
+ throw new Error('[did-provider-cheqd]: RANGE_ERROR');
3154
+ }
3155
+
3156
+ const value = Cheqd.getBitValue(decompressedBitstring, bitPosition, statusSize);
3157
+
3158
+ const result: BitstringValidationResult = {
3159
+ status: value,
3160
+ purpose: statusPurpose,
3161
+ valid: value === 0,
3162
+ };
3163
+
3164
+ // Lookup statusMessage. if statusSize > 1
3165
+ const statusMessages = statusEntry.statusMessage;
3166
+ if (statusPurpose === BitstringStatusPurposeTypes.message && Array.isArray(statusMessages)) {
3167
+ const messageEntry = statusMessages.find((msg: any) => msg.status === `0x${value.toString(16)}`);
3168
+ if (messageEntry) {
3169
+ result.message = messageEntry.message;
3170
+ }
3171
+ }
3172
+ return result;
3173
+ }
3174
+ private async VerifyPresentationWithBitstringStatusList(
3175
+ args: ICheqdVerifyPresentationWithStatusListArgs,
3176
+ context: IContext
3177
+ ): Promise<BitstringVerificationResult> {
3178
+ // Verify default presentation policies first
3179
+ const verificationResult = await context.agent.verifyPresentation({
3180
+ ...args?.verificationArgs,
3181
+ presentation: args.presentation,
3182
+ policies: {
3183
+ ...args?.verificationArgs?.policies,
3184
+ audience: false,
3185
+ credentialStatus: false, // We'll handle status verification separately
3186
+ },
3187
+ } satisfies IVerifyPresentationArgs);
3188
+ // Early return if basic presentation verification failed
3189
+ if (!verificationResult.verified) {
3190
+ return {
3191
+ verified: false,
3192
+ status: 1,
3193
+ purpose: 'unknown',
3194
+ valid: false,
3195
+ error: verificationResult.error,
3196
+ };
3197
+ }
3198
+ // Early return if no verifiable credentials are provided
3199
+ if (!args.presentation.verifiableCredential || !Array.isArray(args.presentation.verifiableCredential)) {
3200
+ throw new Error(
3201
+ '[did-provider-cheqd]: verify presentation: presentation.verifiableCredential is required and must be an array'
3202
+ );
3203
+ }
3204
+ if (args.presentation.verifiableCredential.length === 0) {
3205
+ throw new Error(
3206
+ '[did-provider-cheqd]: verify presentation: presentation must contain at least one verifiable credential'
3207
+ );
3208
+ }
3209
+
3210
+ // Verify each credential's status
3211
+ const credentialResults: BitstringVerificationResult[] = [];
3212
+ let overallValid = true;
3213
+ let hasRevoked = false;
3214
+ let hasSuspended = false;
2063
3215
 
2064
- // define dkg options, if provided
2065
- args.dkgOptions ||= this.didProvider.dkgOptions;
3216
+ for (let credential of args.presentation.verifiableCredential) {
3217
+ // If JWT credential, decode it
3218
+ if (typeof credential === 'string') {
3219
+ credential = await Cheqd.decodeCredentialJWT(credential);
3220
+ }
2066
3221
 
2067
- // verify credential status
2068
- switch (credential.credentialStatus?.statusPurpose) {
2069
- case DefaultStatusList2021StatusPurposeTypes.revocation:
2070
- return {
2071
- ...verificationResult,
2072
- revoked: await Cheqd.checkRevoked(credential, { ...args.options, topArgs: args }),
2073
- };
2074
- case DefaultStatusList2021StatusPurposeTypes.suspension:
2075
- return {
2076
- ...verificationResult,
2077
- suspended: await Cheqd.checkSuspended(credential, { ...args.options, topArgs: args }),
2078
- };
2079
- default:
2080
- throw new Error(
2081
- `[did-provider-cheqd]: verify credential: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`
3222
+ // Skip credentials without status (they're considered valid)
3223
+ if (!credential.credentialStatus || credential.credentialStatus.type !== 'BitstringStatusListEntry') {
3224
+ credentialResults.push({
3225
+ verified: true,
3226
+ status: 0,
3227
+ purpose: 'none',
3228
+ valid: true,
3229
+ });
3230
+ continue;
3231
+ }
3232
+ try {
3233
+ // Define issuer for provider selection
3234
+ const issuer =
3235
+ typeof credential.issuer === 'string'
3236
+ ? credential.issuer
3237
+ : (credential.issuer as { id: string }).id;
3238
+ // Define provider, if applicable
3239
+ this.didProvider = await Cheqd.getProviderFromDidUrl(issuer, this.supportedDidProviders);
3240
+ this.providerId = Cheqd.generateProviderId(issuer);
3241
+ args.dkgOptions ||= this.didProvider.dkgOptions;
3242
+ // Verify credential with Bitstring status list
3243
+ const credentialVerificationResult = await this.VerifyCredentialWithBitstringStatusList(
3244
+ {
3245
+ credential: credential as BitstringVerifiableCredential,
3246
+ verificationArgs: {
3247
+ ...args?.verificationArgs,
3248
+ policies: {
3249
+ ...args?.verificationArgs?.policies,
3250
+ credentialStatus: false, // We handle this manually
3251
+ },
3252
+ credential: '',
3253
+ },
3254
+ fetchList: args?.fetchList ?? true,
3255
+ dkgOptions: args.dkgOptions,
3256
+ options: args.options,
3257
+ },
3258
+ context
2082
3259
  );
3260
+ credentialResults.push(credentialVerificationResult);
3261
+
3262
+ // Track overall status
3263
+ if (!credentialVerificationResult.verified || !credentialVerificationResult.valid) {
3264
+ overallValid = false;
3265
+ }
3266
+ switch (credentialVerificationResult.status) {
3267
+ case BitstringStatusValue.REVOKED:
3268
+ hasRevoked = true;
3269
+ overallValid = false;
3270
+ break;
3271
+ case BitstringStatusValue.SUSPENDED:
3272
+ hasSuspended = true;
3273
+ overallValid = false;
3274
+ break;
3275
+ default:
3276
+ hasSuspended = false;
3277
+ hasRevoked = false;
3278
+ overallValid = true;
3279
+ }
3280
+ } catch (error) {
3281
+ credentialResults.push({
3282
+ verified: false,
3283
+ status: 1,
3284
+ purpose: credential.credentialStatus?.statusPurpose || 'unknown',
3285
+ valid: false,
3286
+ error: error as IError,
3287
+ });
3288
+ overallValid = false;
3289
+ }
2083
3290
  }
2084
- }
2085
3291
 
3292
+ // Determine overall verification result
3293
+ const allCredentialsVerified = credentialResults.every((result) => result.verified);
3294
+ const overallVerified = verificationResult.verified && allCredentialsVerified;
3295
+
3296
+ // Find the most significant status issue for reporting
3297
+ const firstFailedResult = credentialResults.find((result) => !result.verified || !result.valid);
3298
+ const resultStatus = firstFailedResult?.status ?? 0;
3299
+ const resultPurpose = firstFailedResult?.purpose ?? credentialResults[0]?.purpose ?? 'unknown';
3300
+
3301
+ return {
3302
+ verified: overallVerified,
3303
+ status: resultStatus,
3304
+ purpose: resultPurpose,
3305
+ valid: overallValid,
3306
+ revoked: hasRevoked,
3307
+ suspended: hasSuspended,
3308
+ message: firstFailedResult?.message,
3309
+ error: firstFailedResult?.error,
3310
+ };
3311
+ }
2086
3312
  private async VerifyPresentationWithStatusList2021(
2087
- args: ICheqdVerifyPresentationWithStatusList2021Args,
3313
+ args: ICheqdVerifyPresentationWithStatusListArgs,
2088
3314
  context: IContext
2089
3315
  ): Promise<VerificationResult> {
2090
3316
  // verify default policies
@@ -2146,7 +3372,7 @@ export class Cheqd implements IAgentPlugin {
2146
3372
  }
2147
3373
 
2148
3374
  private async CheckCredentialStatusWithStatusList2021(
2149
- args: ICheqdCheckCredentialStatusWithStatusList2021Args,
3375
+ args: ICheqdCheckCredentialStatusWithStatusListArgs,
2150
3376
  context: IContext
2151
3377
  ): Promise<StatusCheckResult> {
2152
3378
  // verify credential, if provided and status options are not
@@ -2171,77 +3397,553 @@ export class Cheqd implements IAgentPlugin {
2171
3397
  if (!args.statusOptions.issuerDid)
2172
3398
  throw new Error('[did-provider-cheqd]: check status: statusOptions.issuerDid is required');
2173
3399
 
2174
- // validate status options - case: statusOptions.statusListName
2175
- if (!args.statusOptions.statusListName)
2176
- throw new Error('[did-provider-cheqd]: check status: statusOptions.statusListName is required');
3400
+ // validate status options - case: statusOptions.statusListName
3401
+ if (!args.statusOptions.statusListName)
3402
+ throw new Error('[did-provider-cheqd]: check status: statusOptions.statusListName is required');
3403
+
3404
+ // validate status options - case: statusOptions.statusListIndex
3405
+ if (!args.statusOptions.statusPurpose)
3406
+ throw new Error('[did-provider-cheqd]: check status: statusOptions.statusListIndex is required');
3407
+
3408
+ // validate status options - case: statusOptions.statusListIndex
3409
+ if (!args.statusOptions.statusListIndex)
3410
+ throw new Error('[did-provider-cheqd]: check status: statusOptions.statusListIndex is required');
3411
+
3412
+ // generate resource type
3413
+ const resourceType =
3414
+ args.statusOptions.statusPurpose === DefaultStatusList2021StatusPurposeTypes.revocation
3415
+ ? DefaultStatusList2021ResourceTypes.revocation
3416
+ : DefaultStatusList2021ResourceTypes.suspension;
3417
+
3418
+ // construct status list credential
3419
+ const statusListCredential = `${DefaultResolverUrl}${args.statusOptions.issuerDid}?resourceName=${args.statusOptions.statusListName}&resourceType=${resourceType}`;
3420
+
3421
+ // construct credential status
3422
+ args.credential = {
3423
+ '@context': [],
3424
+ issuer: args.statusOptions.issuerDid,
3425
+ credentialSubject: {},
3426
+ credentialStatus: {
3427
+ id: `${statusListCredential}#${args.statusOptions.statusListIndex}`,
3428
+ type: 'StatusList2021Entry',
3429
+ statusPurpose: `${args.statusOptions.statusPurpose}`,
3430
+ statusListIndex: `${args.statusOptions.statusListIndex}`,
3431
+ },
3432
+ issuanceDate: '',
3433
+ proof: {},
3434
+ };
3435
+ }
3436
+
3437
+ // validate args - case: credential
3438
+ if (!args.credential) throw new Error('[did-provider-cheqd]: revocation: credential is required');
3439
+
3440
+ // if jwt credential, decode it
3441
+ const credential =
3442
+ typeof args.credential === 'string' ? await Cheqd.decodeCredentialJWT(args.credential) : args.credential;
3443
+
3444
+ // define issuer
3445
+ const issuer =
3446
+ typeof credential.issuer === 'string' ? credential.issuer : (credential.issuer as { id: string }).id;
3447
+
3448
+ // define provider, if applicable
3449
+ this.didProvider = await Cheqd.getProviderFromDidUrl(issuer, this.supportedDidProviders);
3450
+
3451
+ // define provider id, if applicable
3452
+ this.providerId = Cheqd.generateProviderId(issuer);
3453
+
3454
+ // define dkg options, if provided
3455
+ args.dkgOptions ||= this.didProvider.dkgOptions;
3456
+
3457
+ switch (credential.credentialStatus?.statusPurpose) {
3458
+ case DefaultStatusList2021StatusPurposeTypes.revocation:
3459
+ return { revoked: await Cheqd.checkRevoked(credential, { ...args.options, topArgs: args }) };
3460
+ case DefaultStatusList2021StatusPurposeTypes.suspension:
3461
+ return { suspended: await Cheqd.checkSuspended(credential, { ...args.options, topArgs: args }) };
3462
+ default:
3463
+ throw new Error(
3464
+ `[did-provider-cheqd]: check status: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`
3465
+ );
3466
+ }
3467
+ }
3468
+ private async UpdateCredentialWithStatusList(
3469
+ args: ICheqdUpdateCredentialWithStatusListArgs,
3470
+ context: IContext
3471
+ ): Promise<BitstringUpdateResult> {
3472
+ // Verify credential if provided and update options are not
3473
+ if (args?.credential && !args?.updateOptions) {
3474
+ const verificationResult = await context.agent.verifyCredential({
3475
+ ...args?.verificationOptions,
3476
+ credential: args.credential,
3477
+ policies: {
3478
+ credentialStatus: false,
3479
+ },
3480
+ } satisfies IVerifyCredentialArgs);
3481
+
3482
+ if (!verificationResult.verified) {
3483
+ return {
3484
+ updated: false,
3485
+ statusValue: BitstringStatusValue.UNKNOWN,
3486
+ statusMessage: 'unknown',
3487
+ error: verificationResult.error,
3488
+ };
3489
+ }
3490
+ }
3491
+ if (typeof args.newStatus !== 'number' || args.newStatus < 0 || args.newStatus > 3)
3492
+ throw new Error(
3493
+ '[did-provider-cheqd]: updateOptions.newStatus must be 0-3 (valid/revoked/suspended/unknown)'
3494
+ );
3495
+ // if update options are provided, give precedence
3496
+ if (args?.updateOptions) {
3497
+ // Validate update options
3498
+ if (!args.updateOptions.issuerDid)
3499
+ throw new Error('[did-provider-cheqd]: updateOptions.issuerDid is required');
3500
+ if (!args.updateOptions.statusListName)
3501
+ throw new Error('[did-provider-cheqd]: updateOptions.statusListName is required');
3502
+ if (typeof args.updateOptions.statusListIndex !== 'number')
3503
+ throw new Error('[did-provider-cheqd]: updateOptions.statusListIndex is required');
3504
+
3505
+ // Construct status list credential URL
3506
+ const statusListCredential = `${DefaultResolverUrl}${args.updateOptions.issuerDid}?resourceName=${args.updateOptions.statusListName}&resourceType=${BitstringStatusListResourceType}`;
3507
+
3508
+ // fetch latest status list
3509
+ const statusList = await Cheqd.fetchBitstringStatusList({
3510
+ credentialStatus: {
3511
+ id: statusListCredential,
3512
+ },
3513
+ } as VerifiableCredential);
3514
+
3515
+ // For multi-purpose status lists, we need to determine the appropriate statusPurpose
3516
+ // based on the credential's current status entry or the new status being set
3517
+ const statusPurpose = this.getStatusPurposeForMultiPurposeList(args.newStatus);
3518
+ // Override the credential with new status information
3519
+ args.credential = {
3520
+ '@context': [],
3521
+ issuer: args.updateOptions.issuerDid,
3522
+ credentialSubject: {},
3523
+ credentialStatus: {
3524
+ id: `${statusListCredential}#${args.updateOptions.statusListIndex}`,
3525
+ type: 'BitstringStatusListEntry',
3526
+ statusPurpose: statusPurpose,
3527
+ statusListIndex: `${args.updateOptions.statusListIndex}`,
3528
+ statusListCredential,
3529
+ statusSize: statusList.metadata.statusSize || 1,
3530
+ statusMessage: statusList.metadata.statusMessages || [],
3531
+ },
3532
+ issuanceDate: '',
3533
+ proof: {},
3534
+ };
3535
+ }
3536
+ // if jwt credential, decode it
3537
+ const credential =
3538
+ typeof args.credential === 'string' ? await Cheqd.decodeCredentialJWT(args.credential) : args.credential;
3539
+ // Validate that credential MUST have credentialStatus
3540
+ if (!credential?.credentialStatus) {
3541
+ throw new Error('[did-provider-cheqd]: update: credential must have credentialStatus');
3542
+ }
3543
+ // Validate that credentialStatus is BitstringStatusListEntry
3544
+ if (credential.credentialStatus.type !== 'BitstringStatusListEntry') {
3545
+ throw new Error(
3546
+ '[did-provider-cheqd]: update: credential must have BitstringStatusListEntry credentialStatus'
3547
+ );
3548
+ }
3549
+
3550
+ // validate args in pairs - case: statusListFile and statusList
3551
+ if (args.options?.statusListFile && args.options?.statusList) {
3552
+ throw new Error('[did-provider-cheqd]: revocation: statusListFile and statusList are mutually exclusive');
3553
+ }
3554
+
3555
+ // validate args in pairs - case: statusListFile and fetchList
3556
+ if (args.options?.statusListFile && args.options?.fetchList) {
3557
+ throw new Error('[did-provider-cheqd]: revocation: statusListFile and fetchList are mutually exclusive');
3558
+ }
3559
+
3560
+ // validate args in pairs - case: statusList and fetchList
3561
+ if (args.options?.statusList && args.options?.fetchList) {
3562
+ throw new Error('[did-provider-cheqd]: revocation: statusList and fetchList are mutually exclusive');
3563
+ }
3564
+
3565
+ // validate args in pairs - case: publish
3566
+ if (args.options?.publish && !args.fetchList && !(args.options?.statusListFile || args.options?.statusList)) {
3567
+ throw new Error(
3568
+ '[did-provider-cheqd]: revocation: publish requires statusListFile or statusList, if fetchList is disabled'
3569
+ );
3570
+ }
3571
+
3572
+ // Define issuer and provider
3573
+ const issuer =
3574
+ typeof credential.issuer === 'string' ? credential.issuer : (credential.issuer as { id: string }).id;
3575
+
3576
+ this.didProvider = await Cheqd.getProviderFromDidUrl(issuer, this.supportedDidProviders);
3577
+ this.providerId = Cheqd.generateProviderId(issuer);
3578
+ args.dkgOptions ||= this.didProvider.dkgOptions;
3579
+
3580
+ // Perform the status update
3581
+ return await Cheqd.updateBitstringCredentialStatus(credential, {
3582
+ ...args.options,
3583
+ topArgs: args,
3584
+ publishOptions: {
3585
+ context,
3586
+ statusListEncoding: args?.options?.statusListEncoding,
3587
+ statusListValidUntil: args?.options?.statusListValidUntil,
3588
+ resourceId: args?.options?.resourceId,
3589
+ resourceVersion: args?.options?.resourceVersion,
3590
+ resourceAlsoKnownAs: args?.options?.alsoKnownAs,
3591
+ signInputs: args?.options?.signInputs,
3592
+ fee: args?.options?.fee,
3593
+ },
3594
+ });
3595
+ }
3596
+ private getStatusPurposeForMultiPurposeList(newStatus: BitstringStatusValue): BitstringStatusListPurposeType {
3597
+ // TODO Add map with messages
3598
+ // Since the default status list supports multiple purposes, we can use any of them
3599
+ // For multi-purpose lists, typically 'message' is used as it's the most flexible
3600
+ return BitstringStatusPurposeTypes.message;
3601
+ }
3602
+ // Core status update logic for multi-purpose Bitstring Status Lists
3603
+ static async updateBitstringCredentialStatus(
3604
+ credential: VerifiableCredential,
3605
+ options?: ICheqdStatusListOptions
3606
+ ): Promise<BitstringUpdateResult> {
3607
+ try {
3608
+ // Validate credential status
3609
+ if (!credential.credentialStatus) {
3610
+ throw new Error('[did-provider-cheqd]: update: Credential status is not present');
3611
+ }
3612
+
3613
+ // Fetch published status list
3614
+ const publishedList = await Cheqd.fetchBitstringStatusList(credential);
3615
+
3616
+ // Validate that this is a multi-purpose status list with 2-bit status
3617
+ if (publishedList.metadata.statusSize !== 2) {
3618
+ throw new Error('[did-provider-cheqd]: update: Status list must use 2-bit status size');
3619
+ }
3620
+ // Validate status messages are present for 2-bit status
3621
+ if (!publishedList.metadata.statusMessages || publishedList.metadata.statusMessages.length !== 4) {
3622
+ throw new Error(
3623
+ '[did-provider-cheqd]: update: Status list must have 4 status messages for 2-bit status'
3624
+ );
3625
+ }
3626
+
3627
+ // Early return if encrypted and no decryption key provided
3628
+ if (publishedList.metadata.encrypted && !options?.topArgs?.symmetricKey) {
3629
+ throw new Error('[did-provider-cheqd]: update: symmetricKey is required for encrypted status list');
3630
+ }
3631
+ // Calculate positions and values
3632
+ const statusIndex = parseInt(credential.credentialStatus.statusListIndex, 10);
3633
+ const statusSize = publishedList.metadata.statusSize; // Should be 2
3634
+ const newStatusValue = options?.topArgs.newStatus;
3635
+
3636
+ // Fetch and decrypt the current bitstring
3637
+ const currentBitstring = await Cheqd.fetchAndDecryptBitstring(publishedList, options);
3638
+ // Parse the bitstring
3639
+ const decompressedBuffer = await DBBitstring.decodeBits({ encoded: currentBitstring });
3640
+ const bitstring = new DBBitstring({ buffer: decompressedBuffer });
3641
+
3642
+ // Get current status value
3643
+ const bitPosition = statusIndex * statusSize;
3644
+ const currentStatusValue = Cheqd.getBitValue(bitstring, bitPosition, statusSize);
3645
+
3646
+ // Check if update is needed
3647
+ if (currentStatusValue === newStatusValue) {
3648
+ const statusMessage =
3649
+ publishedList.metadata.statusMessages.find((msg) => parseInt(msg.status, 16) === currentStatusValue)
3650
+ ?.message || 'unknown';
3651
+
3652
+ return {
3653
+ updated: false,
3654
+ statusValue: currentStatusValue as BitstringStatusValue,
3655
+ statusMessage,
3656
+ error: { message: `Credential already has status value ${newStatusValue} (${statusMessage})` },
3657
+ };
3658
+ }
3659
+
3660
+ // Update the bitstring
3661
+ Cheqd.setBitValue(bitstring, bitPosition, newStatusValue, statusSize);
3662
+
3663
+ // Compress the updated bitstring
3664
+ const compressedBitstring = await bitstring.compressBits();
3665
+ const encodedBitstring = toString(compressedBitstring, 'base64url');
3666
+
3667
+ // Create updated status list credential
3668
+ const updatedStatusListCredential = {
3669
+ ...publishedList.bitstringStatusListCredential,
3670
+ credentialSubject: {
3671
+ ...publishedList.bitstringStatusListCredential.credentialSubject,
3672
+ encodedList: encodedBitstring,
3673
+ },
3674
+ };
3675
+
3676
+ const updatedStatusList: BitstringStatusList = {
3677
+ bitstringStatusListCredential: updatedStatusListCredential,
3678
+ metadata: publishedList.metadata,
3679
+ };
3680
+
3681
+ // Write to file if requested
3682
+ if (options?.topArgs?.writeToFile) {
3683
+ await Cheqd.writeFile(compressedBitstring, options?.statusListFile);
3684
+ }
3685
+
3686
+ // Publish if requested
3687
+ const published = options?.topArgs?.publish
3688
+ ? await Cheqd.publishUpdatedBitstringStatusList(updatedStatusList, credential, options)
3689
+ : undefined;
3690
+
3691
+ // Get status message for new value
3692
+ const newStatusMessage =
3693
+ publishedList.metadata.statusMessages.find((msg) => parseInt(msg.status, 16) === newStatusValue)
3694
+ ?.message || 'unknown';
3695
+
3696
+ const previousStatusMessage =
3697
+ publishedList.metadata.statusMessages.find((msg) => parseInt(msg.status, 16) === currentStatusValue)
3698
+ ?.message || 'unknown';
3699
+
3700
+ return {
3701
+ updated: true,
3702
+ statusValue: newStatusValue as BitstringStatusValue,
3703
+ previousStatusValue: currentStatusValue as BitstringStatusValue,
3704
+ statusMessage: newStatusMessage,
3705
+ published: options?.topArgs?.publish ? !!published : undefined,
3706
+ statusList: options?.topArgs?.returnUpdatedStatusList ? updatedStatusList : undefined,
3707
+ symmetricKey:
3708
+ options?.topArgs?.returnSymmetricKey && published?.symmetricKey
3709
+ ? published.symmetricKey
3710
+ : undefined,
3711
+ resourceMetadata: options?.topArgs?.returnStatusListMetadata
3712
+ ? await Cheqd.fetchStatusListMetadata(credential)
3713
+ : undefined,
3714
+ };
3715
+ } catch (error) {
3716
+ console.error('[did-provider-cheqd]: update error:', error);
3717
+ return {
3718
+ updated: false,
3719
+ statusValue: BitstringStatusValue.UNKNOWN,
3720
+ statusMessage: 'unknown',
3721
+ error: error as IError,
3722
+ };
3723
+ }
3724
+ }
3725
+
3726
+ // Helper function to fetch and decrypt bitstring (same as before)
3727
+ static async fetchAndDecryptBitstring(
3728
+ publishedList: BitstringStatusList,
3729
+ options?: ICheqdStatusListOptions
3730
+ ): Promise<string> {
3731
+ const topArgs = options?.topArgs as ICheqdUpdateCredentialWithStatusListArgs;
3732
+ const encoded = publishedList.bitstringStatusListCredential.credentialSubject.encodedList;
3733
+ if (topArgs?.fetchList) {
3734
+ // if not encrypted, return published bitstring (always base64url encoded)
3735
+ if (!publishedList.metadata.encrypted) {
3736
+ return encoded;
3737
+ }
3738
+
3739
+ // otherwise, Decrypt using threshold encryption
3740
+ const { thresholdEncryptionCiphertext } = decodeWithMetadata(
3741
+ publishedList.bitstringStatusListCredential.credentialSubject.encodedList,
3742
+ publishedList.metadata.symmetricLength!
3743
+ );
3744
+
3745
+ const lit = (await options!.instantiateDkgClient()) as LitProtocol;
3746
+ // construct access control conditions
3747
+ const unifiedAccessControlConditions = await Promise.all(
3748
+ publishedList.metadata.paymentConditions!.map(async (condition) => {
3749
+ switch (condition.type) {
3750
+ case AccessControlConditionTypes.timelockPayment:
3751
+ return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock(
3752
+ {
3753
+ key: '$.tx_responses.*.timestamp',
3754
+ comparator: '<=',
3755
+ value: `${condition.intervalInSeconds}`,
3756
+ },
3757
+ condition.feePaymentAmount,
3758
+ condition.feePaymentAddress,
3759
+ condition?.blockHeight,
3760
+ options?.topArgs?.dkgOptions?.chain
3761
+ );
3762
+ default:
3763
+ throw new Error(
3764
+ `[did-provider-cheqd]: unsupported access control condition type ${condition.type}`
3765
+ );
3766
+ }
3767
+ })
3768
+ );
3769
+ return await lit.decrypt(
3770
+ toString(thresholdEncryptionCiphertext, 'base64url'),
3771
+ publishedList.metadata.statusListHash!,
3772
+ unifiedAccessControlConditions
3773
+ );
3774
+ } else {
3775
+ // Use provided symmetric key or file
3776
+ if (options?.statusListFile) {
3777
+ // if not encrypted, return bitstring
3778
+ if (!publishedList.metadata.encrypted) {
3779
+ // construct encoded status list
3780
+ const bitstring = new DBBitstring({
3781
+ buffer: await Cheqd.getFile(options.statusListFile),
3782
+ });
3783
+ const compressed = await bitstring.compressBits();
3784
+ // validate against published list
3785
+ if (encoded !== toString(compressed, 'base64url'))
3786
+ throw new Error(
3787
+ '[did-provider-cheqd]: statusListFile does not match published Bitstring status list'
3788
+ );
3789
+
3790
+ // return compressed
3791
+ return compressed;
3792
+ }
3793
+ // otherwise, decrypt and return bitstring
3794
+ const scopedRawBlob = await toBlob(await Cheqd.getFile(options.statusListFile));
3795
+ const decrypted = toString(
3796
+ await LitProtocol.decryptDirect(
3797
+ scopedRawBlob,
3798
+ await safeDeserialise(
3799
+ options?.topArgs?.symmetricKey,
3800
+ fromString,
3801
+ ['hex'],
3802
+ 'Invalid symmetric key'
3803
+ )
3804
+ ),
3805
+ 'base64url'
3806
+ );
3807
+
3808
+ // validate against published list
3809
+ if (decrypted !== encoded)
3810
+ throw new Error(
3811
+ '[did-provider-cheqd]: statusListFile does not match published Bitstring status list'
3812
+ );
2177
3813
 
2178
- // validate status options - case: statusOptions.statusListIndex
2179
- if (!args.statusOptions.statusPurpose)
2180
- throw new Error('[did-provider-cheqd]: check status: statusOptions.statusListIndex is required');
3814
+ // return decrypted
3815
+ return decrypted;
3816
+ }
2181
3817
 
2182
- // validate status options - case: statusOptions.statusListIndex
2183
- if (!args.statusOptions.statusListIndex)
2184
- throw new Error('[did-provider-cheqd]: check status: statusOptions.statusListIndex is required');
3818
+ if (!options?.statusListInlineBitstring) {
3819
+ throw new Error(
3820
+ '[did-provider-cheqd]: statusListInlineBitstring required if statusListFile not provided'
3821
+ );
3822
+ }
3823
+ // validate against published list
3824
+ if (options?.statusListInlineBitstring !== encoded)
3825
+ throw new Error(
3826
+ '[did-provider-cheqd]: statusListInlineBitstring does not match published bitstring status list'
3827
+ );
3828
+ // otherwise, read from inline bitstring
3829
+ return options.statusListInlineBitstring;
3830
+ }
3831
+ }
3832
+ // Helper function to publish updated status list
3833
+ static async publishUpdatedBitstringStatusList(
3834
+ updatedStatusList: BitstringStatusList,
3835
+ credential: VerifiableCredential,
3836
+ options?: ICheqdStatusListOptions
3837
+ ): Promise<{ symmetricKey?: string }> {
3838
+ const topArgs = options?.topArgs as ICheqdUpdateCredentialWithStatusListArgs;
2185
3839
 
2186
- // generate resource type
2187
- const resourceType =
2188
- args.statusOptions.statusPurpose === DefaultStatusList2021StatusPurposeTypes.revocation
2189
- ? DefaultStatusList2021ResourceTypes.revocation
2190
- : DefaultStatusList2021ResourceTypes.suspension;
3840
+ // Fetch current metadata
3841
+ const statusListMetadata = await Cheqd.fetchStatusListMetadata(credential);
2191
3842
 
2192
- // construct status list credential
2193
- const statusListCredential = `${DefaultResolverUrl}${args.statusOptions.issuerDid}?resourceName=${args.statusOptions.statusListName}&resourceType=${resourceType}`;
3843
+ // Handle encrypted publishing if needed
3844
+ if (topArgs.publishEncrypted && updatedStatusList.metadata.encrypted) {
3845
+ // Re-encrypt with new content
3846
+ const bitstring = updatedStatusList.bitstringStatusListCredential.credentialSubject.encodedList;
2194
3847
 
2195
- // construct credential status
2196
- args.credential = {
2197
- '@context': [],
2198
- issuer: args.statusOptions.issuerDid,
2199
- credentialSubject: {},
2200
- credentialStatus: {
2201
- id: `${statusListCredential}#${args.statusOptions.statusListIndex}`,
2202
- type: 'StatusList2021Entry',
2203
- statusPurpose: `${args.statusOptions.statusPurpose}`,
2204
- statusListIndex: `${args.statusOptions.statusListIndex}`,
2205
- },
2206
- issuanceDate: '',
2207
- proof: {},
2208
- };
2209
- }
3848
+ // Encrypt bitstring - case: symmetric
3849
+ const { encryptedString: symmetricEncryptionCiphertext, symmetricKey } = await LitProtocol.encryptDirect(
3850
+ fromString(bitstring, 'base64url')
3851
+ );
2210
3852
 
2211
- // validate args - case: credential
2212
- if (!args.credential) throw new Error('[did-provider-cheqd]: revocation: credential is required');
3853
+ // Get DKG client and encrypt threshold
3854
+ const lit = await options!.publishOptions.instantiateDkgClient();
3855
+ const unifiedAccessControlConditions = await Promise.all(
3856
+ updatedStatusList.metadata.paymentConditions!.map(async (condition) => {
3857
+ switch (condition.type) {
3858
+ case AccessControlConditionTypes.timelockPayment:
3859
+ return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock(
3860
+ {
3861
+ key: '$.tx_responses.*.timestamp',
3862
+ comparator: '<=',
3863
+ value: `${condition.intervalInSeconds}`,
3864
+ },
3865
+ condition.feePaymentAmount,
3866
+ condition.feePaymentAddress,
3867
+ condition?.blockHeight,
3868
+ topArgs?.dkgOptions?.chain
3869
+ );
3870
+ default:
3871
+ throw new Error(
3872
+ `[did-provider-cheqd]: unsupported access control condition type ${condition.type}`
3873
+ );
3874
+ }
3875
+ })
3876
+ );
2213
3877
 
2214
- // if jwt credential, decode it
2215
- const credential =
2216
- typeof args.credential === 'string' ? await Cheqd.decodeCredentialJWT(args.credential) : args.credential;
3878
+ const { encryptedString: thresholdEncryptionCiphertext, stringHash } = await lit.encrypt(
3879
+ fromString(bitstring, 'base64url'),
3880
+ unifiedAccessControlConditions
3881
+ );
2217
3882
 
2218
- // define issuer
2219
- const issuer =
2220
- typeof credential.issuer === 'string' ? credential.issuer : (credential.issuer as { id: string }).id;
3883
+ // Update encoded list with encrypted content
3884
+ const { encodedList, symmetricLength } = await encodeWithMetadata(
3885
+ symmetricEncryptionCiphertext,
3886
+ thresholdEncryptionCiphertext
3887
+ );
2221
3888
 
2222
- // define provider, if applicable
2223
- this.didProvider = await Cheqd.getProviderFromDidUrl(issuer, this.supportedDidProviders);
3889
+ updatedStatusList.bitstringStatusListCredential.credentialSubject.encodedList = encodedList;
3890
+ updatedStatusList.metadata.statusListHash = stringHash;
3891
+ updatedStatusList.metadata.symmetricLength = symmetricLength;
2224
3892
 
2225
- // define provider id, if applicable
2226
- this.providerId = Cheqd.generateProviderId(issuer);
3893
+ // Publish the encrypted status list
3894
+ await Cheqd.publishBitstringStatusList(
3895
+ fromString(JSON.stringify(updatedStatusList), 'utf-8'),
3896
+ statusListMetadata,
3897
+ options?.publishOptions
3898
+ );
2227
3899
 
2228
- // define dkg options, if provided
2229
- args.dkgOptions ||= this.didProvider.dkgOptions;
3900
+ return { symmetricKey: toString(symmetricKey, 'hex') };
3901
+ } else {
3902
+ // Publish unencrypted
3903
+ await Cheqd.publishBitstringStatusList(
3904
+ fromString(JSON.stringify(updatedStatusList), 'utf-8'),
3905
+ statusListMetadata,
3906
+ options?.publishOptions
3907
+ );
2230
3908
 
2231
- switch (credential.credentialStatus?.statusPurpose) {
2232
- case DefaultStatusList2021StatusPurposeTypes.revocation:
2233
- return { revoked: await Cheqd.checkRevoked(credential, { ...args.options, topArgs: args }) };
2234
- case DefaultStatusList2021StatusPurposeTypes.suspension:
2235
- return { suspended: await Cheqd.checkSuspended(credential, { ...args.options, topArgs: args }) };
2236
- default:
2237
- throw new Error(
2238
- `[did-provider-cheqd]: check status: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`
2239
- );
3909
+ return {};
2240
3910
  }
2241
3911
  }
3912
+ // Helper function to publish bitstring status list
3913
+ static async publishBitstringStatusList(
3914
+ statusListRaw: Uint8Array,
3915
+ statusListMetadata: LinkedResourceMetadataResolutionResult,
3916
+ options: {
3917
+ context: IContext;
3918
+ resourceId?: string;
3919
+ resourceVersion?: string;
3920
+ resourceAlsoKnownAs?: AlternativeUri[];
3921
+ signInputs?: ISignInputs[];
3922
+ fee?: DidStdFee | 'auto' | number;
3923
+ }
3924
+ ): Promise<boolean> {
3925
+ // Construct payload
3926
+ const payload = {
3927
+ id: options?.resourceId || v4(),
3928
+ collectionId: statusListMetadata.resourceCollectionId,
3929
+ name: statusListMetadata.resourceName,
3930
+ version: options?.resourceVersion || new Date().toISOString(),
3931
+ alsoKnownAs: options?.resourceAlsoKnownAs || [],
3932
+ resourceType: BitstringStatusListResourceType,
3933
+ data: statusListRaw,
3934
+ } satisfies BitstringStatusListResourcePayload;
3935
+
3936
+ return await options.context.agent[BroadcastStatusListMethodName]({
3937
+ kms: (await options.context.agent.keyManagerGetKeyManagementSystems())[0],
3938
+ payload,
3939
+ network: statusListMetadata.resourceURI.split(':')[2] as CheqdNetwork,
3940
+ signInputs: options?.signInputs,
3941
+ fee: options?.fee,
3942
+ });
3943
+ }
2242
3944
 
2243
3945
  private async RevokeCredentialWithStatusList2021(
2244
- args: ICheqdRevokeCredentialWithStatusList2021Args,
3946
+ args: ICheqdRevokeCredentialWithStatusListArgs,
2245
3947
  context: IContext
2246
3948
  ): Promise<RevocationResult> {
2247
3949
  // verify credential, if provided and revocation options are not
@@ -2359,8 +4061,321 @@ export class Cheqd implements IAgentPlugin {
2359
4061
  });
2360
4062
  }
2361
4063
 
4064
+ private async BulkUpdateCredentialsWithStatusList(
4065
+ args: ICheqdBulkUpdateCredentialWithStatusListArgs,
4066
+ context: IContext
4067
+ ): Promise<BulkBitstringUpdateResult> {
4068
+ // validate new status value
4069
+ if (typeof args.newStatus !== 'number' || args.newStatus < 0 || args.newStatus > 3) {
4070
+ throw new Error(
4071
+ '[did-provider-cheqd]: bulk update: newStatus must be 0-3 (valid/revoked/suspended/unknown)'
4072
+ );
4073
+ }
4074
+
4075
+ // verify credentials, if provided and update options are not
4076
+ if (args?.credentials && !args?.updateOptions) {
4077
+ const verificationResult = await Promise.all(
4078
+ args.credentials.map(async (credential) => {
4079
+ return await context.agent.verifyCredential({
4080
+ ...args?.verificationOptions,
4081
+ credential,
4082
+ policies: {
4083
+ credentialStatus: false,
4084
+ },
4085
+ } satisfies IVerifyCredentialArgs);
4086
+ })
4087
+ );
4088
+
4089
+ // early return if verification failed for any credential
4090
+ if (verificationResult.some((result) => !result.verified)) {
4091
+ return {
4092
+ updated: Array(args.credentials.length).fill(false),
4093
+ statusValues: Array(args.credentials.length).fill(BitstringStatusValue.UNKNOWN),
4094
+ statusMessages: Array(args.credentials.length).fill('verification failed'),
4095
+ error: verificationResult.find((result) => !result.verified)!.error || {
4096
+ message: 'verification: could not verify credential',
4097
+ },
4098
+ };
4099
+ }
4100
+ }
4101
+
4102
+ // if update options are provided, give precedence
4103
+ if (args?.updateOptions) {
4104
+ // validate update options
4105
+ if (!args.updateOptions.issuerDid) {
4106
+ throw new Error('[did-provider-cheqd]: bulk update: updateOptions.issuerDid is required');
4107
+ }
4108
+ if (!args.updateOptions.statusListName) {
4109
+ throw new Error('[did-provider-cheqd]: bulk update: updateOptions.statusListName is required');
4110
+ }
4111
+ if (!args.updateOptions.statusListIndices || !Array.isArray(args.updateOptions.statusListIndices)) {
4112
+ throw new Error(
4113
+ '[did-provider-cheqd]: bulk update: updateOptions.statusListIndices is required and must be an array'
4114
+ );
4115
+ }
4116
+
4117
+ // Construct status list credential URL
4118
+ const statusListCredential = `${DefaultResolverUrl}${args.updateOptions.issuerDid}?resourceName=${args.updateOptions.statusListName}&resourceType=${BitstringStatusListResourceType}`;
4119
+
4120
+ // fetch latest status list to get metadata
4121
+ const statusList = await Cheqd.fetchBitstringStatusList({
4122
+ credentialStatus: {
4123
+ id: statusListCredential,
4124
+ },
4125
+ } as VerifiableCredential);
4126
+
4127
+ // For multi-purpose status lists, determine the appropriate statusPurpose
4128
+ const statusPurpose = this.getStatusPurposeForMultiPurposeList(args.newStatus);
4129
+
4130
+ // construct credentials with proper status entries
4131
+ args.credentials = args.updateOptions.statusListIndices.map((index, i) => ({
4132
+ '@context': [],
4133
+ issuer: args.updateOptions!.issuerDid,
4134
+ credentialSubject: {},
4135
+ credentialStatus: {
4136
+ id: `${statusListCredential}#${index}`,
4137
+ type: 'BitstringStatusListEntry',
4138
+ statusPurpose: statusPurpose,
4139
+ statusListIndex: `${index}`,
4140
+ statusListCredential,
4141
+ statusSize: statusList.metadata.statusSize || 1,
4142
+ statusMessage: statusList.metadata.statusMessages || [],
4143
+ },
4144
+ issuanceDate: '',
4145
+ proof: {},
4146
+ }));
4147
+ }
4148
+ // if jwt credentials, decode them
4149
+ const credentials = await Promise.all(
4150
+ args.credentials!.map(async (credential) =>
4151
+ typeof credential === 'string' ? await Cheqd.decodeCredentialJWT(credential) : credential
4152
+ )
4153
+ );
4154
+
4155
+ // Validate that ALL credentials MUST have credentialStatus
4156
+ const credentialsWithoutStatus = credentials.filter((credential, index) => !credential.credentialStatus);
4157
+ if (credentialsWithoutStatus.length > 0) {
4158
+ throw new Error(
4159
+ `[did-provider-cheqd]: bulk update: ${credentialsWithoutStatus.length} credential(s) missing credentialStatus`
4160
+ );
4161
+ }
4162
+
4163
+ // Validate that all credentials have BitstringStatusListEntry type
4164
+ const invalidStatusTypes = credentials.filter(
4165
+ (credential) => credential.credentialStatus?.type !== 'BitstringStatusListEntry'
4166
+ );
4167
+ if (invalidStatusTypes.length > 0) {
4168
+ throw new Error(
4169
+ `[did-provider-cheqd]: bulk update: ${invalidStatusTypes.length} credential(s) must have BitstringStatusListEntry credentialStatus`
4170
+ );
4171
+ }
4172
+ // validate credentials - case: consistent issuer
4173
+ if (
4174
+ credentials
4175
+ .map((credential) => {
4176
+ return (credential.issuer as { id: string }).id
4177
+ ? (credential.issuer as { id: string }).id
4178
+ : (credential.issuer as string);
4179
+ })
4180
+ .filter((value, _, self) => value && value !== self[0]).length > 0
4181
+ ) {
4182
+ throw new Error('[did-provider-cheqd]: bulk update: Credentials must be issued by the same issuer');
4183
+ }
4184
+ // validate credentials - case: status list index uniqueness
4185
+ if (
4186
+ credentials
4187
+ .map((credential) => credential.credentialStatus!.statusListIndex)
4188
+ .filter((value, index, self) => self.indexOf(value) !== index).length > 0
4189
+ ) {
4190
+ throw new Error('[did-provider-cheqd]: bulk update: Credentials must have unique status list index');
4191
+ }
4192
+ // validate credentials - case: status list credential consistency
4193
+ const statusListCredentialUrl = credentials[0].credentialStatus?.statusListCredential;
4194
+ if (!statusListCredentialUrl) {
4195
+ throw new Error('[did-provider-cheqd]: bulk update: Invalid status list credential URL');
4196
+ }
4197
+ if (
4198
+ !credentials.every(
4199
+ (credential) => credential.credentialStatus?.statusListCredential === statusListCredentialUrl
4200
+ )
4201
+ ) {
4202
+ throw new Error('[did-provider-cheqd]: bulk update: Credentials must belong to the same status list');
4203
+ }
4204
+ // validate credentials - case: status list type
4205
+ if (!credentials.every((credential) => credential.credentialStatus?.type === 'BitstringStatusListEntry')) {
4206
+ throw new Error('[did-provider-cheqd]: bulk update: Invalid status list type');
4207
+ }
4208
+
4209
+ // validate args in pairs - case: statusListFile and statusList
4210
+ if (args.options?.statusListFile && args.options?.statusList) {
4211
+ throw new Error('[did-provider-cheqd]: bulk update: statusListFile and statusList are mutually exclusive');
4212
+ }
4213
+
4214
+ // validate args in pairs - case: statusListFile and fetchList
4215
+ if (args.options?.statusListFile && args.options?.fetchList) {
4216
+ throw new Error('[did-provider-cheqd]: bulk update: statusListFile and fetchList are mutually exclusive');
4217
+ }
4218
+
4219
+ // validate args in pairs - case: statusList and fetchList
4220
+ if (args.options?.statusList && args.options?.fetchList) {
4221
+ throw new Error('[did-provider-cheqd]: bulk update: statusList and fetchList are mutually exclusive');
4222
+ }
4223
+
4224
+ // validate args in pairs - case: publish
4225
+ if (args.options?.publish && !args.fetchList && !(args.options?.statusListFile || args.options?.statusList)) {
4226
+ throw new Error(
4227
+ '[did-provider-cheqd]: bulk update: publish requires statusListFile or statusList, if fetchList is disabled'
4228
+ );
4229
+ }
4230
+ // Define issuer and provider
4231
+ const issuer =
4232
+ typeof credentials[0].issuer === 'string'
4233
+ ? credentials[0].issuer
4234
+ : (credentials[0].issuer as { id: string }).id;
4235
+
4236
+ this.didProvider = await Cheqd.getProviderFromDidUrl(issuer, this.supportedDidProviders);
4237
+ this.providerId = Cheqd.generateProviderId(issuer);
4238
+ args.dkgOptions ||= this.didProvider.dkgOptions;
4239
+ try {
4240
+ // Fetch published status list
4241
+ const publishedList = await Cheqd.fetchBitstringStatusList(credentials[0]);
4242
+ // Error if encrypted and no decryption key provided
4243
+ if (publishedList.metadata.encrypted && !args?.symmetricKey) {
4244
+ throw new Error(
4245
+ '[did-provider-cheqd]: bulk update: symmetricKey is required for encrypted status list'
4246
+ );
4247
+ }
4248
+ // Fetch and decrypt the current bitstring
4249
+ const currentBitstring = await Cheqd.fetchAndDecryptBitstring(publishedList, {
4250
+ ...args.options,
4251
+ topArgs: args,
4252
+ instantiateDkgClient: () => this.didProvider.instantiateDkgThresholdProtocolClient(),
4253
+ });
4254
+ // Parse the bitstring
4255
+ const decompressedBuffer = await DBBitstring.decodeBits({ encoded: currentBitstring });
4256
+ const bitstring = new DBBitstring({ buffer: decompressedBuffer });
4257
+
4258
+ const statusSize = publishedList.metadata.statusSize || Cheqd.DefaultBitstringStatusSize;
4259
+ const newStatusValue = args.newStatus;
4260
+
4261
+ // Process all credentials
4262
+ const results: Array<{
4263
+ updated: boolean;
4264
+ statusValue: BitstringStatusValue;
4265
+ previousStatusValue?: BitstringStatusValue;
4266
+ statusMessage?: string;
4267
+ }> = [];
4268
+
4269
+ let anyUpdated = false;
4270
+ for (const credential of credentials) {
4271
+ const statusIndex = parseInt(credential.credentialStatus!.statusListIndex, 10);
4272
+ const bitPosition = statusIndex * statusSize;
4273
+
4274
+ // Get current status value
4275
+ const currentStatusValue = Cheqd.getBitValue(bitstring, bitPosition, statusSize);
4276
+ // Check if update is needed
4277
+ if (currentStatusValue === newStatusValue) {
4278
+ const statusMessage =
4279
+ publishedList.metadata.statusMessages?.find(
4280
+ (msg) => parseInt(msg.status, 16) === currentStatusValue
4281
+ )?.message || 'unknown';
4282
+
4283
+ results.push({
4284
+ updated: false,
4285
+ statusValue: currentStatusValue as BitstringStatusValue,
4286
+ statusMessage,
4287
+ });
4288
+ } else {
4289
+ // Update the bitstring
4290
+ Cheqd.setBitValue(bitstring, bitPosition, newStatusValue, statusSize);
4291
+
4292
+ const newStatusMessage =
4293
+ publishedList.metadata.statusMessages?.find(
4294
+ (msg) => parseInt(msg.status, 16) === newStatusValue
4295
+ )?.message || 'unknown';
4296
+ results.push({
4297
+ updated: true,
4298
+ statusValue: newStatusValue as BitstringStatusValue,
4299
+ previousStatusValue: currentStatusValue as BitstringStatusValue,
4300
+ statusMessage: newStatusMessage,
4301
+ });
4302
+
4303
+ anyUpdated = true;
4304
+ }
4305
+ }
4306
+ // If no updates needed, return early
4307
+ if (!anyUpdated) {
4308
+ return {
4309
+ updated: results.map((r) => r.updated),
4310
+ statusValues: results.map((r) => r.statusValue),
4311
+ previousStatusValues: results.map((r) => r.previousStatusValue).filter((v) => v !== undefined),
4312
+ statusMessages: results.map((r) => r.statusMessage).filter((m) => m !== undefined),
4313
+ };
4314
+ }
4315
+ // Compress the updated bitstring
4316
+ const compressedBitstring = await bitstring.compressBits();
4317
+ const encodedBitstring = toString(compressedBitstring, 'base64url');
4318
+
4319
+ // Create updated status list credential
4320
+ const updatedStatusListCredential = {
4321
+ ...publishedList.bitstringStatusListCredential,
4322
+ credentialSubject: {
4323
+ ...publishedList.bitstringStatusListCredential.credentialSubject,
4324
+ encodedList: encodedBitstring,
4325
+ },
4326
+ };
4327
+
4328
+ const updatedStatusList: BitstringStatusList = {
4329
+ bitstringStatusListCredential: updatedStatusListCredential,
4330
+ metadata: publishedList.metadata,
4331
+ };
4332
+ // Write to file if requested
4333
+ if (args?.writeToFile) {
4334
+ await Cheqd.writeFile(compressedBitstring, args.options?.statusListFile);
4335
+ }
4336
+ // Publish if requested
4337
+ const published = args?.publish
4338
+ ? await Cheqd.publishUpdatedBitstringStatusList(updatedStatusList, credentials[0], {
4339
+ ...args.options,
4340
+ topArgs: args,
4341
+ publishOptions: {
4342
+ context,
4343
+ statusListEncoding: args?.options?.statusListEncoding,
4344
+ statusListValidUntil: args?.options?.statusListValidUntil,
4345
+ resourceId: args?.options?.resourceId,
4346
+ resourceVersion: args?.options?.resourceVersion,
4347
+ resourceAlsoKnownAs: args?.options?.alsoKnownAs,
4348
+ signInputs: args?.options?.signInputs,
4349
+ fee: args?.options?.fee,
4350
+ instantiateDkgClient: () => this.didProvider.instantiateDkgThresholdProtocolClient(),
4351
+ },
4352
+ })
4353
+ : undefined;
4354
+ return {
4355
+ updated: results.map((r) => r.updated),
4356
+ statusValues: results.map((r) => r.statusValue),
4357
+ previousStatusValues: results.map((r) => r.previousStatusValue).filter((v) => v !== undefined),
4358
+ statusMessages: results.map((r) => r.statusMessage).filter((m) => m !== undefined),
4359
+ published: args?.publish ? !!published : undefined,
4360
+ statusList: args?.returnUpdatedStatusList ? updatedStatusList : undefined,
4361
+ symmetricKey: args?.returnSymmetricKey && published?.symmetricKey ? published.symmetricKey : undefined,
4362
+ resourceMetadata: args?.returnStatusListMetadata
4363
+ ? await Cheqd.fetchStatusListMetadata(credentials[0])
4364
+ : undefined,
4365
+ };
4366
+ } catch (error) {
4367
+ console.error('[did-provider-cheqd]: bulk update error:', error);
4368
+ return {
4369
+ updated: Array(credentials.length).fill(false),
4370
+ statusValues: Array(credentials.length).fill(BitstringStatusValue.UNKNOWN),
4371
+ statusMessages: Array(credentials.length).fill('update failed'),
4372
+ error: error as IError,
4373
+ };
4374
+ }
4375
+ }
4376
+
2362
4377
  private async RevokeBulkCredentialsWithStatusList2021(
2363
- args: ICheqdRevokeBulkCredentialsWithStatusList2021Args,
4378
+ args: ICheqdRevokeBulkCredentialsWithStatusListArgs,
2364
4379
  context: IContext
2365
4380
  ): Promise<BulkRevocationResult> {
2366
4381
  // verify credential, if provided and revocation options are not
@@ -2495,7 +4510,7 @@ export class Cheqd implements IAgentPlugin {
2495
4510
  }
2496
4511
 
2497
4512
  private async SuspendCredentialWithStatusList2021(
2498
- args: ICheqdSuspendCredentialWithStatusList2021Args,
4513
+ args: ICheqdSuspendCredentialWithStatusListArgs,
2499
4514
  context: IContext
2500
4515
  ): Promise<SuspensionResult> {
2501
4516
  // verify credential, if provided and suspension options are not
@@ -2614,7 +4629,7 @@ export class Cheqd implements IAgentPlugin {
2614
4629
  }
2615
4630
 
2616
4631
  private async SuspendBulkCredentialsWithStatusList2021(
2617
- args: ICheqdSuspendBulkCredentialsWithStatusList2021Args,
4632
+ args: ICheqdSuspendBulkCredentialsWithStatusListArgs,
2618
4633
  context: IContext
2619
4634
  ): Promise<BulkSuspensionResult> {
2620
4635
  // verify credential, if provided and suspension options are not
@@ -2749,7 +4764,7 @@ export class Cheqd implements IAgentPlugin {
2749
4764
  }
2750
4765
 
2751
4766
  private async UnsuspendCredentialWithStatusList2021(
2752
- args: ICheqdUnsuspendCredentialWithStatusList2021Args,
4767
+ args: ICheqdUnsuspendCredentialWithStatusListArgs,
2753
4768
  context: IContext
2754
4769
  ): Promise<UnsuspensionResult> {
2755
4770
  // verify credential, if provided and unsuspension options are not
@@ -2868,7 +4883,7 @@ export class Cheqd implements IAgentPlugin {
2868
4883
  }
2869
4884
 
2870
4885
  private async UnsuspendBulkCredentialsWithStatusList2021(
2871
- args: ICheqdUnsuspendBulkCredentialsWithStatusList2021Args,
4886
+ args: ICheqdUnsuspendBulkCredentialsWithStatusListArgs,
2872
4887
  context: IContext
2873
4888
  ): Promise<BulkUnsuspensionResult> {
2874
4889
  // verify credential, if provided and unsuspension options are not
@@ -3343,7 +5358,7 @@ export class Cheqd implements IAgentPlugin {
3343
5358
 
3344
5359
  static async revokeCredential(
3345
5360
  credential: VerifiableCredential,
3346
- options?: ICheqdStatusList2021Options
5361
+ options?: ICheqdStatusListOptions
3347
5362
  ): Promise<RevocationResult> {
3348
5363
  try {
3349
5364
  // validate status purpose
@@ -3369,7 +5384,7 @@ export class Cheqd implements IAgentPlugin {
3369
5384
  : toString(
3370
5385
  fromString(
3371
5386
  publishedList.StatusList2021.encodedList,
3372
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
5387
+ publishedList.metadata.encoding as DefaultStatusListEncoding
3373
5388
  ),
3374
5389
  'base64url'
3375
5390
  );
@@ -3418,7 +5433,7 @@ export class Cheqd implements IAgentPlugin {
3418
5433
  : toString(
3419
5434
  fromString(
3420
5435
  publishedList.StatusList2021.encodedList,
3421
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
5436
+ publishedList.metadata.encoding as DefaultStatusListEncoding
3422
5437
  ),
3423
5438
  'base64url'
3424
5439
  );
@@ -3497,7 +5512,7 @@ export class Cheqd implements IAgentPlugin {
3497
5512
  const bitstring = (await statusList.encode()) as Bitstring;
3498
5513
 
3499
5514
  // cast top-level args
3500
- const topArgs = options?.topArgs as ICheqdRevokeCredentialWithStatusList2021Args;
5515
+ const topArgs = options?.topArgs as ICheqdRevokeCredentialWithStatusListArgs;
3501
5516
 
3502
5517
  // write status list 2021 to file, if provided
3503
5518
  if (topArgs?.writeToFile) {
@@ -3508,7 +5523,7 @@ export class Cheqd implements IAgentPlugin {
3508
5523
  const published = topArgs?.publish
3509
5524
  ? await (async function () {
3510
5525
  // fetch status list 2021 metadata
3511
- const statusListMetadata = await Cheqd.fetchStatusList2021Metadata(credential);
5526
+ const statusListMetadata = await Cheqd.fetchStatusListMetadata(credential);
3512
5527
 
3513
5528
  // publish status list 2021 as new version
3514
5529
  const scoped = topArgs.publishEncrypted
@@ -3516,7 +5531,7 @@ export class Cheqd implements IAgentPlugin {
3516
5531
  // validate encoding, if provided
3517
5532
  if (
3518
5533
  options?.publishOptions?.statusListEncoding &&
3519
- !Object.values(DefaultStatusList2021Encodings).includes(
5534
+ !Object.values(DefaultStatusListEncodings).includes(
3520
5535
  options?.publishOptions?.statusListEncoding
3521
5536
  )
3522
5537
  ) {
@@ -3713,7 +5728,7 @@ export class Cheqd implements IAgentPlugin {
3713
5728
  encrypted: true,
3714
5729
  encoding:
3715
5730
  (options?.publishOptions?.statusListEncoding as
3716
- | DefaultStatusList2021Encoding
5731
+ | DefaultStatusListEncoding
3717
5732
  | undefined) || publishedList.metadata.encoding,
3718
5733
  statusListHash:
3719
5734
  symmetricEncryptionStringHash === thresholdEncryptionStringHash
@@ -3746,7 +5761,7 @@ export class Cheqd implements IAgentPlugin {
3746
5761
  // validate encoding, if provided
3747
5762
  if (
3748
5763
  options?.publishOptions?.statusListEncoding &&
3749
- !Object.values(DefaultStatusList2021Encodings).includes(
5764
+ !Object.values(DefaultStatusListEncodings).includes(
3750
5765
  options?.publishOptions?.statusListEncoding
3751
5766
  )
3752
5767
  ) {
@@ -3795,7 +5810,7 @@ export class Cheqd implements IAgentPlugin {
3795
5810
  : toString(
3796
5811
  fromString(bitstring, 'base64url'),
3797
5812
  options!.publishOptions
3798
- .statusListEncoding as DefaultStatusList2021Encoding
5813
+ .statusListEncoding as DefaultStatusListEncoding
3799
5814
  ),
3800
5815
  validFrom: publishedList.StatusList2021.validFrom,
3801
5816
  validUntil:
@@ -3806,7 +5821,7 @@ export class Cheqd implements IAgentPlugin {
3806
5821
  type: publishedList.metadata.type,
3807
5822
  encoding:
3808
5823
  (options?.publishOptions?.statusListEncoding as
3809
- | DefaultStatusList2021Encoding
5824
+ | DefaultStatusListEncoding
3810
5825
  | undefined) || publishedList.metadata.encoding,
3811
5826
  encrypted: false,
3812
5827
  },
@@ -3842,7 +5857,7 @@ export class Cheqd implements IAgentPlugin {
3842
5857
  ? toString((published?.[1] as { symmetricKey: Uint8Array })?.symmetricKey, 'hex')
3843
5858
  : undefined,
3844
5859
  resourceMetadata: topArgs?.returnStatusListMetadata
3845
- ? await Cheqd.fetchStatusList2021Metadata(credential)
5860
+ ? await Cheqd.fetchStatusListMetadata(credential)
3846
5861
  : undefined,
3847
5862
  } satisfies RevocationResult;
3848
5863
  } catch (error) {
@@ -3855,7 +5870,7 @@ export class Cheqd implements IAgentPlugin {
3855
5870
 
3856
5871
  static async revokeCredentials(
3857
5872
  credentials: VerifiableCredential[],
3858
- options?: ICheqdStatusList2021Options
5873
+ options?: ICheqdStatusListOptions
3859
5874
  ): Promise<BulkRevocationResult> {
3860
5875
  // validate credentials - case: empty
3861
5876
  if (!credentials.length || credentials.length === 0)
@@ -3934,7 +5949,7 @@ export class Cheqd implements IAgentPlugin {
3934
5949
  : toString(
3935
5950
  fromString(
3936
5951
  publishedList.StatusList2021.encodedList,
3937
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
5952
+ publishedList.metadata.encoding as DefaultStatusListEncoding
3938
5953
  ),
3939
5954
  'base64url'
3940
5955
  );
@@ -3983,7 +5998,7 @@ export class Cheqd implements IAgentPlugin {
3983
5998
  : toString(
3984
5999
  fromString(
3985
6000
  publishedList.StatusList2021.encodedList,
3986
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
6001
+ publishedList.metadata.encoding as DefaultStatusListEncoding
3987
6002
  ),
3988
6003
  'base64url'
3989
6004
  );
@@ -4086,7 +6101,7 @@ export class Cheqd implements IAgentPlugin {
4086
6101
  const bitstring = (await statusList.encode()) as Bitstring;
4087
6102
 
4088
6103
  // cast top-level args
4089
- const topArgs = options?.topArgs as ICheqdRevokeCredentialWithStatusList2021Args;
6104
+ const topArgs = options?.topArgs as ICheqdRevokeCredentialWithStatusListArgs;
4090
6105
 
4091
6106
  // write status list 2021 to file, if provided
4092
6107
  if (topArgs?.writeToFile) {
@@ -4097,7 +6112,7 @@ export class Cheqd implements IAgentPlugin {
4097
6112
  const published = topArgs?.publish
4098
6113
  ? await (async function () {
4099
6114
  // fetch status list 2021 metadata
4100
- const statusListMetadata = await Cheqd.fetchStatusList2021Metadata(credentials[0]);
6115
+ const statusListMetadata = await Cheqd.fetchStatusListMetadata(credentials[0]);
4101
6116
 
4102
6117
  // publish status list 2021 as new version
4103
6118
  const scoped = topArgs.publishEncrypted
@@ -4105,7 +6120,7 @@ export class Cheqd implements IAgentPlugin {
4105
6120
  // validate encoding, if provided
4106
6121
  if (
4107
6122
  options?.publishOptions?.statusListEncoding &&
4108
- !Object.values(DefaultStatusList2021Encodings).includes(
6123
+ !Object.values(DefaultStatusListEncodings).includes(
4109
6124
  options?.publishOptions?.statusListEncoding
4110
6125
  )
4111
6126
  ) {
@@ -4302,7 +6317,7 @@ export class Cheqd implements IAgentPlugin {
4302
6317
  encrypted: true,
4303
6318
  encoding:
4304
6319
  (options?.publishOptions?.statusListEncoding as
4305
- | DefaultStatusList2021Encoding
6320
+ | DefaultStatusListEncoding
4306
6321
  | undefined) || publishedList.metadata.encoding,
4307
6322
  statusListHash:
4308
6323
  symmetricEncryptionStringHash === thresholdEncryptionStringHash
@@ -4335,7 +6350,7 @@ export class Cheqd implements IAgentPlugin {
4335
6350
  // validate encoding, if provided
4336
6351
  if (
4337
6352
  options?.publishOptions?.statusListEncoding &&
4338
- !Object.values(DefaultStatusList2021Encodings).includes(
6353
+ !Object.values(DefaultStatusListEncodings).includes(
4339
6354
  options?.publishOptions?.statusListEncoding
4340
6355
  )
4341
6356
  ) {
@@ -4384,7 +6399,7 @@ export class Cheqd implements IAgentPlugin {
4384
6399
  : toString(
4385
6400
  fromString(bitstring, 'base64url'),
4386
6401
  options!.publishOptions
4387
- .statusListEncoding as DefaultStatusList2021Encoding
6402
+ .statusListEncoding as DefaultStatusListEncoding
4388
6403
  ),
4389
6404
  validFrom: publishedList.StatusList2021.validFrom,
4390
6405
  validUntil:
@@ -4395,7 +6410,7 @@ export class Cheqd implements IAgentPlugin {
4395
6410
  type: publishedList.metadata.type,
4396
6411
  encoding:
4397
6412
  (options?.publishOptions?.statusListEncoding as
4398
- | DefaultStatusList2021Encoding
6413
+ | DefaultStatusListEncoding
4399
6414
  | undefined) || publishedList.metadata.encoding,
4400
6415
  encrypted: false,
4401
6416
  },
@@ -4431,7 +6446,7 @@ export class Cheqd implements IAgentPlugin {
4431
6446
  ? toString((published?.[1] as { symmetricKey: Uint8Array })?.symmetricKey, 'hex')
4432
6447
  : undefined,
4433
6448
  resourceMetadata: topArgs?.returnStatusListMetadata
4434
- ? await Cheqd.fetchStatusList2021Metadata(credentials[0])
6449
+ ? await Cheqd.fetchStatusListMetadata(credentials[0])
4435
6450
  : undefined,
4436
6451
  } satisfies BulkRevocationResult;
4437
6452
  } catch (error) {
@@ -4444,7 +6459,7 @@ export class Cheqd implements IAgentPlugin {
4444
6459
 
4445
6460
  static async suspendCredential(
4446
6461
  credential: VerifiableCredential,
4447
- options?: ICheqdStatusList2021Options
6462
+ options?: ICheqdStatusListOptions
4448
6463
  ): Promise<SuspensionResult> {
4449
6464
  try {
4450
6465
  // validate status purpose
@@ -4470,7 +6485,7 @@ export class Cheqd implements IAgentPlugin {
4470
6485
  : toString(
4471
6486
  fromString(
4472
6487
  publishedList.StatusList2021.encodedList,
4473
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
6488
+ publishedList.metadata.encoding as DefaultStatusListEncoding
4474
6489
  ),
4475
6490
  'base64url'
4476
6491
  );
@@ -4519,7 +6534,7 @@ export class Cheqd implements IAgentPlugin {
4519
6534
  : toString(
4520
6535
  fromString(
4521
6536
  publishedList.StatusList2021.encodedList,
4522
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
6537
+ publishedList.metadata.encoding as DefaultStatusListEncoding
4523
6538
  ),
4524
6539
  'base64url'
4525
6540
  );
@@ -4599,7 +6614,7 @@ export class Cheqd implements IAgentPlugin {
4599
6614
  const bitstring = (await statusList.encode()) as Bitstring;
4600
6615
 
4601
6616
  // cast top-level args
4602
- const topArgs = options?.topArgs as ICheqdSuspendCredentialWithStatusList2021Args;
6617
+ const topArgs = options?.topArgs as ICheqdSuspendCredentialWithStatusListArgs;
4603
6618
 
4604
6619
  // write status list 2021 to file, if provided
4605
6620
  if (topArgs?.writeToFile) {
@@ -4610,7 +6625,7 @@ export class Cheqd implements IAgentPlugin {
4610
6625
  const published = topArgs?.publish
4611
6626
  ? await (async function () {
4612
6627
  // fetch status list 2021 metadata
4613
- const statusListMetadata = await Cheqd.fetchStatusList2021Metadata(credential);
6628
+ const statusListMetadata = await Cheqd.fetchStatusListMetadata(credential);
4614
6629
 
4615
6630
  // publish status list 2021 as new version
4616
6631
  const scoped = topArgs.publishEncrypted
@@ -4618,7 +6633,7 @@ export class Cheqd implements IAgentPlugin {
4618
6633
  // validate encoding, if provided
4619
6634
  if (
4620
6635
  options?.publishOptions?.statusListEncoding &&
4621
- !Object.values(DefaultStatusList2021Encodings).includes(
6636
+ !Object.values(DefaultStatusListEncodings).includes(
4622
6637
  options?.publishOptions?.statusListEncoding
4623
6638
  )
4624
6639
  ) {
@@ -4815,7 +6830,7 @@ export class Cheqd implements IAgentPlugin {
4815
6830
  encrypted: true,
4816
6831
  encoding:
4817
6832
  (options?.publishOptions?.statusListEncoding as
4818
- | DefaultStatusList2021Encoding
6833
+ | DefaultStatusListEncoding
4819
6834
  | undefined) || publishedList.metadata.encoding,
4820
6835
  statusListHash:
4821
6836
  symmetricEncryptionStringHash === thresholdEncryptionStringHash
@@ -4848,7 +6863,7 @@ export class Cheqd implements IAgentPlugin {
4848
6863
  // validate encoding, if provided
4849
6864
  if (
4850
6865
  options?.publishOptions?.statusListEncoding &&
4851
- !Object.values(DefaultStatusList2021Encodings).includes(
6866
+ !Object.values(DefaultStatusListEncodings).includes(
4852
6867
  options?.publishOptions?.statusListEncoding
4853
6868
  )
4854
6869
  ) {
@@ -4897,7 +6912,7 @@ export class Cheqd implements IAgentPlugin {
4897
6912
  : toString(
4898
6913
  fromString(bitstring, 'base64url'),
4899
6914
  options!.publishOptions
4900
- .statusListEncoding as DefaultStatusList2021Encoding
6915
+ .statusListEncoding as DefaultStatusListEncoding
4901
6916
  ),
4902
6917
  validFrom: publishedList.StatusList2021.validFrom,
4903
6918
  validUntil:
@@ -4908,7 +6923,7 @@ export class Cheqd implements IAgentPlugin {
4908
6923
  type: publishedList.metadata.type,
4909
6924
  encoding:
4910
6925
  (options?.publishOptions?.statusListEncoding as
4911
- | DefaultStatusList2021Encoding
6926
+ | DefaultStatusListEncoding
4912
6927
  | undefined) || publishedList.metadata.encoding,
4913
6928
  encrypted: false,
4914
6929
  },
@@ -4944,7 +6959,7 @@ export class Cheqd implements IAgentPlugin {
4944
6959
  ? toString((published?.[1] as { symmetricKey: Uint8Array })?.symmetricKey, 'hex')
4945
6960
  : undefined,
4946
6961
  resourceMetadata: topArgs?.returnStatusListMetadata
4947
- ? await Cheqd.fetchStatusList2021Metadata(credential)
6962
+ ? await Cheqd.fetchStatusListMetadata(credential)
4948
6963
  : undefined,
4949
6964
  } satisfies SuspensionResult;
4950
6965
  } catch (error) {
@@ -4957,7 +6972,7 @@ export class Cheqd implements IAgentPlugin {
4957
6972
 
4958
6973
  static async suspendCredentials(
4959
6974
  credentials: VerifiableCredential[],
4960
- options?: ICheqdStatusList2021Options
6975
+ options?: ICheqdStatusListOptions
4961
6976
  ): Promise<BulkSuspensionResult> {
4962
6977
  // validate credentials - case: empty
4963
6978
  if (!credentials.length || credentials.length === 0)
@@ -5036,7 +7051,7 @@ export class Cheqd implements IAgentPlugin {
5036
7051
  : toString(
5037
7052
  fromString(
5038
7053
  publishedList.StatusList2021.encodedList,
5039
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
7054
+ publishedList.metadata.encoding as DefaultStatusListEncoding
5040
7055
  ),
5041
7056
  'base64url'
5042
7057
  );
@@ -5085,7 +7100,7 @@ export class Cheqd implements IAgentPlugin {
5085
7100
  : toString(
5086
7101
  fromString(
5087
7102
  publishedList.StatusList2021.encodedList,
5088
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
7103
+ publishedList.metadata.encoding as DefaultStatusListEncoding
5089
7104
  ),
5090
7105
  'base64url'
5091
7106
  );
@@ -5188,7 +7203,7 @@ export class Cheqd implements IAgentPlugin {
5188
7203
  const bitstring = (await statusList.encode()) as Bitstring;
5189
7204
 
5190
7205
  // cast top-level args
5191
- const topArgs = options?.topArgs as ICheqdRevokeCredentialWithStatusList2021Args;
7206
+ const topArgs = options?.topArgs as ICheqdRevokeCredentialWithStatusListArgs;
5192
7207
 
5193
7208
  // write status list 2021 to file, if provided
5194
7209
  if (topArgs?.writeToFile) {
@@ -5199,7 +7214,7 @@ export class Cheqd implements IAgentPlugin {
5199
7214
  const published = topArgs?.publish
5200
7215
  ? await (async function () {
5201
7216
  // fetch status list 2021 metadata
5202
- const statusListMetadata = await Cheqd.fetchStatusList2021Metadata(credentials[0]);
7217
+ const statusListMetadata = await Cheqd.fetchStatusListMetadata(credentials[0]);
5203
7218
 
5204
7219
  // publish status list 2021 as new version
5205
7220
  const scoped = topArgs.publishEncrypted
@@ -5207,7 +7222,7 @@ export class Cheqd implements IAgentPlugin {
5207
7222
  // validate encoding, if provided
5208
7223
  if (
5209
7224
  options?.publishOptions?.statusListEncoding &&
5210
- !Object.values(DefaultStatusList2021Encodings).includes(
7225
+ !Object.values(DefaultStatusListEncodings).includes(
5211
7226
  options?.publishOptions?.statusListEncoding
5212
7227
  )
5213
7228
  ) {
@@ -5404,7 +7419,7 @@ export class Cheqd implements IAgentPlugin {
5404
7419
  encrypted: true,
5405
7420
  encoding:
5406
7421
  (options?.publishOptions?.statusListEncoding as
5407
- | DefaultStatusList2021Encoding
7422
+ | DefaultStatusListEncoding
5408
7423
  | undefined) || publishedList.metadata.encoding,
5409
7424
  statusListHash:
5410
7425
  symmetricEncryptionStringHash === thresholdEncryptionStringHash
@@ -5437,7 +7452,7 @@ export class Cheqd implements IAgentPlugin {
5437
7452
  // validate encoding, if provided
5438
7453
  if (
5439
7454
  options?.publishOptions?.statusListEncoding &&
5440
- !Object.values(DefaultStatusList2021Encodings).includes(
7455
+ !Object.values(DefaultStatusListEncodings).includes(
5441
7456
  options?.publishOptions?.statusListEncoding
5442
7457
  )
5443
7458
  ) {
@@ -5486,7 +7501,7 @@ export class Cheqd implements IAgentPlugin {
5486
7501
  : toString(
5487
7502
  fromString(bitstring, 'base64url'),
5488
7503
  options!.publishOptions
5489
- .statusListEncoding as DefaultStatusList2021Encoding
7504
+ .statusListEncoding as DefaultStatusListEncoding
5490
7505
  ),
5491
7506
  validFrom: publishedList.StatusList2021.validFrom,
5492
7507
  validUntil:
@@ -5497,7 +7512,7 @@ export class Cheqd implements IAgentPlugin {
5497
7512
  type: publishedList.metadata.type,
5498
7513
  encoding:
5499
7514
  (options?.publishOptions?.statusListEncoding as
5500
- | DefaultStatusList2021Encoding
7515
+ | DefaultStatusListEncoding
5501
7516
  | undefined) || publishedList.metadata.encoding,
5502
7517
  encrypted: false,
5503
7518
  },
@@ -5533,7 +7548,7 @@ export class Cheqd implements IAgentPlugin {
5533
7548
  ? toString((published?.[1] as { symmetricKey: Uint8Array })?.symmetricKey, 'hex')
5534
7549
  : undefined,
5535
7550
  resourceMetadata: topArgs?.returnStatusListMetadata
5536
- ? await Cheqd.fetchStatusList2021Metadata(credentials[0])
7551
+ ? await Cheqd.fetchStatusListMetadata(credentials[0])
5537
7552
  : undefined,
5538
7553
  } satisfies BulkSuspensionResult;
5539
7554
  } catch (error) {
@@ -5545,7 +7560,7 @@ export class Cheqd implements IAgentPlugin {
5545
7560
 
5546
7561
  static async unsuspendCredential(
5547
7562
  credential: VerifiableCredential,
5548
- options?: ICheqdStatusList2021Options
7563
+ options?: ICheqdStatusListOptions
5549
7564
  ): Promise<UnsuspensionResult> {
5550
7565
  try {
5551
7566
  // validate status purpose
@@ -5571,7 +7586,7 @@ export class Cheqd implements IAgentPlugin {
5571
7586
  : toString(
5572
7587
  fromString(
5573
7588
  publishedList.StatusList2021.encodedList,
5574
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
7589
+ publishedList.metadata.encoding as DefaultStatusListEncoding
5575
7590
  ),
5576
7591
  'base64url'
5577
7592
  );
@@ -5620,7 +7635,7 @@ export class Cheqd implements IAgentPlugin {
5620
7635
  : toString(
5621
7636
  fromString(
5622
7637
  publishedList.StatusList2021.encodedList,
5623
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
7638
+ publishedList.metadata.encoding as DefaultStatusListEncoding
5624
7639
  ),
5625
7640
  'base64url'
5626
7641
  );
@@ -5700,7 +7715,7 @@ export class Cheqd implements IAgentPlugin {
5700
7715
  const bitstring = (await statusList.encode()) as Bitstring;
5701
7716
 
5702
7717
  // cast top-level args
5703
- const topArgs = options?.topArgs as ICheqdSuspendCredentialWithStatusList2021Args;
7718
+ const topArgs = options?.topArgs as ICheqdSuspendCredentialWithStatusListArgs;
5704
7719
 
5705
7720
  // write status list 2021 to file, if provided
5706
7721
  if (topArgs?.writeToFile) {
@@ -5711,7 +7726,7 @@ export class Cheqd implements IAgentPlugin {
5711
7726
  const published = topArgs?.publish
5712
7727
  ? await (async function () {
5713
7728
  // fetch status list 2021 metadata
5714
- const statusListMetadata = await Cheqd.fetchStatusList2021Metadata(credential);
7729
+ const statusListMetadata = await Cheqd.fetchStatusListMetadata(credential);
5715
7730
 
5716
7731
  // publish status list 2021 as new version
5717
7732
  const scoped = topArgs.publishEncrypted
@@ -5719,7 +7734,7 @@ export class Cheqd implements IAgentPlugin {
5719
7734
  // validate encoding, if provided
5720
7735
  if (
5721
7736
  options?.publishOptions?.statusListEncoding &&
5722
- !Object.values(DefaultStatusList2021Encodings).includes(
7737
+ !Object.values(DefaultStatusListEncodings).includes(
5723
7738
  options?.publishOptions?.statusListEncoding
5724
7739
  )
5725
7740
  ) {
@@ -5916,7 +7931,7 @@ export class Cheqd implements IAgentPlugin {
5916
7931
  encrypted: true,
5917
7932
  encoding:
5918
7933
  (options?.publishOptions?.statusListEncoding as
5919
- | DefaultStatusList2021Encoding
7934
+ | DefaultStatusListEncoding
5920
7935
  | undefined) || publishedList.metadata.encoding,
5921
7936
  statusListHash:
5922
7937
  symmetricEncryptionStringHash === thresholdEncryptionStringHash
@@ -5949,7 +7964,7 @@ export class Cheqd implements IAgentPlugin {
5949
7964
  // validate encoding, if provided
5950
7965
  if (
5951
7966
  options?.publishOptions?.statusListEncoding &&
5952
- !Object.values(DefaultStatusList2021Encodings).includes(
7967
+ !Object.values(DefaultStatusListEncodings).includes(
5953
7968
  options?.publishOptions?.statusListEncoding
5954
7969
  )
5955
7970
  ) {
@@ -5998,7 +8013,7 @@ export class Cheqd implements IAgentPlugin {
5998
8013
  : toString(
5999
8014
  fromString(bitstring, 'base64url'),
6000
8015
  options!.publishOptions
6001
- .statusListEncoding as DefaultStatusList2021Encoding
8016
+ .statusListEncoding as DefaultStatusListEncoding
6002
8017
  ),
6003
8018
  validFrom: publishedList.StatusList2021.validFrom,
6004
8019
  validUntil:
@@ -6009,7 +8024,7 @@ export class Cheqd implements IAgentPlugin {
6009
8024
  type: publishedList.metadata.type,
6010
8025
  encoding:
6011
8026
  (options?.publishOptions?.statusListEncoding as
6012
- | DefaultStatusList2021Encoding
8027
+ | DefaultStatusListEncoding
6013
8028
  | undefined) || publishedList.metadata.encoding,
6014
8029
  encrypted: false,
6015
8030
  },
@@ -6045,7 +8060,7 @@ export class Cheqd implements IAgentPlugin {
6045
8060
  ? toString((published?.[1] as { symmetricKey: Uint8Array })?.symmetricKey, 'hex')
6046
8061
  : undefined,
6047
8062
  resourceMetadata: topArgs?.returnStatusListMetadata
6048
- ? await Cheqd.fetchStatusList2021Metadata(credential)
8063
+ ? await Cheqd.fetchStatusListMetadata(credential)
6049
8064
  : undefined,
6050
8065
  } satisfies UnsuspensionResult;
6051
8066
  } catch (error) {
@@ -6058,7 +8073,7 @@ export class Cheqd implements IAgentPlugin {
6058
8073
 
6059
8074
  static async unsuspendCredentials(
6060
8075
  credentials: VerifiableCredential[],
6061
- options?: ICheqdStatusList2021Options
8076
+ options?: ICheqdStatusListOptions
6062
8077
  ): Promise<BulkUnsuspensionResult> {
6063
8078
  // validate credentials - case: empty
6064
8079
  if (!credentials.length || credentials.length === 0)
@@ -6137,7 +8152,7 @@ export class Cheqd implements IAgentPlugin {
6137
8152
  : toString(
6138
8153
  fromString(
6139
8154
  publishedList.StatusList2021.encodedList,
6140
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
8155
+ publishedList.metadata.encoding as DefaultStatusListEncoding
6141
8156
  ),
6142
8157
  'base64url'
6143
8158
  );
@@ -6186,7 +8201,7 @@ export class Cheqd implements IAgentPlugin {
6186
8201
  : toString(
6187
8202
  fromString(
6188
8203
  publishedList.StatusList2021.encodedList,
6189
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
8204
+ publishedList.metadata.encoding as DefaultStatusListEncoding
6190
8205
  ),
6191
8206
  'base64url'
6192
8207
  );
@@ -6289,7 +8304,7 @@ export class Cheqd implements IAgentPlugin {
6289
8304
  const bitstring = (await statusList.encode()) as Bitstring;
6290
8305
 
6291
8306
  // cast top-level args
6292
- const topArgs = options?.topArgs as ICheqdRevokeCredentialWithStatusList2021Args;
8307
+ const topArgs = options?.topArgs as ICheqdRevokeCredentialWithStatusListArgs;
6293
8308
 
6294
8309
  // write status list 2021 to file, if provided
6295
8310
  if (topArgs?.writeToFile) {
@@ -6300,7 +8315,7 @@ export class Cheqd implements IAgentPlugin {
6300
8315
  const published = topArgs?.publish
6301
8316
  ? await (async function () {
6302
8317
  // fetch status list 2021 metadata
6303
- const statusListMetadata = await Cheqd.fetchStatusList2021Metadata(credentials[0]);
8318
+ const statusListMetadata = await Cheqd.fetchStatusListMetadata(credentials[0]);
6304
8319
 
6305
8320
  // publish status list 2021 as new version
6306
8321
  const scoped = topArgs.publishEncrypted
@@ -6308,7 +8323,7 @@ export class Cheqd implements IAgentPlugin {
6308
8323
  // validate encoding, if provided
6309
8324
  if (
6310
8325
  options?.publishOptions?.statusListEncoding &&
6311
- !Object.values(DefaultStatusList2021Encodings).includes(
8326
+ !Object.values(DefaultStatusListEncodings).includes(
6312
8327
  options?.publishOptions?.statusListEncoding
6313
8328
  )
6314
8329
  ) {
@@ -6505,7 +8520,7 @@ export class Cheqd implements IAgentPlugin {
6505
8520
  encrypted: true,
6506
8521
  encoding:
6507
8522
  (options?.publishOptions?.statusListEncoding as
6508
- | DefaultStatusList2021Encoding
8523
+ | DefaultStatusListEncoding
6509
8524
  | undefined) || publishedList.metadata.encoding,
6510
8525
  statusListHash:
6511
8526
  symmetricEncryptionStringHash === thresholdEncryptionStringHash
@@ -6538,7 +8553,7 @@ export class Cheqd implements IAgentPlugin {
6538
8553
  // validate encoding, if provided
6539
8554
  if (
6540
8555
  options?.publishOptions?.statusListEncoding &&
6541
- !Object.values(DefaultStatusList2021Encodings).includes(
8556
+ !Object.values(DefaultStatusListEncodings).includes(
6542
8557
  options?.publishOptions?.statusListEncoding
6543
8558
  )
6544
8559
  ) {
@@ -6587,7 +8602,7 @@ export class Cheqd implements IAgentPlugin {
6587
8602
  : toString(
6588
8603
  fromString(bitstring, 'base64url'),
6589
8604
  options!.publishOptions
6590
- .statusListEncoding as DefaultStatusList2021Encoding
8605
+ .statusListEncoding as DefaultStatusListEncoding
6591
8606
  ),
6592
8607
  validFrom: publishedList.StatusList2021.validFrom,
6593
8608
  validUntil:
@@ -6598,7 +8613,7 @@ export class Cheqd implements IAgentPlugin {
6598
8613
  type: publishedList.metadata.type,
6599
8614
  encoding:
6600
8615
  (options?.publishOptions?.statusListEncoding as
6601
- | DefaultStatusList2021Encoding
8616
+ | DefaultStatusListEncoding
6602
8617
  | undefined) || publishedList.metadata.encoding,
6603
8618
  encrypted: false,
6604
8619
  },
@@ -6636,7 +8651,7 @@ export class Cheqd implements IAgentPlugin {
6636
8651
  ? toString((published?.[1] as { symmetricKey: Uint8Array })?.symmetricKey, 'hex')
6637
8652
  : undefined,
6638
8653
  resourceMetadata: topArgs?.returnStatusListMetadata
6639
- ? await Cheqd.fetchStatusList2021Metadata(credentials[0])
8654
+ ? await Cheqd.fetchStatusListMetadata(credentials[0])
6640
8655
  : undefined,
6641
8656
  } satisfies BulkUnsuspensionResult;
6642
8657
  } catch (error) {
@@ -6649,7 +8664,7 @@ export class Cheqd implements IAgentPlugin {
6649
8664
 
6650
8665
  static async checkRevoked(
6651
8666
  credential: VerifiableCredential,
6652
- options: ICheqdStatusList2021Options = { fetchList: true }
8667
+ options: ICheqdStatusListOptions = { fetchList: true }
6653
8668
  ): Promise<boolean> {
6654
8669
  // validate status purpose
6655
8670
  if (credential.credentialStatus?.statusPurpose !== DefaultStatusList2021StatusPurposeTypes.revocation) {
@@ -6684,7 +8699,7 @@ export class Cheqd implements IAgentPlugin {
6684
8699
  : toString(
6685
8700
  fromString(
6686
8701
  publishedList.StatusList2021.encodedList,
6687
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
8702
+ publishedList.metadata.encoding as DefaultStatusListEncoding
6688
8703
  ),
6689
8704
  'base64url'
6690
8705
  );
@@ -6742,7 +8757,7 @@ export class Cheqd implements IAgentPlugin {
6742
8757
  : toString(
6743
8758
  fromString(
6744
8759
  publishedList.StatusList2021.encodedList,
6745
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
8760
+ publishedList.metadata.encoding as DefaultStatusListEncoding
6746
8761
  ),
6747
8762
  'base64url'
6748
8763
  );
@@ -6813,7 +8828,7 @@ export class Cheqd implements IAgentPlugin {
6813
8828
  publishedList.metadata.encoding === 'base64url'
6814
8829
  ? statusList2021
6815
8830
  : toString(
6816
- fromString(statusList2021, publishedList.metadata.encoding as DefaultStatusList2021Encoding),
8831
+ fromString(statusList2021, publishedList.metadata.encoding as DefaultStatusListEncoding),
6817
8832
  'base64url'
6818
8833
  );
6819
8834
 
@@ -6826,7 +8841,7 @@ export class Cheqd implements IAgentPlugin {
6826
8841
 
6827
8842
  static async checkSuspended(
6828
8843
  credential: VerifiableCredential,
6829
- options: ICheqdStatusList2021Options = { fetchList: true }
8844
+ options: ICheqdStatusListOptions = { fetchList: true }
6830
8845
  ): Promise<boolean> {
6831
8846
  // validate status purpose
6832
8847
  if (credential.credentialStatus?.statusPurpose !== DefaultStatusList2021StatusPurposeTypes.suspension) {
@@ -6861,7 +8876,7 @@ export class Cheqd implements IAgentPlugin {
6861
8876
  : toString(
6862
8877
  fromString(
6863
8878
  publishedList.StatusList2021.encodedList,
6864
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
8879
+ publishedList.metadata.encoding as DefaultStatusListEncoding
6865
8880
  ),
6866
8881
  'base64url'
6867
8882
  );
@@ -6915,7 +8930,7 @@ export class Cheqd implements IAgentPlugin {
6915
8930
  : toString(
6916
8931
  fromString(
6917
8932
  publishedList.StatusList2021.encodedList,
6918
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
8933
+ publishedList.metadata.encoding as DefaultStatusListEncoding
6919
8934
  ),
6920
8935
  'base64url'
6921
8936
  );
@@ -6991,7 +9006,7 @@ export class Cheqd implements IAgentPlugin {
6991
9006
  private static async checkRevokedNonMigrated(
6992
9007
  credential: VerifiableCredential,
6993
9008
  associatedStatusList?: StatusList2021RevocationNonMigrated,
6994
- options: ICheqdStatusList2021Options = { fetchList: true }
9009
+ options: ICheqdStatusListOptions = { fetchList: true }
6995
9010
  ): Promise<boolean> {
6996
9011
  // validate status purpose
6997
9012
  if (credential.credentialStatus?.statusPurpose !== DefaultStatusList2021StatusPurposeTypes.revocation) {
@@ -7019,7 +9034,7 @@ export class Cheqd implements IAgentPlugin {
7019
9034
  : toString(
7020
9035
  fromString(
7021
9036
  publishedList.StatusList2021.encodedList,
7022
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
9037
+ publishedList.metadata.encoding as DefaultStatusListEncoding
7023
9038
  ),
7024
9039
  'base64url'
7025
9040
  );
@@ -7072,7 +9087,7 @@ export class Cheqd implements IAgentPlugin {
7072
9087
  : toString(
7073
9088
  fromString(
7074
9089
  publishedList.StatusList2021.encodedList,
7075
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
9090
+ publishedList.metadata.encoding as DefaultStatusListEncoding
7076
9091
  ),
7077
9092
  'base64url'
7078
9093
  );
@@ -7135,7 +9150,7 @@ export class Cheqd implements IAgentPlugin {
7135
9150
  publishedList.metadata.encoding === 'base64url'
7136
9151
  ? statusList2021
7137
9152
  : toString(
7138
- fromString(statusList2021, publishedList.metadata.encoding as DefaultStatusList2021Encoding),
9153
+ fromString(statusList2021, publishedList.metadata.encoding as DefaultStatusListEncoding),
7139
9154
  'base64url'
7140
9155
  );
7141
9156
 
@@ -7149,7 +9164,7 @@ export class Cheqd implements IAgentPlugin {
7149
9164
  private static async checkSuspendedNonMigrated(
7150
9165
  credential: VerifiableCredential,
7151
9166
  associatedStatusList?: StatusList2021SuspensionNonMigrated,
7152
- options: ICheqdStatusList2021Options = { fetchList: true }
9167
+ options: ICheqdStatusListOptions = { fetchList: true }
7153
9168
  ): Promise<boolean> {
7154
9169
  // validate status purpose
7155
9170
  if (credential.credentialStatus?.statusPurpose !== DefaultStatusList2021StatusPurposeTypes.suspension) {
@@ -7177,7 +9192,7 @@ export class Cheqd implements IAgentPlugin {
7177
9192
  : toString(
7178
9193
  fromString(
7179
9194
  publishedList.StatusList2021.encodedList,
7180
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
9195
+ publishedList.metadata.encoding as DefaultStatusListEncoding
7181
9196
  ),
7182
9197
  'base64url'
7183
9198
  );
@@ -7230,7 +9245,7 @@ export class Cheqd implements IAgentPlugin {
7230
9245
  : toString(
7231
9246
  fromString(
7232
9247
  publishedList.StatusList2021.encodedList,
7233
- publishedList.metadata.encoding as DefaultStatusList2021Encoding
9248
+ publishedList.metadata.encoding as DefaultStatusListEncoding
7234
9249
  ),
7235
9250
  'base64url'
7236
9251
  );
@@ -7375,7 +9390,7 @@ export class Cheqd implements IAgentPlugin {
7375
9390
  if (returnRaw) {
7376
9391
  return fromString(
7377
9392
  content.StatusList2021.encodedList,
7378
- content.metadata.encoding as DefaultStatusList2021Encoding
9393
+ content.metadata.encoding as DefaultStatusListEncoding
7379
9394
  );
7380
9395
  }
7381
9396
 
@@ -7383,7 +9398,7 @@ export class Cheqd implements IAgentPlugin {
7383
9398
  return content;
7384
9399
  }
7385
9400
 
7386
- static async fetchStatusList2021Metadata(
9401
+ static async fetchStatusListMetadata(
7387
9402
  credential: VerifiableCredential
7388
9403
  ): Promise<LinkedResourceMetadataResolutionResult> {
7389
9404
  // get base url
@@ -7434,6 +9449,28 @@ export class Cheqd implements IAgentPlugin {
7434
9449
  resourceVersioning.sort((a, b) => new Date(b.created).getTime() - new Date(a.created).getTime())[0]
7435
9450
  );
7436
9451
  }
9452
+ /**
9453
+ * Fetch the JSON metadata from a bitstring status list credential URL
9454
+ */
9455
+ static async fetchBitstringStatusList(credential: VerifiableCredential): Promise<BitstringStatusList> {
9456
+ // get base url
9457
+ const baseUrl = new URL(credential.credentialStatus!.id.split('#')[0]);
9458
+ // fetch collection metadata
9459
+ const response = await fetch(baseUrl, {
9460
+ method: 'GET',
9461
+ headers: {
9462
+ Accept: 'application/json',
9463
+ 'Content-Type': 'application/json',
9464
+ },
9465
+ });
9466
+ if (!response.ok) {
9467
+ throw new Error(
9468
+ `[did-provider-cheqd]: Bitstring Status List retrieval error ${response.status}: ${response.statusText}`
9469
+ );
9470
+ }
9471
+ const data: BitstringStatusList = await response.json();
9472
+ return data;
9473
+ }
7437
9474
 
7438
9475
  static async getProviderFromDidUrl(
7439
9476
  didUrl: string,
@@ -7525,6 +9562,22 @@ export class Cheqd implements IAgentPlugin {
7525
9562
  return {
7526
9563
  ...decodedCredential.payload.vc,
7527
9564
  issuer: decodedCredential.payload.iss,
7528
- } satisfies VerifiableCredential;
9565
+ } satisfies VerifiableCredential | BitstringStatusListCredential;
9566
+ }
9567
+ static getBitValue(bitstring: DBBitstring, bitIndex: number, statusSize = 1): number {
9568
+ let value = 0;
9569
+ for (let i = 0; i < statusSize; i++) {
9570
+ const bit = bitstring.get(bitIndex + i);
9571
+ value |= bit << i;
9572
+ }
9573
+ return value;
9574
+ }
9575
+ // Helper function to set bit values in a bitstring (2-bit values)
9576
+ static setBitValue(bitstring: DBBitstring, bitIndex: number, value: number, statusSize: number = 2): void {
9577
+ for (let i = 0; i < statusSize; i++) {
9578
+ const bit = (value >> i) & 1;
9579
+ bitstring.set(bitIndex + i, bit === 1);
9580
+ }
7529
9581
  }
7530
9582
  }
9583
+ export { BitstringStatusListResourceType, DefaultStatusListEncodings };