@trustvc/trustvc 2.9.1 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  export { v4ComputeInterfaceId, v4ComputeTitleEscrowAddress, v4ContractAddress, v4Contracts, v4EncodeInitParams, v4GetEventFromReceipt, v4RoleHash, v4SupportInterfaceIds, v4Utils } from './token-registry-v4';
2
2
  export { v5ComputeInterfaceId, v5ContractAddress, v5Contracts, v5EncodeInitParams, v5GetEventFromReceipt, v5RoleHash, v5SupportInterfaceIds, v5Utils } from './token-registry-v5';
3
3
  export { DocumentStore__factory, TransferableDocumentStore__factory, deployDocumentStore, documentStoreGrantRole, documentStoreIssue, documentStoreRevoke, documentStoreRevokeRole, documentStoreTransferOwnership, getRoleString } from './document-store';
4
+ export * from './transaction';
5
+ export { cancelTransaction } from './transaction';
4
6
  export * from './token-registry-functions';
5
7
  export * from './core';
6
8
  export * from './open-attestation';
@@ -0,0 +1,28 @@
1
+ import forge from 'node-forge';
2
+ import { ENCRYPTION_PARAMETERS, decodeDocument } from './utils';
3
+
4
+ var __defProp = Object.defineProperty;
5
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
+ const decryptString = /* @__PURE__ */ __name(({ cipherText, tag, iv, key, type }) => {
7
+ if (type !== ENCRYPTION_PARAMETERS.version) {
8
+ throw new Error(`Expecting version ${ENCRYPTION_PARAMETERS.version} but got ${type}`);
9
+ }
10
+ const keyBytestring = forge.util.hexToBytes(key);
11
+ const cipherTextBytestring = forge.util.decode64(cipherText);
12
+ const ivBytestring = forge.util.decode64(iv);
13
+ const tagBytestring = forge.util.decode64(tag);
14
+ const decipher = forge.cipher.createDecipher("AES-GCM", keyBytestring);
15
+ decipher.start({
16
+ iv: ivBytestring,
17
+ tagLength: ENCRYPTION_PARAMETERS.tagLength,
18
+ tag: forge.util.createBuffer(tagBytestring, "raw")
19
+ });
20
+ decipher.update(forge.util.createBuffer(cipherTextBytestring, "raw"));
21
+ const success = decipher.finish();
22
+ if (!success) {
23
+ throw new Error("Error decrypting message");
24
+ }
25
+ return decodeDocument(decipher.output.data);
26
+ }, "decryptString");
27
+
28
+ export { decryptString };
@@ -0,0 +1,41 @@
1
+ import forge from 'node-forge';
2
+ import { encodeDocument, ENCRYPTION_PARAMETERS, generateEncryptionKey } from './utils';
3
+
4
+ var __defProp = Object.defineProperty;
5
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
+ const generateIv = /* @__PURE__ */ __name((ivLengthInBits = ENCRYPTION_PARAMETERS.ivLength) => {
7
+ const iv = forge.random.getBytesSync(ivLengthInBits / 8);
8
+ return forge.util.encode64(iv);
9
+ }, "generateIv");
10
+ const makeCipher = /* @__PURE__ */ __name((encryptionKey = generateEncryptionKey()) => {
11
+ const iv = generateIv();
12
+ const cipher = forge.cipher.createCipher(
13
+ ENCRYPTION_PARAMETERS.algorithm,
14
+ forge.util.hexToBytes(encryptionKey)
15
+ );
16
+ cipher.start({
17
+ iv: forge.util.decode64(iv),
18
+ tagLength: ENCRYPTION_PARAMETERS.tagLength
19
+ });
20
+ return { cipher, encryptionKey, iv };
21
+ }, "makeCipher");
22
+ const encryptString = /* @__PURE__ */ __name((document, key) => {
23
+ if (typeof document !== "string") {
24
+ throw new Error("encryptString only accepts strings");
25
+ }
26
+ const { cipher, encryptionKey, iv } = makeCipher(key);
27
+ const buffer = forge.util.createBuffer(encodeDocument(document));
28
+ cipher.update(buffer);
29
+ cipher.finish();
30
+ const encryptedMessage = forge.util.encode64(cipher.output.data);
31
+ const tag = forge.util.encode64(cipher.mode.tag.data);
32
+ return {
33
+ cipherText: encryptedMessage,
34
+ iv,
35
+ tag,
36
+ key: encryptionKey,
37
+ type: ENCRYPTION_PARAMETERS.version
38
+ };
39
+ }, "encryptString");
40
+
41
+ export { encryptString };
@@ -3,3 +3,5 @@ export * from './types';
3
3
  export * from './utils';
4
4
  export * from './verify';
5
5
  export * from './wrap';
6
+ export { encryptString } from './encrypt';
7
+ export { decryptString } from './decrypt';
@@ -1,6 +1,41 @@
1
+ import forge from 'node-forge';
1
2
  import { utils } from '@tradetrust-tt/tradetrust';
2
3
  export { SUPPORTED_SIGNING_ALGORITHM, SchemaId, getData as getDataV2, isSchemaValidationError, obfuscateDocument, validateSchema } from '@tradetrust-tt/tradetrust';
3
4
 
5
+ var __defProp = Object.defineProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ const ENCRYPTION_PARAMETERS = Object.freeze({
8
+ algorithm: "AES-GCM",
9
+ keyLength: 256,
10
+ // Key length in bits
11
+ ivLength: 96,
12
+ // IV length in bits: NIST suggests 12 bytes
13
+ tagLength: 128,
14
+ // GCM authentication tag length in bits, see link above for explanation
15
+ version: "OPEN-ATTESTATION-TYPE-1"
16
+ // Type 1 using the above params without compression
17
+ });
18
+ const generateEncryptionKey = /* @__PURE__ */ __name((keyLengthInBits = ENCRYPTION_PARAMETERS.keyLength) => {
19
+ if (!Number.isInteger(keyLengthInBits) || ![128, 192, 256].includes(keyLengthInBits)) {
20
+ throw new Error("keyLengthInBits must be one of 128, 192, or 256");
21
+ }
22
+ const encryptionKey = forge.random.getBytesSync(keyLengthInBits / 8);
23
+ return forge.util.bytesToHex(encryptionKey);
24
+ }, "generateEncryptionKey");
25
+ const encodeDocument = /* @__PURE__ */ __name((document) => {
26
+ const bytes = forge.util.encodeUtf8(document);
27
+ const standard = forge.util.encode64(bytes);
28
+ const s = standard.replace(/\+/g, "-").replace(/\//g, "_");
29
+ const trim = s.endsWith("==") ? 2 : s.endsWith("=") ? 1 : 0;
30
+ return trim ? s.slice(0, -trim) : s;
31
+ }, "encodeDocument");
32
+ const decodeDocument = /* @__PURE__ */ __name((encoded) => {
33
+ let normalized = encoded.replace(/-/g, "+").replace(/_/g, "/");
34
+ const pad = normalized.length % 4;
35
+ if (pad) normalized += "=".repeat(4 - pad);
36
+ const decoded = forge.util.decode64(normalized);
37
+ return forge.util.decodeUtf8(decoded);
38
+ }, "decodeDocument");
4
39
  const {
5
40
  isTransferableAsset,
6
41
  isDocumentRevokable,
@@ -17,4 +52,4 @@ const {
17
52
  getTemplateURL
18
53
  } = utils;
19
54
 
20
- export { diagnose, getAssetId, getDocumentData, getIssuerAddress, getTemplateURL, isDocumentRevokable, isRawV2Document, isRawV3Document, isSignedWrappedV2Document, isSignedWrappedV3Document, isTransferableAsset, isWrappedV2Document, isWrappedV3Document };
55
+ export { ENCRYPTION_PARAMETERS, decodeDocument, diagnose, encodeDocument, generateEncryptionKey, getAssetId, getDocumentData, getIssuerAddress, getTemplateURL, isDocumentRevokable, isRawV2Document, isRawV3Document, isSignedWrappedV2Document, isSignedWrappedV3Document, isTransferableAsset, isWrappedV2Document, isWrappedV3Document };
@@ -0,0 +1,55 @@
1
+ import { BigNumber } from 'ethers';
2
+
3
+ var __defProp = Object.defineProperty;
4
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
5
+ const GAS_PRICE_SCALE_WHEN_FROM_HASH = 2;
6
+ const cancelTransaction = /* @__PURE__ */ __name(async (signer, options) => {
7
+ if (!signer.provider) {
8
+ throw new Error("Provider is required on signer");
9
+ }
10
+ const { nonce, gasPrice, transactionHash } = options;
11
+ let transactionNonce = nonce;
12
+ let transactionGasPrice = gasPrice;
13
+ if (transactionHash) {
14
+ if (typeof signer.provider.getTransaction !== "function") {
15
+ throw new Error("Provider does not support getTransaction");
16
+ }
17
+ const tx = await signer.provider.getTransaction(transactionHash);
18
+ if (!tx) {
19
+ throw new Error(`Transaction not found: ${transactionHash}`);
20
+ }
21
+ const txNonce = tx.nonce;
22
+ const txGasPrice = tx.gasPrice;
23
+ if (txGasPrice == null) {
24
+ throw new Error(
25
+ "Transaction uses EIP-1559 (no gasPrice). Cancel by providing --nonce and --gas-price explicitly."
26
+ );
27
+ }
28
+ transactionNonce = String(txNonce);
29
+ const scaled = typeof txGasPrice === "bigint" ? txGasPrice * BigInt(GAS_PRICE_SCALE_WHEN_FROM_HASH) : BigNumber.from(txGasPrice).mul(GAS_PRICE_SCALE_WHEN_FROM_HASH);
30
+ transactionGasPrice = String(scaled);
31
+ }
32
+ if (!transactionNonce || !transactionGasPrice) {
33
+ throw new Error(
34
+ "Provide either (--nonce and --gas-price) or --transaction-hash to cancel the pending transaction"
35
+ );
36
+ }
37
+ const address = await signer.getAddress();
38
+ if (!/^\d+$/.test(transactionNonce)) {
39
+ throw new Error("Invalid nonce: expected a non-negative integer");
40
+ }
41
+ if (!/^\d+$/.test(transactionGasPrice) || transactionGasPrice === "0") {
42
+ throw new Error("Invalid gasPrice: expected a positive integer string in wei");
43
+ }
44
+ const nonceNum = Number(transactionNonce);
45
+ const txResponse = await signer.sendTransaction({
46
+ to: address,
47
+ value: 0,
48
+ nonce: nonceNum,
49
+ gasPrice: transactionGasPrice,
50
+ gasLimit: 21e3
51
+ });
52
+ return txResponse.hash;
53
+ }, "cancelTransaction");
54
+
55
+ export { cancelTransaction };
@@ -0,0 +1 @@
1
+ export { cancelTransaction } from './cancel';
@@ -19,6 +19,7 @@ export { documentStoreTransferOwnership } from './document-store/transferOwnersh
19
19
  export { deployDocumentStore } from './deploy/document-store.js';
20
20
  export { getRoleString } from './document-store/document-store-roles.js';
21
21
  export { DocumentStore__factory, TransferableDocumentStore__factory } from '@trustvc/document-store';
22
+ export { CancelTransactionOptions, CancelTransactionSigner, cancelTransaction } from './transaction/cancel.js';
22
23
  export { nominate, transferBeneficiary, transferHolder, transferOwners } from './token-registry-functions/transfer.js';
23
24
  export { rejectTransferBeneficiary, rejectTransferHolder, rejectTransferOwners } from './token-registry-functions/rejectTransfers.js';
24
25
  export { acceptReturned, rejectReturned, returnToIssuer } from './token-registry-functions/returnToken.js';
@@ -36,10 +37,12 @@ export { EndorsementChain, ParsedLog, TitleEscrowTransferEvent, TitleEscrowTrans
36
37
  export { TitleEscrowInterface, checkSupportsInterface, fetchEndorsementChain, getDocumentOwner, getTitleEscrowAddress, isTitleEscrowVersion } from './core/endorsement-chain/useEndorsementChain.js';
37
38
  export { DocumentBuilder, RenderMethod, SignOptions, W3CTransferableRecordsConfig, W3CVerifiableDocumentConfig, qrCode } from './core/documentBuilder.js';
38
39
  export { signOA } from './open-attestation/sign.js';
39
- export { KeyPair } from './open-attestation/types.js';
40
- export { diagnose, getAssetId, getDocumentData, getIssuerAddress, getTemplateURL, isDocumentRevokable, isRawV2Document, isRawV3Document, isSignedWrappedV2Document, isSignedWrappedV3Document, isTransferableAsset, isWrappedV2Document, isWrappedV3Document } from './open-attestation/utils.js';
40
+ export { IEncryptionResults, KeyPair } from './open-attestation/types.js';
41
+ export { ENCRYPTION_PARAMETERS, decodeDocument, diagnose, encodeDocument, generateEncryptionKey, getAssetId, getDocumentData, getIssuerAddress, getTemplateURL, isDocumentRevokable, isRawV2Document, isRawV3Document, isSignedWrappedV2Document, isSignedWrappedV3Document, isTransferableAsset, isWrappedV2Document, isWrappedV3Document } from './open-attestation/utils.js';
41
42
  export { verifyOASignature } from './open-attestation/verify.js';
42
43
  export { wrapOADocument, wrapOADocumentV2, wrapOADocuments, wrapOADocumentsV2 } from './open-attestation/wrap.js';
44
+ export { encryptString } from './open-attestation/encrypt.js';
45
+ export { decryptString } from './open-attestation/decrypt.js';
43
46
  export { openAttestationVerifiers, verifiers, w3cVerifiers } from './verify/verify.js';
44
47
  export { i as fragments } from './index-ZZ1UYFI0.js';
45
48
  export { OpencertsRegistryCode, OpencertsRegistryVerificationInvalidData, OpencertsRegistryVerificationInvalidDataArray, OpencertsRegistryVerificationValidData, OpencertsRegistryVerificationValidDataArray, OpencertsRegistryVerifierInvalidFragmentV2, OpencertsRegistryVerifierInvalidFragmentV3, OpencertsRegistryVerifierValidFragmentV2, OpencertsRegistryVerifierValidFragmentV3, OpencertsRegistryVerifierVerificationFragment, Registry, RegistryEntry, getOpencertsRegistryVerifierFragment, isValidOpenCert, name, registryVerifier, type, verifyOpenCertSignature } from './open-cert/verify.js';
@@ -0,0 +1,12 @@
1
+ import { IEncryptionResults } from './types.js';
2
+ import '@tradetrust-tt/tradetrust';
3
+ import '@tradetrust-tt/tradetrust/dist/types/shared/utils';
4
+
5
+ /**
6
+ * Decrypts a given ciphertext along with its associated variables.
7
+ * @param {IEncryptionResults} encryptionResults - Encryption result object containing cipherText (base64), tag (base64), iv (base64), key (hex), and type.
8
+ * @returns {string} Decrypted plaintext string.
9
+ */
10
+ declare const decryptString: ({ cipherText, tag, iv, key, type }: IEncryptionResults) => string;
11
+
12
+ export { decryptString };
@@ -0,0 +1,13 @@
1
+ import { IEncryptionResults } from './types.js';
2
+ import '@tradetrust-tt/tradetrust';
3
+ import '@tradetrust-tt/tradetrust/dist/types/shared/utils';
4
+
5
+ /**
6
+ * Encrypts a given string with symmetric AES-GCM.
7
+ * @param {string} document - Input string to encrypt.
8
+ * @param {string} [key] - Optional encryption key in hexadecimal (64 chars for 256-bit). If omitted, a key is generated.
9
+ * @returns {IEncryptionResults} Object with cipherText (base64), iv (base64), tag (base64), key (hex), and type.
10
+ */
11
+ declare const encryptString: (document: string, key?: string) => IEncryptionResults;
12
+
13
+ export { encryptString };
@@ -1,8 +1,10 @@
1
1
  export { signOA } from './sign.js';
2
- export { KeyPair } from './types.js';
3
- export { diagnose, getAssetId, getDocumentData, getIssuerAddress, getTemplateURL, isDocumentRevokable, isRawV2Document, isRawV3Document, isSignedWrappedV2Document, isSignedWrappedV3Document, isTransferableAsset, isWrappedV2Document, isWrappedV3Document } from './utils.js';
2
+ export { IEncryptionResults, KeyPair } from './types.js';
3
+ export { ENCRYPTION_PARAMETERS, decodeDocument, diagnose, encodeDocument, generateEncryptionKey, getAssetId, getDocumentData, getIssuerAddress, getTemplateURL, isDocumentRevokable, isRawV2Document, isRawV3Document, isSignedWrappedV2Document, isSignedWrappedV3Document, isTransferableAsset, isWrappedV2Document, isWrappedV3Document } from './utils.js';
4
4
  export { verifyOASignature } from './verify.js';
5
5
  export { wrapOADocument, wrapOADocumentV2, wrapOADocuments, wrapOADocumentsV2 } from './wrap.js';
6
+ export { encryptString } from './encrypt.js';
7
+ export { decryptString } from './decrypt.js';
6
8
  export { OpenAttestationDocument, SUPPORTED_SIGNING_ALGORITHM, SchemaId, SignedWrappedDocument, WrappedDocument, getData as getDataV2, isSchemaValidationError, obfuscateDocument, v2, v3, validateSchema, __unsafe__use__it__at__your__own__risks__wrapDocument as wrapOADocumentV3, __unsafe__use__it__at__your__own__risks__wrapDocuments as wrapOADocumentsV3 } from '@tradetrust-tt/tradetrust';
7
9
  export { DiagnoseError } from '@tradetrust-tt/tradetrust/dist/types/shared/utils';
8
10
  import '@ethersproject/abstract-signer';
@@ -5,5 +5,12 @@ type KeyPair = {
5
5
  public: string;
6
6
  private: string;
7
7
  };
8
+ interface IEncryptionResults {
9
+ cipherText: string;
10
+ iv: string;
11
+ tag: string;
12
+ key: string;
13
+ type: string;
14
+ }
8
15
 
9
- export type { KeyPair };
16
+ export type { IEncryptionResults, KeyPair };
@@ -7,6 +7,37 @@ import * as _tradetrust_tt_tradetrust_dist_types_2_0_types from '@tradetrust-tt/
7
7
  import * as _tradetrust_tt_tradetrust_dist_types___generated___schema_2_0 from '@tradetrust-tt/tradetrust/dist/types/__generated__/schema.2.0';
8
8
  import * as _tradetrust_tt_tradetrust_dist_types_shared_utils__types_diagnose from '@tradetrust-tt/tradetrust/dist/types/shared/utils/@types/diagnose';
9
9
 
10
+ /**
11
+ * Default options for OA document encryption (AES-GCM).
12
+ * {@link https://crypto.stackexchange.com/questions/26783/ciphertext-and-tag-size-and-iv-transmission-with-aes-in-gcm-mode/26787|here}
13
+ */
14
+ declare const ENCRYPTION_PARAMETERS: Readonly<{
15
+ readonly algorithm: "AES-GCM";
16
+ readonly keyLength: 256;
17
+ readonly ivLength: 96;
18
+ readonly tagLength: 128;
19
+ readonly version: "OPEN-ATTESTATION-TYPE-1";
20
+ }>;
21
+ /**
22
+ * Generates a random key represented as a hexadecimal string.
23
+ * @param {number} [keyLengthInBits] - Key length in bits.
24
+ * @returns {string} Hexadecimal-encoded encryption key.
25
+ */
26
+ declare const generateEncryptionKey: (keyLengthInBits?: number) => string;
27
+ /**
28
+ * Encode document string to URL-safe base64 (base64url: UTF-8 then base64 with +→-, /→_, no padding).
29
+ * Safe for use in query strings and JSON without further encoding.
30
+ * @param {string} document - Plain text document to encode.
31
+ * @returns {string} Base64url-encoded string.
32
+ */
33
+ declare const encodeDocument: (document: string) => string;
34
+ /**
35
+ * Decode base64url-encoded document string back to UTF-8.
36
+ * Accepts both base64url (no padding, - and _) and standard base64 for backwards compatibility.
37
+ * @param {string} encoded - Base64- or base64url-encoded string to decode.
38
+ * @returns {string} Decoded UTF-8 plain text.
39
+ */
40
+ declare const decodeDocument: (encoded: string) => string;
10
41
  declare const isTransferableAsset: (document: any) => boolean;
11
42
  declare const isDocumentRevokable: (document: any) => boolean;
12
43
  declare const getAssetId: (document: any) => string;
@@ -39,4 +70,4 @@ declare const diagnose: ({ version, kind, document, debug, mode, }: {
39
70
  }) => utils.DiagnoseError[];
40
71
  declare const getTemplateURL: (document: any) => string | undefined;
41
72
 
42
- export { diagnose, getAssetId, getDocumentData, getIssuerAddress, getTemplateURL, isDocumentRevokable, isRawV2Document, isRawV3Document, isSignedWrappedV2Document, isSignedWrappedV3Document, isTransferableAsset, isWrappedV2Document, isWrappedV3Document };
73
+ export { ENCRYPTION_PARAMETERS, decodeDocument, diagnose, encodeDocument, generateEncryptionKey, getAssetId, getDocumentData, getIssuerAddress, getTemplateURL, isDocumentRevokable, isRawV2Document, isRawV3Document, isSignedWrappedV2Document, isSignedWrappedV3Document, isTransferableAsset, isWrappedV2Document, isWrappedV3Document };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Transaction Cancel Module
3
+ *
4
+ * Cancels a pending transaction by replacing it with a 0-value transaction to self
5
+ * using the same nonce and a higher gas price (e.g. 2x when using --transaction-hash).
6
+ * @see https://info.etherscan.com/how-to-cancel-ethereum-pending-transactions/
7
+ */
8
+ interface CancelTransactionOptions {
9
+ /** Pending transaction nonce (use with gasPrice, or use transactionHash instead) */
10
+ nonce?: string;
11
+ /** Gas price higher than the pending transaction (use with nonce) */
12
+ gasPrice?: string;
13
+ /** Pending transaction hash; nonce and gas price will be fetched and gas price increased by 100% */
14
+ transactionHash?: string;
15
+ }
16
+ /** Signer with provider, compatible with ethers v5 and v6. */
17
+ interface CancelTransactionSigner {
18
+ getAddress(): Promise<string>;
19
+ provider: {
20
+ getTransaction?(hash: string): Promise<unknown>;
21
+ } | null;
22
+ sendTransaction(tx: Record<string, unknown>): Promise<{
23
+ hash: string;
24
+ }>;
25
+ }
26
+ /**
27
+ * Cancels a pending transaction by sending a 0-value transaction to self with the same nonce
28
+ * and a higher gas price. Supports both ethers v5 and v6 signers via a unified transaction object.
29
+ * @param {CancelTransactionSigner} signer - Signer with provider (ethers v5 or v6)
30
+ * @param {CancelTransactionOptions} options - Either (nonce + gasPrice) or transactionHash
31
+ * @returns {Promise<string>} The replacement transaction hash
32
+ * @throws If neither (nonce and gasPrice) nor transactionHash is provided
33
+ * @throws If provider is not available on signer
34
+ */
35
+ declare const cancelTransaction: (signer: CancelTransactionSigner, options: CancelTransactionOptions) => Promise<string>;
36
+
37
+ export { type CancelTransactionOptions, type CancelTransactionSigner, cancelTransaction };
@@ -0,0 +1 @@
1
+ export { CancelTransactionOptions, CancelTransactionSigner, cancelTransaction } from './cancel.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trustvc/trustvc",
3
- "version": "2.9.1",
3
+ "version": "2.11.0",
4
4
  "description": "TrustVC library",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -131,6 +131,7 @@
131
131
  "ethersV6": "npm:ethers@^6.14.4",
132
132
  "js-sha3": "^0.9.3",
133
133
  "node-fetch": "^2.7.0",
134
+ "node-forge": "^1.3.3",
134
135
  "ts-chacha20": "^1.2.0"
135
136
  },
136
137
  "devDependencies": {
@@ -149,6 +150,7 @@
149
150
  "@types/lodash": "^4.17.16",
150
151
  "@types/mocha": "^10.0.10",
151
152
  "@types/node": "^18.19.86",
153
+ "@types/node-forge": "^1.3.14",
152
154
  "@types/node-fetch": "^2.6.12",
153
155
  "@vitest/coverage-v8": "^1.6.1",
154
156
  "concurrently": "^9.2.0",