@sphereon/ssi-sdk.vc-status-list 0.34.1-feature.SSISDK.17.bitstring.sl.8 → 0.34.1-feature.SSISDK.26.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ var Status2021 = /* @__PURE__ */ function(Status20212) {
15
15
  }({});
16
16
 
17
17
  // src/functions.ts
18
- import { CredentialMapper as CredentialMapper4, DocumentFormat as DocumentFormat4, StatusListType as StatusListType6 } from "@sphereon/ssi-types";
18
+ import { CredentialMapper as CredentialMapper4, StatusListType as StatusListType6 } from "@sphereon/ssi-types";
19
19
  import { checkStatus } from "@sphereon/vc-status-list";
20
20
 
21
21
  // src/utils.ts
@@ -76,7 +76,8 @@ var ValidProofTypeMap = /* @__PURE__ */ new Map([
76
76
  [
77
77
  StatusListType.BitstringStatusList,
78
78
  [
79
- "lds"
79
+ "lds",
80
+ "vc+jwt"
80
81
  ]
81
82
  ]
82
83
  ]);
@@ -91,29 +92,50 @@ function determineStatusListType(credential) {
91
92
  const proofFormat = determineProofFormat(credential);
92
93
  switch (proofFormat) {
93
94
  case "jwt":
94
- const payload = jwtDecode(credential);
95
- const keys = Object.keys(payload);
96
- if (keys.includes("status_list")) {
97
- return StatusListType.OAuthStatusList;
98
- } else if (keys.includes("vc")) {
99
- return StatusListType.StatusList2021;
100
- }
101
- break;
95
+ return determineJwtStatusListType(credential);
102
96
  case "lds":
103
- const uniform = CredentialMapper.toUniformCredential(credential);
104
- const type = uniform.type.find((t) => {
105
- return Object.values(StatusListType).some((statusType) => t.includes(statusType));
106
- });
107
- if (!type) {
108
- throw new Error("Invalid status list credential type");
109
- }
110
- return type.replace("Credential", "");
97
+ return determineLdsStatusListType(credential);
111
98
  case "cbor":
112
99
  return StatusListType.OAuthStatusList;
100
+ default:
101
+ throw new Error("Cannot determine status list type from credential payload");
113
102
  }
114
- throw new Error("Cannot determine status list type from credential payload");
115
103
  }
116
104
  __name(determineStatusListType, "determineStatusListType");
105
+ function determineJwtStatusListType(credential) {
106
+ const payload = jwtDecode(credential);
107
+ if ("status_list" in payload) {
108
+ return StatusListType.OAuthStatusList;
109
+ }
110
+ if ("credentialSubject" in payload) {
111
+ return getStatusListTypeFromSubject(payload.credentialSubject);
112
+ }
113
+ if ("vc" in payload && "credentialSubject" in payload.vc) {
114
+ return getStatusListTypeFromSubject(payload.vc.credentialSubject);
115
+ }
116
+ throw new Error("Invalid status list credential: credentialSubject not found");
117
+ }
118
+ __name(determineJwtStatusListType, "determineJwtStatusListType");
119
+ function determineLdsStatusListType(credential) {
120
+ const uniform = CredentialMapper.toUniformCredential(credential);
121
+ const statusListType = uniform.type.find((type) => Object.values(StatusListType).some((statusType) => type.includes(statusType)));
122
+ if (!statusListType) {
123
+ throw new Error("Invalid status list credential type");
124
+ }
125
+ return statusListType.replace("Credential", "");
126
+ }
127
+ __name(determineLdsStatusListType, "determineLdsStatusListType");
128
+ function getStatusListTypeFromSubject(credentialSubject) {
129
+ switch (credentialSubject.type) {
130
+ case "StatusList2021":
131
+ return StatusListType.StatusList2021;
132
+ case "BitstringStatusList":
133
+ return StatusListType.BitstringStatusList;
134
+ default:
135
+ throw new Error(`Unknown credential subject type: ${credentialSubject.type}`);
136
+ }
137
+ }
138
+ __name(getStatusListTypeFromSubject, "getStatusListTypeFromSubject");
117
139
  function determineProofFormat(credential) {
118
140
  const type = CredentialMapper.detectDocumentType(credential);
119
141
  switch (type) {
@@ -128,6 +150,26 @@ function determineProofFormat(credential) {
128
150
  }
129
151
  }
130
152
  __name(determineProofFormat, "determineProofFormat");
153
+ function ensureDate(value) {
154
+ if (value === void 0 || value === null) {
155
+ return void 0;
156
+ }
157
+ if (value instanceof Date) {
158
+ return value;
159
+ }
160
+ if (typeof value === "string") {
161
+ if (value.trim() === "") {
162
+ return void 0;
163
+ }
164
+ const date = new Date(value);
165
+ if (isNaN(date.getTime())) {
166
+ return void 0;
167
+ }
168
+ return date;
169
+ }
170
+ return void 0;
171
+ }
172
+ __name(ensureDate, "ensureDate");
131
173
 
132
174
  // src/impl/StatusList2021.ts
133
175
  import { CredentialMapper as CredentialMapper2, DocumentFormat as DocumentFormat2, StatusListType as StatusListType2 } from "@sphereon/ssi-types";
@@ -191,13 +233,14 @@ var StatusList2021Implementation = class {
191
233
  encodedList,
192
234
  proofFormat
193
235
  }, context);
236
+ if (!("statusPurpose" in credentialSubject)) {
237
+ return Promise.reject(Error("statusPurpose is required in credentialSubject for StatusList2021"));
238
+ }
194
239
  return {
195
240
  statusListCredential: updatedCredential,
196
241
  encodedList,
197
242
  statusList2021: {
198
- ..."statusPurpose" in credentialSubject ? {
199
- statusPurpose: credentialSubject.statusPurpose
200
- } : {},
243
+ statusPurpose: credentialSubject.statusPurpose,
201
244
  indexingDirection: "rightToLeft"
202
245
  },
203
246
  length: statusList.length - 1,
@@ -254,36 +297,88 @@ var StatusList2021Implementation = class {
254
297
  const status = statusList.getStatus(typeof args.statusListIndex === "number" ? args.statusListIndex : parseInt(args.statusListIndex));
255
298
  return status ? Status2021.Invalid : Status2021.Valid;
256
299
  }
257
- async toStatusListDetails(args) {
258
- const { statusListPayload } = args;
259
- const uniform = CredentialMapper2.toUniformCredential(statusListPayload);
300
+ /**
301
+ * Performs the initial parsing of a StatusListCredential.
302
+ * This method handles expensive operations like JWT/CWT decoding once.
303
+ * It extracts all details available from the credential payload itself.
304
+ */
305
+ async extractCredentialDetails(credential) {
306
+ const uniform = CredentialMapper2.toUniformCredential(credential);
260
307
  const { issuer, credentialSubject } = uniform;
261
- const id = getAssertedValue("id", uniform.id);
262
- const encodedList = getAssertedProperty("encodedList", credentialSubject);
263
- const proofFormat = CredentialMapper2.detectDocumentType(statusListPayload) === DocumentFormat2.JWT ? "jwt" : "lds";
264
- const statusPurpose = getAssertedProperty("statusPurpose", credentialSubject);
265
- const list = await StatusList.decode({
266
- encodedList
267
- });
308
+ const subject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject;
268
309
  return {
269
- id,
270
- encodedList,
310
+ id: getAssertedValue("id", uniform.id),
271
311
  issuer,
272
- type: StatusListType2.StatusList2021,
273
- proofFormat,
274
- length: list.length,
275
- statusListCredential: statusListPayload,
276
- statuslistContentType: this.buildContentType(proofFormat),
277
- statusList2021: {
312
+ encodedList: getAssertedProperty("encodedList", subject)
313
+ };
314
+ }
315
+ async toStatusListDetails(args) {
316
+ if ("statusListCredential" in args) {
317
+ const { statusListCredential, correlationId, driverType } = args;
318
+ const uniform = CredentialMapper2.toUniformCredential(statusListCredential);
319
+ const { issuer, credentialSubject } = uniform;
320
+ const subject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject;
321
+ const id = getAssertedValue("id", uniform.id);
322
+ const encodedList = getAssertedProperty("encodedList", subject);
323
+ const statusPurpose = getAssertedProperty("statusPurpose", subject);
324
+ const proofFormat = CredentialMapper2.detectDocumentType(statusListCredential) === DocumentFormat2.JWT ? "jwt" : "lds";
325
+ const list = await StatusList.decode({
326
+ encodedList
327
+ });
328
+ return {
329
+ id,
330
+ encodedList,
331
+ issuer,
332
+ type: StatusListType2.StatusList2021,
333
+ proofFormat,
334
+ length: list.length,
335
+ statusListCredential,
336
+ statuslistContentType: this.buildContentType(proofFormat),
337
+ correlationId,
338
+ driverType,
278
339
  indexingDirection: "rightToLeft",
279
- statusPurpose
280
- },
281
- ...args.correlationId && {
282
- correlationId: args.correlationId
283
- },
284
- ...args.driverType && {
285
- driverType: args.driverType
286
- }
340
+ statusPurpose,
341
+ statusList2021: {
342
+ indexingDirection: "rightToLeft",
343
+ statusPurpose
344
+ }
345
+ };
346
+ } else {
347
+ const { extractedDetails, statusListEntity } = args;
348
+ const statusList2021Entity = statusListEntity;
349
+ const proofFormat = CredentialMapper2.detectDocumentType(statusListEntity.statusListCredential) === DocumentFormat2.JWT ? "jwt" : "lds";
350
+ const list = await StatusList.decode({
351
+ encodedList: extractedDetails.encodedList
352
+ });
353
+ return {
354
+ id: extractedDetails.id,
355
+ encodedList: extractedDetails.encodedList,
356
+ issuer: extractedDetails.issuer,
357
+ type: StatusListType2.StatusList2021,
358
+ proofFormat,
359
+ length: list.length,
360
+ statusListCredential: statusListEntity.statusListCredential,
361
+ statuslistContentType: this.buildContentType(proofFormat),
362
+ correlationId: statusListEntity.correlationId,
363
+ driverType: statusListEntity.driverType,
364
+ indexingDirection: statusList2021Entity.indexingDirection,
365
+ statusPurpose: statusList2021Entity.statusPurpose,
366
+ statusList2021: {
367
+ indexingDirection: statusList2021Entity.indexingDirection,
368
+ statusPurpose: statusList2021Entity.statusPurpose
369
+ }
370
+ };
371
+ }
372
+ }
373
+ async createCredentialStatus(args) {
374
+ const { statusList, statusListIndex } = args;
375
+ const statusList2021 = statusList;
376
+ return {
377
+ id: `${statusList.id}#${statusListIndex}`,
378
+ type: "StatusList2021Entry",
379
+ statusPurpose: statusList2021.statusPurpose ?? "revocation",
380
+ statusListIndex: "" + statusListIndex,
381
+ statusListCredential: statusList.id
287
382
  };
288
383
  }
289
384
  async createVerifiableCredential(args, context) {
@@ -578,7 +673,8 @@ var OAuthStatusListImplementation = class {
578
673
  }
579
674
  const proofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT2;
580
675
  const { issuer, id, oauthStatusList, keyRef } = args;
581
- const { bitsPerStatus, expiresAt } = oauthStatusList;
676
+ const { bitsPerStatus } = oauthStatusList;
677
+ const expiresAt = ensureDate(oauthStatusList.expiresAt);
582
678
  const length = args.length ?? DEFAULT_LIST_LENGTH2;
583
679
  const issuerString = typeof issuer === "string" ? issuer : issuer.id;
584
680
  const correlationId = getAssertedValue("correlationId", args.correlationId);
@@ -601,7 +697,8 @@ var OAuthStatusListImplementation = class {
601
697
  };
602
698
  }
603
699
  async updateStatusListIndex(args, context) {
604
- const { statusListCredential, value, expiresAt, keyRef } = args;
700
+ const { statusListCredential, value, keyRef } = args;
701
+ const expiresAt = ensureDate(args.expiresAt);
605
702
  if (typeof statusListCredential !== "string") {
606
703
  return Promise.reject("statusListCredential in neither JWT nor CWT");
607
704
  }
@@ -637,7 +734,8 @@ var OAuthStatusListImplementation = class {
637
734
  throw new Error("OAuthStatusList options are required for type OAuthStatusList");
638
735
  }
639
736
  const { proofFormat, oauthStatusList, keyRef } = args;
640
- const { bitsPerStatus, expiresAt } = oauthStatusList;
737
+ const { bitsPerStatus } = oauthStatusList;
738
+ const expiresAt = ensureDate(oauthStatusList.expiresAt);
641
739
  const { issuer, id } = getAssertedValues(args);
642
740
  const issuerString = typeof issuer === "string" ? issuer : issuer.id;
643
741
  const listToUpdate = StatusList4.decompressStatusList(args.encodedList, bitsPerStatus ?? DEFAULT_BITS_PER_STATUS);
@@ -659,9 +757,6 @@ var OAuthStatusListImplementation = class {
659
757
  statuslistContentType: this.buildContentType(proofFormat)
660
758
  };
661
759
  }
662
- buildContentType(proofFormat) {
663
- return `application/statuslist+${proofFormat === "cbor" ? "cwt" : "jwt"}`;
664
- }
665
760
  async checkStatusIndex(args) {
666
761
  const { statusListCredential, statusListIndex } = args;
667
762
  if (typeof statusListCredential !== "string") {
@@ -675,34 +770,101 @@ var OAuthStatusListImplementation = class {
675
770
  }
676
771
  return statusList.getStatus(index);
677
772
  }
678
- async toStatusListDetails(args) {
679
- const { statusListPayload } = args;
680
- const proofFormat = determineProofFormat(statusListPayload);
681
- const decoded = proofFormat === "jwt" ? decodeStatusListJWT(statusListPayload) : decodeStatusListCWT(statusListPayload);
682
- const { statusList, issuer, id, exp } = decoded;
773
+ /**
774
+ * Performs the initial parsing of a StatusListCredential.
775
+ * This method handles expensive operations like JWT/CWT decoding once.
776
+ * It extracts all details available from the credential payload itself.
777
+ */
778
+ async extractCredentialDetails(credential) {
779
+ if (typeof credential !== "string") {
780
+ return Promise.reject("statusListCredential must be a JWT or CWT string");
781
+ }
782
+ const proofFormat = determineProofFormat(credential);
783
+ const decoded = proofFormat === "jwt" ? decodeStatusListJWT(credential) : decodeStatusListCWT(credential);
683
784
  return {
684
- id,
685
- encodedList: statusList.compressStatusList(),
686
- issuer,
687
- type: StatusListType3.OAuthStatusList,
688
- proofFormat,
689
- length: statusList.statusList.length,
690
- statusListCredential: statusListPayload,
691
- statuslistContentType: this.buildContentType(proofFormat),
692
- oauthStatusList: {
693
- bitsPerStatus: statusList.getBitsPerStatus(),
694
- ...exp && {
695
- expiresAt: new Date(exp * 1e3)
696
- }
697
- },
698
- ...args.correlationId && {
699
- correlationId: args.correlationId
700
- },
701
- ...args.driverType && {
702
- driverType: args.driverType
785
+ id: decoded.id,
786
+ issuer: decoded.issuer,
787
+ encodedList: decoded.statusList.compressStatusList(),
788
+ decodedPayload: decoded
789
+ };
790
+ }
791
+ async toStatusListDetails(args) {
792
+ if ("statusListCredential" in args) {
793
+ const { statusListCredential, bitsPerStatus, correlationId, driverType } = args;
794
+ if (!bitsPerStatus || bitsPerStatus < 1) {
795
+ return Promise.reject(Error("bitsPerStatus must be set for OAuth status lists and must be 1 or higher"));
703
796
  }
797
+ const proofFormat = determineProofFormat(statusListCredential);
798
+ const decoded = proofFormat === "jwt" ? decodeStatusListJWT(statusListCredential) : decodeStatusListCWT(statusListCredential);
799
+ const { statusList, issuer, id, exp } = decoded;
800
+ const expiresAt = exp ? new Date(exp * 1e3) : void 0;
801
+ return {
802
+ id,
803
+ encodedList: statusList.compressStatusList(),
804
+ issuer,
805
+ type: StatusListType3.OAuthStatusList,
806
+ proofFormat,
807
+ length: statusList.statusList.length,
808
+ statusListCredential,
809
+ statuslistContentType: this.buildContentType(proofFormat),
810
+ correlationId,
811
+ driverType,
812
+ bitsPerStatus,
813
+ ...expiresAt && {
814
+ expiresAt
815
+ },
816
+ oauthStatusList: {
817
+ bitsPerStatus,
818
+ ...expiresAt && {
819
+ expiresAt
820
+ }
821
+ }
822
+ };
823
+ } else {
824
+ const { extractedDetails, statusListEntity } = args;
825
+ const oauthEntity = statusListEntity;
826
+ const decoded = extractedDetails.decodedPayload;
827
+ const proofFormat = determineProofFormat(statusListEntity.statusListCredential);
828
+ const expiresAt = decoded.exp ? new Date(decoded.exp * 1e3) : void 0;
829
+ return {
830
+ id: extractedDetails.id,
831
+ encodedList: extractedDetails.encodedList,
832
+ issuer: extractedDetails.issuer,
833
+ type: StatusListType3.OAuthStatusList,
834
+ proofFormat,
835
+ length: decoded.statusList.statusList.length,
836
+ statusListCredential: statusListEntity.statusListCredential,
837
+ statuslistContentType: this.buildContentType(proofFormat),
838
+ correlationId: statusListEntity.correlationId,
839
+ driverType: statusListEntity.driverType,
840
+ bitsPerStatus: oauthEntity.bitsPerStatus,
841
+ ...expiresAt && {
842
+ expiresAt
843
+ },
844
+ oauthStatusList: {
845
+ bitsPerStatus: oauthEntity.bitsPerStatus,
846
+ ...expiresAt && {
847
+ expiresAt
848
+ }
849
+ }
850
+ };
851
+ }
852
+ }
853
+ async createCredentialStatus(args) {
854
+ const { statusList, statusListIndex } = args;
855
+ const oauthStatusList = statusList;
856
+ return {
857
+ id: `${statusList.id}#${statusListIndex}`,
858
+ type: "OAuthStatusListEntry",
859
+ bitsPerStatus: oauthStatusList.bitsPerStatus,
860
+ statusListIndex: "" + statusListIndex,
861
+ statusListCredential: statusList.id,
862
+ expiresAt: oauthStatusList.expiresAt
704
863
  };
705
864
  }
865
+ buildContentType(proofFormat) {
866
+ return `application/statuslist+${proofFormat === "cbor" ? "cwt" : "jwt"}`;
867
+ }
706
868
  async createSignedStatusList(proofFormat, context, statusList, issuerString, id, expiresAt, keyRef) {
707
869
  switch (proofFormat) {
708
870
  case "jwt": {
@@ -724,12 +886,19 @@ import { StatusListType as StatusListType5 } from "@sphereon/ssi-types";
724
886
  import { CredentialMapper as CredentialMapper3, DocumentFormat as DocumentFormat3, StatusListType as StatusListType4 } from "@sphereon/ssi-types";
725
887
  import { BitstreamStatusList, createStatusListCredential } from "@4sure-tech/vc-bitstring-status-lists";
726
888
  var DEFAULT_LIST_LENGTH3 = 131072;
727
- var DEFAULT_PROOF_FORMAT3 = "lds";
889
+ var DEFAULT_PROOF_FORMAT3 = "vc+jwt";
728
890
  var DEFAULT_STATUS_PURPOSE = "revocation";
729
891
  var BitstringStatusListImplementation = class {
730
892
  static {
731
893
  __name(this, "BitstringStatusListImplementation");
732
894
  }
895
+ /**
896
+ * Creates a new bitstring status list with the specified configuration
897
+ *
898
+ * @param args - Configuration for the new status list including issuer, purpose, and size
899
+ * @param context - Veramo agent context for credential operations
900
+ * @returns Promise resolving to the created status list details
901
+ */
733
902
  async createNewStatusList(args, context) {
734
903
  if (!args.bitstringStatusList) {
735
904
  throw new Error("BitstringStatusList options are required for type BitstringStatusList");
@@ -737,28 +906,34 @@ var BitstringStatusListImplementation = class {
737
906
  const length = args?.length ?? DEFAULT_LIST_LENGTH3;
738
907
  const proofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT3;
739
908
  assertValidProofType(StatusListType4.BitstringStatusList, proofFormat);
740
- const veramoProofFormat = proofFormat;
741
909
  const { issuer, id } = args;
742
910
  const correlationId = getAssertedValue("correlationId", args.correlationId);
743
911
  const { statusPurpose, bitsPerStatus, validFrom, validUntil, ttl } = args.bitstringStatusList;
744
- const statusListCredential = await this.createVerifiableCredential({
745
- ...args,
746
- proofFormat: veramoProofFormat,
912
+ const unsignedCredential = await createStatusListCredential({
913
+ id,
914
+ issuer,
747
915
  statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
748
- validFrom,
749
- validUntil,
916
+ validFrom: ensureDate(validFrom),
917
+ validUntil: ensureDate(validUntil),
750
918
  ttl
919
+ });
920
+ const statusListCredential = await this.createVerifiableCredential({
921
+ unsignedCredential,
922
+ id,
923
+ issuer,
924
+ proofFormat,
925
+ keyRef: args.keyRef
751
926
  }, context);
752
927
  return {
753
- encodedList: statusListCredential.credentialSubject.encodedList,
928
+ encodedList: unsignedCredential.credentialSubject.encodedList,
754
929
  statusListCredential,
755
930
  bitstringStatusList: {
756
931
  statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
757
- ...statusListCredential.validFrom && {
758
- validFrom: new Date(statusListCredential.validFrom)
932
+ ...unsignedCredential.validFrom && {
933
+ validFrom: new Date(unsignedCredential.validFrom)
759
934
  },
760
- ...statusListCredential.validUntil && {
761
- validUntil: new Date(statusListCredential.validUntil)
935
+ ...unsignedCredential.validUntil && {
936
+ validUntil: new Date(unsignedCredential.validUntil)
762
937
  },
763
938
  ttl,
764
939
  bitsPerStatus
@@ -772,9 +947,16 @@ var BitstringStatusListImplementation = class {
772
947
  statuslistContentType: this.buildContentType(proofFormat)
773
948
  };
774
949
  }
950
+ /**
951
+ * Updates the status of a specific credential in an existing status list
952
+ *
953
+ * @param args - Update parameters including the status list credential, index, and new value
954
+ * @param context - Veramo agent context for credential operations
955
+ * @returns Promise resolving to the updated status list details
956
+ */
775
957
  async updateStatusListIndex(args, context) {
776
958
  if (!args.bitsPerStatus || args.bitsPerStatus < 1) {
777
- return Promise.reject("bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (updateStatusListIndex)");
959
+ return Promise.reject(Error("bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (updateStatusListIndex)"));
778
960
  }
779
961
  const credential = args.statusListCredential;
780
962
  const uniform = CredentialMapper3.toUniformCredential(credential);
@@ -786,34 +968,40 @@ var BitstringStatusListImplementation = class {
786
968
  encodedList: origEncodedList,
787
969
  statusSize: args.bitsPerStatus
788
970
  });
789
- statusList.setStatus(index, args.value);
790
- const proofFormat = CredentialMapper3.detectDocumentType(credential) === DocumentFormat3.JWT ? "jwt" : "lds";
971
+ const bitstringStatusId = args.value;
972
+ statusList.setStatus(index, bitstringStatusId);
973
+ const proofFormat = CredentialMapper3.detectDocumentType(credential) === DocumentFormat3.JWT ? "vc+jwt" : "lds";
791
974
  const credSubject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject;
792
975
  const statusPurpose = getAssertedProperty("statusPurpose", credSubject);
793
976
  const validFrom = uniform.validFrom ? new Date(uniform.validFrom) : void 0;
794
977
  const validUntil = uniform.validUntil ? new Date(uniform.validUntil) : void 0;
795
978
  const ttl = credSubject.ttl;
796
- const updatedCredential = await this.createVerifiableCredential({
797
- ...args,
979
+ const unsignedCredential = await createStatusListCredential({
798
980
  id,
799
981
  issuer,
800
982
  statusList,
983
+ statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
984
+ validFrom: ensureDate(validFrom),
985
+ validUntil: ensureDate(validUntil),
986
+ ttl
987
+ });
988
+ const updatedCredential = await this.createVerifiableCredential({
989
+ unsignedCredential,
990
+ id,
991
+ issuer,
801
992
  proofFormat,
802
- statusPurpose,
803
- ttl,
804
- validFrom,
805
- validUntil
993
+ keyRef: args.keyRef
806
994
  }, context);
807
995
  return {
808
996
  statusListCredential: updatedCredential,
809
- encodedList: updatedCredential.credentialSubject.encodedList,
997
+ encodedList: unsignedCredential.credentialSubject.encodedList,
810
998
  bitstringStatusList: {
811
999
  statusPurpose,
812
- ...updatedCredential.validFrom && {
813
- validFrom: new Date(updatedCredential.validFrom)
1000
+ ...unsignedCredential.validFrom && {
1001
+ validFrom: new Date(unsignedCredential.validFrom)
814
1002
  },
815
- ...updatedCredential.validUntil && {
816
- validUntil: new Date(updatedCredential.validUntil)
1003
+ ...unsignedCredential.validUntil && {
1004
+ validUntil: new Date(unsignedCredential.validUntil)
817
1005
  },
818
1006
  bitsPerStatus: args.bitsPerStatus,
819
1007
  ttl
@@ -826,17 +1014,23 @@ var BitstringStatusListImplementation = class {
826
1014
  statuslistContentType: this.buildContentType(proofFormat)
827
1015
  };
828
1016
  }
1017
+ /**
1018
+ * Updates a status list by decoding an encoded list, modifying it, and re-encoding
1019
+ *
1020
+ * @param args - Update parameters including encoded list, index, and new value
1021
+ * @param context - Veramo agent context for credential operations
1022
+ * @returns Promise resolving to the updated status list details
1023
+ */
829
1024
  async updateStatusListFromEncodedList(args, context) {
830
1025
  if (!args.bitstringStatusList) {
831
1026
  throw new Error("bitstringStatusList options required for type BitstringStatusList");
832
1027
  }
833
1028
  if (args.bitstringStatusList.bitsPerStatus < 1) {
834
- return Promise.reject("bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (updateStatusListFromEncodedList)");
1029
+ return Promise.reject(Error("bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (updateStatusListFromEncodedList)"));
835
1030
  }
836
1031
  const { statusPurpose, bitsPerStatus, ttl, validFrom, validUntil } = args.bitstringStatusList;
837
1032
  const proofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT3;
838
1033
  assertValidProofType(StatusListType4.BitstringStatusList, proofFormat);
839
- const veramoProofFormat = proofFormat;
840
1034
  const { issuer, id } = getAssertedValues(args);
841
1035
  const statusList = await BitstreamStatusList.decode({
842
1036
  encodedList: args.encodedList,
@@ -844,29 +1038,34 @@ var BitstringStatusListImplementation = class {
844
1038
  });
845
1039
  const index = typeof args.statusListIndex === "number" ? args.statusListIndex : parseInt(args.statusListIndex);
846
1040
  statusList.setStatus(index, args.value);
847
- const credential = await this.createVerifiableCredential({
1041
+ const unsignedCredential = await createStatusListCredential({
848
1042
  id,
849
1043
  issuer,
850
1044
  statusList,
851
- proofFormat: veramoProofFormat,
852
- keyRef: args.keyRef,
853
- statusPurpose,
854
- validFrom,
855
- validUntil,
1045
+ statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
1046
+ validFrom: ensureDate(validFrom),
1047
+ validUntil: ensureDate(validUntil),
856
1048
  ttl
1049
+ });
1050
+ const credential = await this.createVerifiableCredential({
1051
+ unsignedCredential,
1052
+ id,
1053
+ issuer,
1054
+ proofFormat,
1055
+ keyRef: args.keyRef
857
1056
  }, context);
858
1057
  return {
859
1058
  type: StatusListType4.BitstringStatusList,
860
1059
  statusListCredential: credential,
861
- encodedList: credential.credentialSubject.encodedList,
1060
+ encodedList: unsignedCredential.credentialSubject.encodedList,
862
1061
  bitstringStatusList: {
863
1062
  statusPurpose,
864
1063
  bitsPerStatus,
865
- ...credential.validFrom && {
866
- validFrom: new Date(credential.validFrom)
1064
+ ...unsignedCredential.validFrom && {
1065
+ validFrom: new Date(unsignedCredential.validFrom)
867
1066
  },
868
- ...credential.validUntil && {
869
- validUntil: new Date(credential.validUntil)
1067
+ ...unsignedCredential.validUntil && {
1068
+ validUntil: new Date(unsignedCredential.validUntil)
870
1069
  },
871
1070
  ttl
872
1071
  },
@@ -877,17 +1076,22 @@ var BitstringStatusListImplementation = class {
877
1076
  statuslistContentType: this.buildContentType(proofFormat)
878
1077
  };
879
1078
  }
1079
+ /**
1080
+ * Checks the status of a specific credential by its index in the status list
1081
+ *
1082
+ * @param args - Check parameters including the status list credential and index
1083
+ * @returns Promise resolving to the status value at the specified index
1084
+ */
880
1085
  async checkStatusIndex(args) {
881
1086
  if (!args.bitsPerStatus || args.bitsPerStatus < 1) {
882
- return Promise.reject("bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (checkStatusIndex)");
1087
+ return Promise.reject(Error("bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (checkStatusIndex)"));
883
1088
  }
884
1089
  const uniform = CredentialMapper3.toUniformCredential(args.statusListCredential);
885
1090
  const { credentialSubject } = uniform;
886
1091
  const encodedList = getAssertedProperty("encodedList", credentialSubject);
887
- const statusSize = args.bitsPerStatus;
888
1092
  const statusList = await BitstreamStatusList.decode({
889
1093
  encodedList,
890
- statusSize
1094
+ statusSize: args.bitsPerStatus
891
1095
  });
892
1096
  const numIndex = typeof args.statusListIndex === "number" ? args.statusListIndex : parseInt(args.statusListIndex);
893
1097
  if (statusList.getLength() <= numIndex) {
@@ -895,67 +1099,177 @@ var BitstringStatusListImplementation = class {
895
1099
  }
896
1100
  return statusList.getStatus(numIndex);
897
1101
  }
898
- async toStatusListDetails(args) {
899
- const { statusListPayload, bitsPerStatus } = args;
900
- if (!bitsPerStatus || bitsPerStatus < 1) {
901
- return Promise.reject("bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (toStatusListDetails)");
902
- }
903
- const uniform = CredentialMapper3.toUniformCredential(statusListPayload);
1102
+ /**
1103
+ * Performs the initial parsing of a StatusListCredential.
1104
+ * This method handles expensive operations like JWT/CWT decoding once.
1105
+ * It extracts all details available from the credential payload itself.
1106
+ */
1107
+ async extractCredentialDetails(credential) {
1108
+ const uniform = CredentialMapper3.toUniformCredential(credential);
904
1109
  const { issuer, credentialSubject } = uniform;
905
- const id = getAssertedValue("id", uniform.id);
906
- const encodedList = getAssertedProperty("encodedList", credentialSubject);
907
- const proofFormat = CredentialMapper3.detectDocumentType(statusListPayload) === DocumentFormat3.JWT ? "jwt" : "lds";
908
- const credSubject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject;
909
- const statusPurpose = getAssertedProperty("statusPurpose", credSubject);
910
- const validFrom = uniform.validFrom ? new Date(uniform.validFrom) : void 0;
911
- const validUntil = uniform.validUntil ? new Date(uniform.validUntil) : void 0;
912
- const ttl = credSubject.ttl;
913
- const statuslistLength = BitstreamStatusList.getStatusListLength(encodedList, bitsPerStatus);
1110
+ const subject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject;
914
1111
  return {
915
- id,
916
- encodedList,
1112
+ id: getAssertedValue("id", uniform.id),
917
1113
  issuer,
918
- type: StatusListType4.BitstringStatusList,
919
- proofFormat,
920
- length: statuslistLength,
921
- statusListCredential: statusListPayload,
922
- statuslistContentType: this.buildContentType(proofFormat),
923
- bitstringStatusList: {
1114
+ encodedList: getAssertedProperty("encodedList", subject)
1115
+ };
1116
+ }
1117
+ async toStatusListDetails(args) {
1118
+ if ("statusListCredential" in args) {
1119
+ const { statusListCredential, bitsPerStatus, correlationId, driverType } = args;
1120
+ if (!bitsPerStatus || bitsPerStatus < 1) {
1121
+ return Promise.reject(Error("bitsPerStatus must be set for bitstring status lists and must be 1 or higher"));
1122
+ }
1123
+ const uniform = CredentialMapper3.toUniformCredential(statusListCredential);
1124
+ const { issuer, credentialSubject } = uniform;
1125
+ const subject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject;
1126
+ const id = getAssertedValue("id", uniform.id);
1127
+ const encodedList = getAssertedProperty("encodedList", subject);
1128
+ const statusPurpose = getAssertedProperty("statusPurpose", subject);
1129
+ const validFrom = uniform.validFrom ? new Date(uniform.validFrom) : void 0;
1130
+ const validUntil = uniform.validUntil ? new Date(uniform.validUntil) : void 0;
1131
+ const ttl = subject.ttl;
1132
+ const proofFormat = CredentialMapper3.detectDocumentType(statusListCredential) === DocumentFormat3.JWT ? "vc+jwt" : "lds";
1133
+ const statuslistLength = BitstreamStatusList.getStatusListLength(encodedList, bitsPerStatus);
1134
+ return {
1135
+ id,
1136
+ encodedList,
1137
+ issuer,
1138
+ type: StatusListType4.BitstringStatusList,
1139
+ proofFormat,
1140
+ length: statuslistLength,
1141
+ statusListCredential,
1142
+ statuslistContentType: this.buildContentType(proofFormat),
1143
+ correlationId,
1144
+ driverType,
924
1145
  statusPurpose,
925
1146
  bitsPerStatus,
926
- validFrom,
927
- validUntil,
928
- ttl
929
- },
930
- ...args.correlationId && {
931
- correlationId: args.correlationId
932
- },
933
- ...args.driverType && {
934
- driverType: args.driverType
1147
+ ...validFrom && {
1148
+ validFrom
1149
+ },
1150
+ ...validUntil && {
1151
+ validUntil
1152
+ },
1153
+ ...ttl && {
1154
+ ttl
1155
+ },
1156
+ bitstringStatusList: {
1157
+ statusPurpose,
1158
+ bitsPerStatus,
1159
+ ...validFrom && {
1160
+ validFrom
1161
+ },
1162
+ ...validUntil && {
1163
+ validUntil
1164
+ },
1165
+ ...ttl && {
1166
+ ttl
1167
+ }
1168
+ }
1169
+ };
1170
+ } else {
1171
+ const { extractedDetails, statusListEntity } = args;
1172
+ const bitstringEntity = statusListEntity;
1173
+ if (!bitstringEntity.bitsPerStatus) {
1174
+ return Promise.reject(Error("bitsPerStatus must be present for a bitstring status list"));
935
1175
  }
1176
+ const proofFormat = CredentialMapper3.detectDocumentType(statusListEntity.statusListCredential) === DocumentFormat3.JWT ? "vc+jwt" : "lds";
1177
+ const statuslistLength = BitstreamStatusList.getStatusListLength(extractedDetails.encodedList, bitstringEntity.bitsPerStatus);
1178
+ return {
1179
+ id: extractedDetails.id,
1180
+ encodedList: extractedDetails.encodedList,
1181
+ issuer: extractedDetails.issuer,
1182
+ type: StatusListType4.BitstringStatusList,
1183
+ proofFormat,
1184
+ length: statuslistLength,
1185
+ statusListCredential: statusListEntity.statusListCredential,
1186
+ statuslistContentType: this.buildContentType(proofFormat),
1187
+ correlationId: statusListEntity.correlationId,
1188
+ driverType: statusListEntity.driverType,
1189
+ statusPurpose: bitstringEntity.statusPurpose,
1190
+ bitsPerStatus: bitstringEntity.bitsPerStatus,
1191
+ ...bitstringEntity.validFrom && {
1192
+ validFrom: bitstringEntity.validFrom
1193
+ },
1194
+ ...bitstringEntity.validUntil && {
1195
+ validUntil: bitstringEntity.validUntil
1196
+ },
1197
+ ...bitstringEntity.ttl && {
1198
+ ttl: bitstringEntity.ttl
1199
+ },
1200
+ bitstringStatusList: {
1201
+ statusPurpose: bitstringEntity.statusPurpose,
1202
+ bitsPerStatus: bitstringEntity.bitsPerStatus,
1203
+ ...bitstringEntity.validFrom && {
1204
+ validFrom: bitstringEntity.validFrom
1205
+ },
1206
+ ...bitstringEntity.validUntil && {
1207
+ validUntil: bitstringEntity.validUntil
1208
+ },
1209
+ ...bitstringEntity.ttl && {
1210
+ ttl: bitstringEntity.ttl
1211
+ }
1212
+ }
1213
+ };
1214
+ }
1215
+ }
1216
+ /**
1217
+ * Creates a credential status entry for a specific credential in a status list
1218
+ *
1219
+ * @param args - Parameters including the status list, entry details, and index
1220
+ * @returns Promise resolving to the credential status entry
1221
+ */
1222
+ async createCredentialStatus(args) {
1223
+ const { statusList, statusListEntry, statusListIndex } = args;
1224
+ const bitstringStatusList = statusList;
1225
+ const bitstringStatusListEntry = statusListEntry;
1226
+ return {
1227
+ id: `${statusList.id}#${statusListIndex}`,
1228
+ type: "BitstringStatusListEntry",
1229
+ statusPurpose: bitstringStatusListEntry.statusPurpose,
1230
+ statusListIndex: "" + statusListIndex,
1231
+ statusListCredential: statusList.id,
1232
+ bitsPerStatus: bitstringStatusList.bitsPerStatus,
1233
+ statusMessage: bitstringStatusListEntry.statusMessage,
1234
+ statusReference: bitstringStatusListEntry.statusReference
936
1235
  };
937
1236
  }
1237
+ /**
1238
+ * Creates a signed verifiable credential from an unsigned status list credential
1239
+ *
1240
+ * @param args - Parameters including the unsigned credential and signing details
1241
+ * @param context - Veramo agent context for credential operations
1242
+ * @returns Promise resolving to the signed credential
1243
+ */
938
1244
  async createVerifiableCredential(args, context) {
1245
+ const { unsignedCredential, issuer, proofFormat, keyRef } = args;
939
1246
  const identifier = await context.agent.identifierManagedGet({
940
- identifier: typeof args.issuer === "string" ? args.issuer : args.issuer.id,
1247
+ identifier: typeof issuer === "string" ? issuer : issuer.id,
941
1248
  vmRelationship: "assertionMethod",
942
1249
  offlineWhenNoDIDRegistered: true
943
1250
  });
944
- const unsignedCredential = await createStatusListCredential(args);
945
1251
  const verifiableCredential = await context.agent.createVerifiableCredential({
946
1252
  credential: unsignedCredential,
947
- keyRef: args.keyRef ?? identifier.kmsKeyRef,
948
- proofFormat: args.proofFormat,
1253
+ keyRef: keyRef ?? identifier.kmsKeyRef,
1254
+ proofFormat,
949
1255
  fetchRemoteContexts: true
950
1256
  });
951
1257
  return CredentialMapper3.toWrappedVerifiableCredential(verifiableCredential).original;
952
1258
  }
1259
+ /**
1260
+ * Builds the appropriate content type string for a given proof format
1261
+ *
1262
+ * @param proofFormat - The proof format to build content type for
1263
+ * @returns The corresponding content type string
1264
+ */
953
1265
  buildContentType(proofFormat) {
954
1266
  switch (proofFormat) {
955
1267
  case "jwt":
956
- return `application/statuslist+jwt`;
1268
+ return "application/statuslist+jwt";
957
1269
  case "cbor":
958
- return `application/statuslist+cwt`;
1270
+ return "application/statuslist+cwt";
1271
+ case "vc+jwt":
1272
+ return "application/statuslist+vc+jwt";
959
1273
  case "lds":
960
1274
  return "application/statuslist+ld+json";
961
1275
  default:
@@ -1111,36 +1425,35 @@ async function updateStatusIndexFromStatusListCredential(args, context) {
1111
1425
  return implementation.updateStatusListIndex(args, context);
1112
1426
  }
1113
1427
  __name(updateStatusIndexFromStatusListCredential, "updateStatusIndexFromStatusListCredential");
1114
- async function statusListCredentialToDetails({ correlationId, driverType, statusListCredential, bitsPerStatus }) {
1115
- const credential = getAssertedValue("statusListCredential", statusListCredential);
1116
- let statusListType;
1117
- const documentFormat = CredentialMapper4.detectDocumentType(credential);
1118
- if (documentFormat === DocumentFormat4.JWT) {
1119
- const [header] = credential.split(".");
1120
- const decodedHeader = JSON.parse(Buffer.from(header, "base64").toString());
1121
- if (decodedHeader.typ === "statuslist+jwt") {
1122
- statusListType = StatusListType6.OAuthStatusList;
1123
- }
1124
- } else if (documentFormat === DocumentFormat4.MSO_MDOC) {
1125
- statusListType = StatusListType6.OAuthStatusList;
1126
- }
1127
- if (!statusListType) {
1128
- const uniform = CredentialMapper4.toUniformCredential(credential);
1129
- const type = uniform.type.find((t) => t.includes("StatusList2021") || t.includes("OAuth2StatusList") || t.includes("BitstringStatusList"));
1130
- if (!type) {
1131
- throw new Error("Invalid status list credential type");
1132
- }
1133
- statusListType = type.replace("Credential", "");
1428
+ async function extractCredentialDetails(statusListCredential) {
1429
+ const statusListType = determineStatusListType(statusListCredential);
1430
+ const implementation = getStatusListImplementation(statusListType);
1431
+ return implementation.extractCredentialDetails(statusListCredential);
1432
+ }
1433
+ __name(extractCredentialDetails, "extractCredentialDetails");
1434
+ async function toStatusListDetails(args) {
1435
+ if ("statusListCredential" in args) {
1436
+ const statusListType = args.statusListType;
1437
+ const implementation = getStatusListImplementation(statusListType);
1438
+ return implementation.toStatusListDetails(args);
1439
+ } else {
1440
+ const statusListType = args.statusListEntity.type;
1441
+ const implementation = getStatusListImplementation(statusListType);
1442
+ return implementation.toStatusListDetails(args);
1134
1443
  }
1444
+ }
1445
+ __name(toStatusListDetails, "toStatusListDetails");
1446
+ async function createCredentialStatusFromStatusList(args) {
1447
+ const { statusList, statusListEntry, statusListIndex } = args;
1448
+ const statusListType = determineStatusListType(statusList.statusListCredential);
1135
1449
  const implementation = getStatusListImplementation(statusListType);
1136
- return await implementation.toStatusListDetails({
1137
- statusListPayload: credential,
1138
- correlationId,
1139
- driverType,
1140
- bitsPerStatus
1450
+ return implementation.createCredentialStatus({
1451
+ statusList,
1452
+ statusListEntry,
1453
+ statusListIndex
1141
1454
  });
1142
1455
  }
1143
- __name(statusListCredentialToDetails, "statusListCredentialToDetails");
1456
+ __name(createCredentialStatusFromStatusList, "createCredentialStatusFromStatusList");
1144
1457
  async function updateStatusListIndexFromEncodedList(args, context) {
1145
1458
  const { type } = getAssertedValue("type", args);
1146
1459
  const implementation = getStatusListImplementation(type);
@@ -1192,12 +1505,15 @@ export {
1192
1505
  StatusOAuth,
1193
1506
  checkStatusForCredential,
1194
1507
  checkStatusIndexFromStatusListCredential,
1508
+ createCredentialStatusFromStatusList,
1195
1509
  createNewStatusList,
1510
+ determineStatusListType,
1511
+ extractCredentialDetails,
1196
1512
  fetchStatusListCredential,
1197
1513
  simpleCheckStatusFromStatusListUrl,
1198
1514
  statusList2021ToVerifiableCredential,
1199
- statusListCredentialToDetails,
1200
1515
  statusPluginStatusFunction,
1516
+ toStatusListDetails,
1201
1517
  updateStatusIndexFromStatusListCredential,
1202
1518
  updateStatusListIndexFromEncodedList,
1203
1519
  vcLibCheckStatusFunction