@twin.org/identity-models 0.9.2 → 0.9.3-next.1

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.
@@ -75,5 +75,41 @@ export class VerificationHelper {
75
75
  }
76
76
  return true;
77
77
  }
78
+ /**
79
+ * Check a verifiable credential is within its validity period.
80
+ * @param credential The credential to check, either VC data model v1 or v2.
81
+ * @throws GeneralError if the credential has expired or is not yet valid.
82
+ */
83
+ static checkValidityPeriod(credential) {
84
+ Guards.object(VerificationHelper.CLASS_NAME, "credential", credential);
85
+ const dated = credential;
86
+ const notBefore = dated.issuanceDate ?? dated.validFrom;
87
+ const notAfter = dated.expirationDate ?? dated.validUntil;
88
+ const now = Date.now();
89
+ if (Is.stringValue(notBefore)) {
90
+ if (!Is.dateTimeString(notBefore)) {
91
+ throw new GeneralError(VerificationHelper.CLASS_NAME, "credentialValidityDateInvalid", {
92
+ date: notBefore
93
+ });
94
+ }
95
+ if (new Date(notBefore).getTime() > now) {
96
+ throw new GeneralError(VerificationHelper.CLASS_NAME, "credentialNotYetValid", {
97
+ validFrom: notBefore
98
+ });
99
+ }
100
+ }
101
+ if (Is.stringValue(notAfter)) {
102
+ if (!Is.dateTimeString(notAfter)) {
103
+ throw new GeneralError(VerificationHelper.CLASS_NAME, "credentialValidityDateInvalid", {
104
+ date: notAfter
105
+ });
106
+ }
107
+ if (new Date(notAfter).getTime() < now) {
108
+ throw new GeneralError(VerificationHelper.CLASS_NAME, "credentialExpired", {
109
+ validUntil: notAfter
110
+ });
111
+ }
112
+ }
113
+ }
78
114
  }
79
115
  //# sourceMappingURL=verificationHelper.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"verificationHelper.js","sourceRoot":"","sources":["../../../src/utils/verificationHelper.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { GeneralError, Guards, Is } from \"@twin.org/core\";\nimport type { IJsonLdNodeObject } from \"@twin.org/data-json-ld\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { ProofHelper, type IDidDocument, type IProof } from \"@twin.org/standards-w3c-did\";\nimport { Jwk, Jwt, type IJwtHeader, type IJwtPayload } from \"@twin.org/web\";\nimport { DocumentHelper } from \"./documentHelper.js\";\nimport type { IIdentityResolverComponent } from \"../models/IIdentityResolverComponent.js\";\n\n/**\n * Helper methods for verification.\n */\nexport class VerificationHelper {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<VerificationHelper>();\n\n\t/**\n\t * Verify the JWT and return the decoded header and payload.\n\t * @param resolver The resolver to use for finding the document.\n\t * @param jwt The token to verify.\n\t * @returns The decoded header and payload.\n\t */\n\tpublic static async verifyJwt<T extends IJwtHeader, U extends IJwtPayload>(\n\t\tresolver: IIdentityResolverComponent,\n\t\tjwt: string\n\t): Promise<{\n\t\theader: T;\n\t\tpayload: U;\n\t}> {\n\t\tGuards.object<IIdentityResolverComponent>(\n\t\t\tVerificationHelper.CLASS_NAME,\n\t\t\tnameof(resolver),\n\t\t\tresolver\n\t\t);\n\t\tGuards.string(VerificationHelper.CLASS_NAME, nameof(jwt), jwt);\n\n\t\tconst jwtDecoded = await Jwt.decode<T, U>(jwt);\n\n\t\tconst jwtHeader = jwtDecoded.header;\n\t\tconst jwtPayload = jwtDecoded.payload;\n\t\tconst jwtSignature = jwtDecoded.signature;\n\n\t\tif (!Is.object(jwtHeader) || !Is.object(jwtPayload) || !Is.uint8Array(jwtSignature)) {\n\t\t\tthrow new GeneralError(VerificationHelper.CLASS_NAME, \"jwtDecodeFailed\");\n\t\t}\n\n\t\tconst iss = jwtHeader?.iss;\n\t\tconst kid = jwtHeader?.kid;\n\n\t\tGuards.stringValue(VerificationHelper.CLASS_NAME, nameof(iss), iss);\n\t\tGuards.stringValue(VerificationHelper.CLASS_NAME, nameof(kid), kid);\n\n\t\tconst didDocument = await resolver.identityResolve(iss);\n\n\t\tconst jwk = DocumentHelper.getJwk(didDocument, kid);\n\n\t\tconst publicKey = await Jwk.toCryptoKey(jwk);\n\n\t\treturn Jwt.verify(jwt, publicKey);\n\t}\n\n\t/**\n\t * Verify the proof for the document.\n\t * @param resolver The resolver to use for finding the document.\n\t * @param secureDocument The secure document to verify.\n\t * @returns True if all proofs in the document are verified successfully.\n\t */\n\tpublic static async verifyProof(\n\t\tresolver: IIdentityResolverComponent,\n\t\tsecureDocument: IJsonLdNodeObject\n\t): Promise<boolean> {\n\t\tGuards.object<IIdentityResolverComponent>(\n\t\t\tVerificationHelper.CLASS_NAME,\n\t\t\tnameof(resolver),\n\t\t\tresolver\n\t\t);\n\t\tGuards.object<IJsonLdNodeObject>(\n\t\t\tVerificationHelper.CLASS_NAME,\n\t\t\tnameof(secureDocument),\n\t\t\tsecureDocument\n\t\t);\n\t\tGuards.object<IJsonLdNodeObject>(\n\t\t\tVerificationHelper.CLASS_NAME,\n\t\t\tnameof(secureDocument.proof),\n\t\t\tsecureDocument.proof\n\t\t);\n\n\t\tconst proofList = Is.array<IProof>(secureDocument.proof)\n\t\t\t? secureDocument.proof\n\t\t\t: [secureDocument.proof];\n\n\t\tconst documentCache: { [key: string]: IDidDocument } = {};\n\n\t\tfor (const proof of proofList as IProof[]) {\n\t\t\tif (!Is.stringValue(proof?.verificationMethod)) {\n\t\t\t\tthrow new GeneralError(VerificationHelper.CLASS_NAME, \"proofMissingVerificationMethod\");\n\t\t\t}\n\n\t\t\tconst proofVerificationMethod = DocumentHelper.parseId(proof.verificationMethod);\n\t\t\tif (!Is.stringValue(proofVerificationMethod.fragment)) {\n\t\t\t\tthrow new GeneralError(VerificationHelper.CLASS_NAME, \"proofMissingVerificationMethod\");\n\t\t\t}\n\n\t\t\tlet document: IDidDocument;\n\n\t\t\tif (documentCache[proofVerificationMethod.id]) {\n\t\t\t\tdocument = documentCache[proofVerificationMethod.id];\n\t\t\t} else {\n\t\t\t\tdocument = await resolver.identityResolve(proofVerificationMethod.id);\n\t\t\t\tdocumentCache[proofVerificationMethod.id] = document;\n\t\t\t}\n\n\t\t\tconst verificationJwk = DocumentHelper.getJwk(document, proofVerificationMethod.id);\n\n\t\t\tconst verified = await ProofHelper.verifyProof(secureDocument, proof, verificationJwk);\n\n\t\t\tif (!verified) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n}\n"]}
1
+ {"version":3,"file":"verificationHelper.js","sourceRoot":"","sources":["../../../src/utils/verificationHelper.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { GeneralError, Guards, Is } from \"@twin.org/core\";\nimport type { IJsonLdNodeObject } from \"@twin.org/data-json-ld\";\nimport { nameof } from \"@twin.org/nameof\";\nimport {\n\tProofHelper,\n\ttype IDidDocument,\n\ttype IDidVerifiableCredential,\n\ttype IProof\n} from \"@twin.org/standards-w3c-did\";\nimport { Jwk, Jwt, type IJwtHeader, type IJwtPayload } from \"@twin.org/web\";\nimport { DocumentHelper } from \"./documentHelper.js\";\nimport type { IIdentityResolverComponent } from \"../models/IIdentityResolverComponent.js\";\n\n/**\n * Helper methods for verification.\n */\nexport class VerificationHelper {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<VerificationHelper>();\n\n\t/**\n\t * Verify the JWT and return the decoded header and payload.\n\t * @param resolver The resolver to use for finding the document.\n\t * @param jwt The token to verify.\n\t * @returns The decoded header and payload.\n\t */\n\tpublic static async verifyJwt<T extends IJwtHeader, U extends IJwtPayload>(\n\t\tresolver: IIdentityResolverComponent,\n\t\tjwt: string\n\t): Promise<{\n\t\theader: T;\n\t\tpayload: U;\n\t}> {\n\t\tGuards.object<IIdentityResolverComponent>(\n\t\t\tVerificationHelper.CLASS_NAME,\n\t\t\tnameof(resolver),\n\t\t\tresolver\n\t\t);\n\t\tGuards.string(VerificationHelper.CLASS_NAME, nameof(jwt), jwt);\n\n\t\tconst jwtDecoded = await Jwt.decode<T, U>(jwt);\n\n\t\tconst jwtHeader = jwtDecoded.header;\n\t\tconst jwtPayload = jwtDecoded.payload;\n\t\tconst jwtSignature = jwtDecoded.signature;\n\n\t\tif (!Is.object(jwtHeader) || !Is.object(jwtPayload) || !Is.uint8Array(jwtSignature)) {\n\t\t\tthrow new GeneralError(VerificationHelper.CLASS_NAME, \"jwtDecodeFailed\");\n\t\t}\n\n\t\tconst iss = jwtHeader?.iss;\n\t\tconst kid = jwtHeader?.kid;\n\n\t\tGuards.stringValue(VerificationHelper.CLASS_NAME, nameof(iss), iss);\n\t\tGuards.stringValue(VerificationHelper.CLASS_NAME, nameof(kid), kid);\n\n\t\tconst didDocument = await resolver.identityResolve(iss);\n\n\t\tconst jwk = DocumentHelper.getJwk(didDocument, kid);\n\n\t\tconst publicKey = await Jwk.toCryptoKey(jwk);\n\n\t\treturn Jwt.verify(jwt, publicKey);\n\t}\n\n\t/**\n\t * Verify the proof for the document.\n\t * @param resolver The resolver to use for finding the document.\n\t * @param secureDocument The secure document to verify.\n\t * @returns True if all proofs in the document are verified successfully.\n\t */\n\tpublic static async verifyProof(\n\t\tresolver: IIdentityResolverComponent,\n\t\tsecureDocument: IJsonLdNodeObject\n\t): Promise<boolean> {\n\t\tGuards.object<IIdentityResolverComponent>(\n\t\t\tVerificationHelper.CLASS_NAME,\n\t\t\tnameof(resolver),\n\t\t\tresolver\n\t\t);\n\t\tGuards.object<IJsonLdNodeObject>(\n\t\t\tVerificationHelper.CLASS_NAME,\n\t\t\tnameof(secureDocument),\n\t\t\tsecureDocument\n\t\t);\n\t\tGuards.object<IJsonLdNodeObject>(\n\t\t\tVerificationHelper.CLASS_NAME,\n\t\t\tnameof(secureDocument.proof),\n\t\t\tsecureDocument.proof\n\t\t);\n\n\t\tconst proofList = Is.array<IProof>(secureDocument.proof)\n\t\t\t? secureDocument.proof\n\t\t\t: [secureDocument.proof];\n\n\t\tconst documentCache: { [key: string]: IDidDocument } = {};\n\n\t\tfor (const proof of proofList as IProof[]) {\n\t\t\tif (!Is.stringValue(proof?.verificationMethod)) {\n\t\t\t\tthrow new GeneralError(VerificationHelper.CLASS_NAME, \"proofMissingVerificationMethod\");\n\t\t\t}\n\n\t\t\tconst proofVerificationMethod = DocumentHelper.parseId(proof.verificationMethod);\n\t\t\tif (!Is.stringValue(proofVerificationMethod.fragment)) {\n\t\t\t\tthrow new GeneralError(VerificationHelper.CLASS_NAME, \"proofMissingVerificationMethod\");\n\t\t\t}\n\n\t\t\tlet document: IDidDocument;\n\n\t\t\tif (documentCache[proofVerificationMethod.id]) {\n\t\t\t\tdocument = documentCache[proofVerificationMethod.id];\n\t\t\t} else {\n\t\t\t\tdocument = await resolver.identityResolve(proofVerificationMethod.id);\n\t\t\t\tdocumentCache[proofVerificationMethod.id] = document;\n\t\t\t}\n\n\t\t\tconst verificationJwk = DocumentHelper.getJwk(document, proofVerificationMethod.id);\n\n\t\t\tconst verified = await ProofHelper.verifyProof(secureDocument, proof, verificationJwk);\n\n\t\t\tif (!verified) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Check a verifiable credential is within its validity period.\n\t * @param credential The credential to check, either VC data model v1 or v2.\n\t * @throws GeneralError if the credential has expired or is not yet valid.\n\t */\n\tpublic static checkValidityPeriod(credential: IDidVerifiableCredential): void {\n\t\tGuards.object<IDidVerifiableCredential>(\n\t\t\tVerificationHelper.CLASS_NAME,\n\t\t\tnameof(credential),\n\t\t\tcredential\n\t\t);\n\n\t\tconst dated = credential as {\n\t\t\tissuanceDate?: string;\n\t\t\tvalidFrom?: string;\n\t\t\texpirationDate?: string;\n\t\t\tvalidUntil?: string;\n\t\t};\n\t\tconst notBefore = dated.issuanceDate ?? dated.validFrom;\n\t\tconst notAfter = dated.expirationDate ?? dated.validUntil;\n\t\tconst now = Date.now();\n\n\t\tif (Is.stringValue(notBefore)) {\n\t\t\tif (!Is.dateTimeString(notBefore)) {\n\t\t\t\tthrow new GeneralError(VerificationHelper.CLASS_NAME, \"credentialValidityDateInvalid\", {\n\t\t\t\t\tdate: notBefore\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (new Date(notBefore).getTime() > now) {\n\t\t\t\tthrow new GeneralError(VerificationHelper.CLASS_NAME, \"credentialNotYetValid\", {\n\t\t\t\t\tvalidFrom: notBefore\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (Is.stringValue(notAfter)) {\n\t\t\tif (!Is.dateTimeString(notAfter)) {\n\t\t\t\tthrow new GeneralError(VerificationHelper.CLASS_NAME, \"credentialValidityDateInvalid\", {\n\t\t\t\t\tdate: notAfter\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (new Date(notAfter).getTime() < now) {\n\t\t\t\tthrow new GeneralError(VerificationHelper.CLASS_NAME, \"credentialExpired\", {\n\t\t\t\t\tvalidUntil: notAfter\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import type { IJsonLdNodeObject } from "@twin.org/data-json-ld";
2
+ import { type IDidVerifiableCredential } from "@twin.org/standards-w3c-did";
2
3
  import { type IJwtHeader, type IJwtPayload } from "@twin.org/web";
3
4
  import type { IIdentityResolverComponent } from "../models/IIdentityResolverComponent.js";
4
5
  /**
@@ -26,4 +27,10 @@ export declare class VerificationHelper {
26
27
  * @returns True if all proofs in the document are verified successfully.
27
28
  */
28
29
  static verifyProof(resolver: IIdentityResolverComponent, secureDocument: IJsonLdNodeObject): Promise<boolean>;
30
+ /**
31
+ * Check a verifiable credential is within its validity period.
32
+ * @param credential The credential to check, either VC data model v1 or v2.
33
+ * @throws GeneralError if the credential has expired or is not yet valid.
34
+ */
35
+ static checkValidityPeriod(credential: IDidVerifiableCredential): void;
29
36
  }
package/docs/changelog.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.3-next.1](https://github.com/iotaledger/twin-identity/compare/identity-models-v0.9.3-next.0...identity-models-v0.9.3-next.1) (2026-08-26)
4
+
5
+
6
+ ### Features
7
+
8
+ * add addAlsoKnownAs to identity connector ([#117](https://github.com/iotaledger/twin-identity/issues/117)) ([aa27cff](https://github.com/iotaledger/twin-identity/commit/aa27cff88e61e7c8c6e32aeb437fb01c6ee9f57a))
9
+ * add context id features ([#62](https://github.com/iotaledger/twin-identity/issues/62)) ([e02ecca](https://github.com/iotaledger/twin-identity/commit/e02ecca9c45a849104bfbf7bc18a1f44e6eea8a1))
10
+ * add context id long method ([#182](https://github.com/iotaledger/twin-identity/issues/182)) ([8e04625](https://github.com/iotaledger/twin-identity/commit/8e04625812cd3b8680ce837fadbb0bce046a5c2f))
11
+ * add expiration date option to vc creation ([73e05e1](https://github.com/iotaledger/twin-identity/commit/73e05e1ae61112c7e056889969751f4ff82d9f29))
12
+ * add identity remove ([eebc13f](https://github.com/iotaledger/twin-identity/commit/eebc13f4c2cd994d2d9cce4da2128fb346c80ba7))
13
+ * add idHelper class ([57c8bdb](https://github.com/iotaledger/twin-identity/commit/57c8bdb81efaa163b5e83f8a7f16f3764d12fd75))
14
+ * add optional jwt payload and headers to vc and vp tokens ([#135](https://github.com/iotaledger/twin-identity/issues/135)) ([aa1de0f](https://github.com/iotaledger/twin-identity/commit/aa1de0f63be95ff62bae3c699aabc85ea93d74c2))
15
+ * add proof to vcs and verify vs documents ([#103](https://github.com/iotaledger/twin-identity/issues/103)) ([b60bf0c](https://github.com/iotaledger/twin-identity/commit/b60bf0cb7d453d67574c5c0e4f769e67cf7cd6d1))
16
+ * add telemetry metrics ([#132](https://github.com/iotaledger/twin-identity/issues/132)) ([b51cd78](https://github.com/iotaledger/twin-identity/commit/b51cd7816905fd55e250035daf1b8f2047cba83d))
17
+ * add validate-locales ([04d74b4](https://github.com/iotaledger/twin-identity/commit/04d74b4d1ebe42672e8ca75a7bdb8e3556afd0be))
18
+ * admin endpoints ([#199](https://github.com/iotaledger/twin-identity/issues/199)) ([da6c189](https://github.com/iotaledger/twin-identity/commit/da6c18963ed551451d919e36aedc1dd8b005a12f))
19
+ * common connector tests ([4f9642c](https://github.com/iotaledger/twin-identity/commit/4f9642ceb09843870909fc6819bf69fb20ef952a))
20
+ * eslint migration to flat config ([fd6246d](https://github.com/iotaledger/twin-identity/commit/fd6246d566280b6d5d10a108eb1e92c4b510f2f2))
21
+ * expanded cli methods ([#121](https://github.com/iotaledger/twin-identity/issues/121)) ([80a52b7](https://github.com/iotaledger/twin-identity/commit/80a52b779237cd633d1f2813fa976585cef6e551))
22
+ * health and key removal ([934391f](https://github.com/iotaledger/twin-identity/commit/934391f9307beda34bc594e3aa506137e3df631b))
23
+ * health and key removal ([#191](https://github.com/iotaledger/twin-identity/issues/191)) ([8504101](https://github.com/iotaledger/twin-identity/commit/8504101a7a08b2a042a4e59f666c245308527088))
24
+ * identity key separator use slash ([1319d0d](https://github.com/iotaledger/twin-identity/commit/1319d0d07164a36b3ec279e6421b8835ffefc3d3))
25
+ * remove auth generator ([#98](https://github.com/iotaledger/twin-identity/issues/98)) ([a8969e8](https://github.com/iotaledger/twin-identity/commit/a8969e85a5a2804abfc787406e2d12eb168dd978))
26
+ * separate vc verification routes with query and body ([ea7d891](https://github.com/iotaledger/twin-identity/commit/ea7d8910472150cf76dbd51e282625e70226d9b3))
27
+ * tracing ([#205](https://github.com/iotaledger/twin-identity/issues/205)) ([add81ab](https://github.com/iotaledger/twin-identity/commit/add81ab4a258078c34ef0c57681d1675c81f8e2c))
28
+ * typescript 6 update ([e8806ad](https://github.com/iotaledger/twin-identity/commit/e8806ad6858c37be3c0f54c41cf654023773bef3))
29
+ * update did context handler definition ([02aa59a](https://github.com/iotaledger/twin-identity/commit/02aa59ae8100b1afb2325ea858411fc3e4d9d1e9))
30
+ * update framework core ([c824497](https://github.com/iotaledger/twin-identity/commit/c82449709af0215eb7af496cf687c93fb30b5ae0))
31
+ * use shared store mechanism ([#27](https://github.com/iotaledger/twin-identity/issues/27)) ([ce41f3f](https://github.com/iotaledger/twin-identity/commit/ce41f3fc3da1b206ec06da7ea5b2c968f788804d))
32
+
33
+
34
+ ### Bug Fixes
35
+
36
+ * didContextIdHandler tests ([dc7b555](https://github.com/iotaledger/twin-identity/commit/dc7b5558e47117475b7f1fa1686d3ed7e0906563))
37
+ * enforce credentialStatus, validity period and assertionMethod scope on object-form verification ([#215](https://github.com/iotaledger/twin-identity/issues/215)) ([8e6eb92](https://github.com/iotaledger/twin-identity/commit/8e6eb920564e0fe4ebdc984bdf682b7779f747d0))
38
+ * Import path and bump version ([#21](https://github.com/iotaledger/twin-identity/issues/21)) ([ccea845](https://github.com/iotaledger/twin-identity/commit/ccea845bf32562267280bc1b3dde1c9af1a00360))
39
+ * Install sdk-wasm ([#20](https://github.com/iotaledger/twin-identity/issues/20)) ([75ec14e](https://github.com/iotaledger/twin-identity/commit/75ec14e072f8c219863a1c028a3b0783802086e9))
40
+ * query params force coercion ([d9347d2](https://github.com/iotaledger/twin-identity/commit/d9347d29d4a9cc58759f30f5d8526de864ea7522))
41
+ * stricter pathParam types ([a174cdf](https://github.com/iotaledger/twin-identity/commit/a174cdf0ca4272bee35fcf20ab7e8e4e17b8b6f4))
42
+ * use base64Url for tenant id short form so it doesn't include slash ([53b9e27](https://github.com/iotaledger/twin-identity/commit/53b9e27351f20e2689734581c252a23527657926))
43
+ * Use resolver component ([#22](https://github.com/iotaledger/twin-identity/issues/22)) ([d0b3a32](https://github.com/iotaledger/twin-identity/commit/d0b3a321c7f9f966d397a880d752e9f2c0a98a27))
44
+
3
45
  ## [0.9.2](https://github.com/iotaledger/twin-identity/compare/identity-models-v0.9.2...identity-models-v0.9.2) (2026-08-24)
4
46
 
5
47
 
@@ -85,3 +85,27 @@ The secure document to verify.
85
85
  `Promise`\<`boolean`\>
86
86
 
87
87
  True if all proofs in the document are verified successfully.
88
+
89
+ ***
90
+
91
+ ### checkValidityPeriod() {#checkvalidityperiod}
92
+
93
+ > `static` **checkValidityPeriod**(`credential`): `void`
94
+
95
+ Check a verifiable credential is within its validity period.
96
+
97
+ #### Parameters
98
+
99
+ ##### credential
100
+
101
+ `IDidVerifiableCredential`
102
+
103
+ The credential to check, either VC data model v1 or v2.
104
+
105
+ #### Returns
106
+
107
+ `void`
108
+
109
+ #### Throws
110
+
111
+ GeneralError if the credential has expired or is not yet valid.
package/locales/en.json CHANGED
@@ -2,7 +2,10 @@
2
2
  "error": {
3
3
  "verificationHelper": {
4
4
  "jwtDecodeFailed": "Decoding the JWT failed",
5
- "proofMissingVerificationMethod": "The proof is missing the verification method"
5
+ "proofMissingVerificationMethod": "The proof is missing the verification method",
6
+ "credentialNotYetValid": "The credential is not valid until \"{validFrom}\"",
7
+ "credentialExpired": "The credential expired at \"{validUntil}\"",
8
+ "credentialValidityDateInvalid": "The credential validity date is not a valid ISO 8601 timestamp \"{date}\""
6
9
  },
7
10
  "documentHelper": {
8
11
  "verificationMethodNotFound": "The verification method \"{methodName}\" of type \"{methodType}\" could not be found",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/identity-models",
3
- "version": "0.9.2",
3
+ "version": "0.9.3-next.1",
4
4
  "description": "Shared identity models and contracts for consistent data structures across services, connectors, and clients.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,15 +14,15 @@
14
14
  "node": ">=24.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@twin.org/context": "^0.9.2",
18
- "@twin.org/core": "^0.9.2",
19
- "@twin.org/data-core": "^0.9.2",
20
- "@twin.org/data-json-ld": "^0.9.2",
21
- "@twin.org/entity": "^0.9.2",
22
- "@twin.org/nameof": "^0.9.2",
23
- "@twin.org/standards-w3c-did": "^0.9.2",
24
- "@twin.org/telemetry-models": "^0.9.2",
25
- "@twin.org/web": "^0.9.2"
17
+ "@twin.org/context": "next",
18
+ "@twin.org/core": "next",
19
+ "@twin.org/data-core": "next",
20
+ "@twin.org/data-json-ld": "next",
21
+ "@twin.org/entity": "next",
22
+ "@twin.org/nameof": "next",
23
+ "@twin.org/standards-w3c-did": "next",
24
+ "@twin.org/telemetry-models": "next",
25
+ "@twin.org/web": "next"
26
26
  },
27
27
  "main": "./dist/es/index.js",
28
28
  "types": "./dist/types/index.d.ts",