@provablehq/sdk 0.9.16-rc → 0.9.17

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 (73) hide show
  1. package/dist/mainnet/account.d.ts +18 -3
  2. package/dist/mainnet/browser.d.ts +26 -7
  3. package/dist/mainnet/browser.js +1198 -248
  4. package/dist/mainnet/browser.js.map +1 -1
  5. package/dist/mainnet/keys/keystore/error.d.ts +23 -0
  6. package/dist/mainnet/keys/keystore/file.d.ts +207 -13
  7. package/dist/mainnet/keys/keystore/interface.d.ts +85 -0
  8. package/dist/mainnet/keys/provider/interface.d.ts +170 -0
  9. package/dist/{testnet/keys/provider/function-key-provider.d.ts → mainnet/keys/provider/memory.d.ts} +14 -180
  10. package/dist/{testnet/keys/provider/offline-key-provider.d.ts → mainnet/keys/provider/offline.d.ts} +4 -4
  11. package/dist/mainnet/keys/verifier/interface.d.ts +70 -0
  12. package/dist/mainnet/keys/verifier/memory.d.ts +37 -0
  13. package/dist/mainnet/models/cryptoBoxPubkey.d.ts +4 -0
  14. package/dist/mainnet/models/encryptedProvingRequest.d.ts +4 -0
  15. package/dist/mainnet/models/provingResponse.d.ts +48 -2
  16. package/dist/mainnet/models/record-scanner/encryptedRecordsResult.d.ts +7 -0
  17. package/dist/mainnet/models/record-scanner/encryptedRegistrationRequest.d.ts +8 -0
  18. package/dist/mainnet/models/record-scanner/error.d.ts +47 -0
  19. package/dist/mainnet/models/record-scanner/ownedFilter.d.ts +0 -2
  20. package/dist/mainnet/models/record-scanner/ownedRecordsResult.d.ts +13 -0
  21. package/dist/mainnet/models/record-scanner/registrationResponse.d.ts +0 -2
  22. package/dist/mainnet/models/record-scanner/registrationResult.d.ts +9 -0
  23. package/dist/mainnet/models/record-scanner/revokeResult.d.ts +17 -0
  24. package/dist/mainnet/models/record-scanner/serialNumbersResult.d.ts +15 -0
  25. package/dist/mainnet/models/record-scanner/statusResult.d.ts +13 -0
  26. package/dist/mainnet/models/record-scanner/tagsResult.d.ts +12 -0
  27. package/dist/mainnet/network-client.d.ts +81 -35
  28. package/dist/mainnet/node.js +345 -75
  29. package/dist/mainnet/node.js.map +1 -1
  30. package/dist/mainnet/program-manager.d.ts +54 -48
  31. package/dist/mainnet/record-provider.d.ts +7 -7
  32. package/dist/mainnet/record-scanner.d.ts +247 -31
  33. package/dist/mainnet/security.d.ts +38 -0
  34. package/dist/mainnet/utils.d.ts +1 -0
  35. package/dist/testnet/account.d.ts +18 -3
  36. package/dist/testnet/browser.d.ts +26 -7
  37. package/dist/testnet/browser.js +1198 -248
  38. package/dist/testnet/browser.js.map +1 -1
  39. package/dist/testnet/keys/keystore/error.d.ts +23 -0
  40. package/dist/testnet/keys/keystore/file.d.ts +207 -13
  41. package/dist/testnet/keys/keystore/interface.d.ts +85 -0
  42. package/dist/testnet/keys/provider/interface.d.ts +170 -0
  43. package/dist/{mainnet/keys/provider/function-key-provider.d.ts → testnet/keys/provider/memory.d.ts} +14 -180
  44. package/dist/{mainnet/keys/provider/offline-key-provider.d.ts → testnet/keys/provider/offline.d.ts} +4 -4
  45. package/dist/testnet/keys/verifier/interface.d.ts +70 -0
  46. package/dist/testnet/keys/verifier/memory.d.ts +37 -0
  47. package/dist/testnet/models/cryptoBoxPubkey.d.ts +4 -0
  48. package/dist/testnet/models/encryptedProvingRequest.d.ts +4 -0
  49. package/dist/testnet/models/provingResponse.d.ts +48 -2
  50. package/dist/testnet/models/record-scanner/encryptedRecordsResult.d.ts +7 -0
  51. package/dist/testnet/models/record-scanner/encryptedRegistrationRequest.d.ts +8 -0
  52. package/dist/testnet/models/record-scanner/error.d.ts +47 -0
  53. package/dist/testnet/models/record-scanner/ownedFilter.d.ts +0 -2
  54. package/dist/testnet/models/record-scanner/ownedRecordsResult.d.ts +13 -0
  55. package/dist/testnet/models/record-scanner/registrationResponse.d.ts +0 -2
  56. package/dist/testnet/models/record-scanner/registrationResult.d.ts +9 -0
  57. package/dist/testnet/models/record-scanner/revokeResult.d.ts +17 -0
  58. package/dist/testnet/models/record-scanner/serialNumbersResult.d.ts +15 -0
  59. package/dist/testnet/models/record-scanner/statusResult.d.ts +13 -0
  60. package/dist/testnet/models/record-scanner/tagsResult.d.ts +12 -0
  61. package/dist/testnet/network-client.d.ts +81 -35
  62. package/dist/testnet/node.js +345 -75
  63. package/dist/testnet/node.js.map +1 -1
  64. package/dist/testnet/program-manager.d.ts +54 -48
  65. package/dist/testnet/record-provider.d.ts +7 -7
  66. package/dist/testnet/record-scanner.d.ts +247 -31
  67. package/dist/testnet/security.d.ts +38 -0
  68. package/dist/testnet/utils.d.ts +1 -0
  69. package/package.json +4 -3
  70. package/dist/mainnet/keys/keystore/keystore.d.ts +0 -81
  71. package/dist/mainnet/keys/keystore/memory.d.ts +0 -8
  72. package/dist/testnet/keys/keystore/keystore.d.ts +0 -81
  73. package/dist/testnet/keys/keystore/memory.d.ts +0 -8
@@ -1,32 +1,105 @@
1
1
  import './node-polyfill.js';
2
2
  import * as fs from 'node:fs/promises';
3
+ import * as $fs from 'node:fs';
3
4
  import * as path from 'path';
5
+ import { MemKeyVerifier, InvalidLocatorError } from './browser.js';
6
+ export { Account, AleoKeyProvider, AleoKeyProviderParams, AleoNetworkClient, BlockHeightSearch, CREDITS_PROGRAM_KEYS, KeyVerificationError as ChecksumMismatchError, DecryptionNotEnabledError, KEY_STORE, KeyVerificationError, NetworkRecordProvider, OfflineKeyProvider, OfflineSearchParams, PRIVATE_TO_PUBLIC_TRANSFER, PRIVATE_TRANSFER, PRIVATE_TRANSFER_TYPES, PUBLIC_TO_PRIVATE_TRANSFER, PUBLIC_TRANSFER, PUBLIC_TRANSFER_AS_SIGNER, ProgramManager, RECORD_DOMAIN, RecordNotFoundError, RecordScanner, RecordScannerRequestError, SealanceMerkleTree, UUIDError, VALID_TRANSFER_TYPES, ViewKeyNotStoredError, encryptAuthorization, encryptProvingRequest, encryptRegistrationRequest, encryptViewKey, initializeWasm, isProveApiErrorBody, isProvingResponse, logAndThrow, sha256Hex } from './browser.js';
4
7
  import { ProvingKey, VerifyingKey } from '@provablehq/wasm/testnet.js';
5
8
  export { Address, Authorization, BHP1024, BHP256, BHP512, BHP768, Boolean, Ciphertext, ComputeKey, EncryptionToolkit, ExecutionRequest, ExecutionResponse, Field, Execution as FunctionExecution, GraphKey, Group, I128, I16, I32, I64, I8, OfflineQuery, Pedersen128, Pedersen64, Plaintext, Poseidon2, Poseidon4, Poseidon8, PrivateKey, PrivateKeyCiphertext, Program, ProgramManager as ProgramManagerBase, ProvingKey, ProvingRequest, RecordCiphertext, RecordPlaintext, Scalar, Signature, Transaction, Transition, U128, U16, U32, U64, U8, VerifyingKey, ViewKey, getOrInitConsensusVersionTestHeights, initThreadPool, verifyFunctionExecution } from '@provablehq/wasm/testnet.js';
6
- export { Account, AleoKeyProvider, AleoKeyProviderParams, AleoNetworkClient, BlockHeightSearch, CREDITS_PROGRAM_KEYS, KEY_STORE, NetworkRecordProvider, OfflineKeyProvider, OfflineSearchParams, PRIVATE_TO_PUBLIC_TRANSFER, PRIVATE_TRANSFER, PRIVATE_TRANSFER_TYPES, PUBLIC_TO_PRIVATE_TRANSFER, PUBLIC_TRANSFER, PUBLIC_TRANSFER_AS_SIGNER, ProgramManager, RECORD_DOMAIN, RecordScanner, SealanceMerkleTree, VALID_TRANSFER_TYPES, initializeWasm, logAndThrow, promoteMapToKeyStore } from './browser.js';
7
9
  import 'core-js/proposals/json-parse-with-source.js';
8
10
  import 'node:crypto';
9
- import 'node:fs';
10
11
  import 'mime/lite';
11
12
  import 'xmlhttprequest-ssl';
12
13
  import 'node:worker_threads';
13
14
  import 'node:os';
15
+ import 'libsodium-wrappers';
14
16
  import '@scure/base';
15
17
 
16
18
  class LocalFileKeyStore {
17
19
  directory;
20
+ keyVerifier = new MemKeyVerifier();
21
+ /**
22
+ * Creates a new directory at the given path or CURRENTDIR/.aleo if none is provided to store keys.
23
+ * If a custom directory is passed and its last path segment is not ".aleo", ".aleo" is appended
24
+ * so keys are stored under that subdirectory (e.g. /home/project → /home/project/.aleo).
25
+ *
26
+ * @param {string} [directory] - Optional custom directory path for key storage. Defaults to ".aleo" in current working directory.
27
+ * @throws {Error} If directory creation fails.
28
+ */
18
29
  constructor(directory) {
19
- this.directory = directory ?? path.join(process.cwd(), "keystore");
20
- // Ensure directory exists
21
- fs.mkdir(this.directory, { recursive: true }).catch((err) => {
22
- console.error("Failed to create keystore directory:", err);
23
- });
30
+ this.directory = directory ?? path.join(process.cwd(), ".aleo");
31
+ if (directory !== undefined && path.basename(this.directory) !== ".aleo") {
32
+ this.directory = path.join(this.directory, ".aleo");
33
+ }
34
+ $fs.mkdirSync(this.directory, { recursive: true });
24
35
  }
25
- proverPath(locator) {
26
- return path.join(this.directory, `${locator}.prover`);
36
+ /**
37
+ * Validates that a locator is a safe filesystem identifier.
38
+ *
39
+ * @private
40
+ * @param {string} locator - Unique identifier used to derive a metadata file path.
41
+ * @throws {InvalidLocatorError} If the locator could cause path traversal.
42
+ */
43
+ validateLocator(locator) {
44
+ // Reject empty and reserved names that could resolve to the directory or parent
45
+ if (locator === "" || locator === "." || locator === "..") {
46
+ throw new InvalidLocatorError(`Invalid locator: reserved or empty name "${locator}"`, locator, "reserved_name");
47
+ }
48
+ // Explicitly block traversal attempts
49
+ if (locator.includes("..")) {
50
+ throw new InvalidLocatorError("Invalid locator: path traversal detected", locator, "path_traversal");
51
+ }
52
+ // Block path separators and null byte
53
+ if (locator.includes("/") || locator.includes("\\") || locator.includes("\0")) {
54
+ throw new InvalidLocatorError("Invalid locator: path separator or null byte not allowed", locator, "path_separator");
55
+ }
27
56
  }
28
- verifierPath(locator) {
29
- return path.join(this.directory, `${locator}.verifier`);
57
+ /**
58
+ * Generates the path for a key metadata file based on the locator.
59
+ *
60
+ * @private
61
+ * @param {string} locator - Unique identifier for the key.
62
+ * @returns {string} Full filesystem path to the metadata file.
63
+ */
64
+ metadataPath(locator) {
65
+ return path.join(this.directory, `${locator}.metadata`);
66
+ }
67
+ /**
68
+ * Reads and parses the key fingerprint metadata from storage.
69
+ *
70
+ * @private
71
+ * @param {string} locator - Unique identifier for the key.
72
+ * @returns {Promise<KeyFingerprint | null>} The key fingerprint if found, null if file doesn't exist.
73
+ * @throws {Error} If file read fails for any reason other than not found.
74
+ */
75
+ async readKeyMetadata(locator) {
76
+ try {
77
+ const data = await fs.readFile(this.metadataPath(locator), "utf-8");
78
+ return JSON.parse(data);
79
+ }
80
+ catch (err) {
81
+ if (err &&
82
+ typeof err === "object" &&
83
+ "code" in err &&
84
+ err.code === "ENOENT")
85
+ return null;
86
+ throw err;
87
+ }
88
+ }
89
+ /**
90
+ * Writes key fingerprint metadata to storage.
91
+ *
92
+ * @private
93
+ * @param {string} locator - Unique identifier for the key.
94
+ * @param {KeyFingerprint} metadata - Key fingerprint metadata to store.
95
+ * @returns {Promise<void>}
96
+ * @throws {Error} If directory creation or file write fails.
97
+ */
98
+ async writeKeyMetadata(locator, metadata) {
99
+ await fs.mkdir(path.dirname(this.metadataPath(locator)), {
100
+ recursive: true,
101
+ });
102
+ await fs.writeFile(this.metadataPath(locator), JSON.stringify(metadata, null, 0), "utf-8");
30
103
  }
31
104
  async readFileOptional(filepath) {
32
105
  try {
@@ -39,102 +112,299 @@ class LocalFileKeyStore {
39
112
  throw err;
40
113
  }
41
114
  }
115
+ /**
116
+ * Atomically writes data to a file, ensuring the parent directories exist.
117
+ *
118
+ * @private
119
+ * @param {string} filepath - Full path to the file to write
120
+ * @param {Uint8Array} data - Binary data to write to the file
121
+ * @returns {Promise<void>} Resolves when write is complete
122
+ * @throws {Error} If directory creation or file write fails
123
+ */
42
124
  async writeFileAtomic(filepath, data) {
43
- // Ensure parent directories for nested locators exist
44
- await fs.mkdir(path.dirname(filepath), { recursive: true });
45
- await fs.writeFile(filepath, data);
125
+ const dir = path.dirname(filepath);
126
+ await fs.mkdir(dir, { recursive: true });
127
+ const tempPath = path.join(dir, `.${path.basename(filepath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
128
+ await fs.writeFile(tempPath, data);
129
+ try {
130
+ await fs.rename(tempPath, filepath);
131
+ }
132
+ catch (err) {
133
+ const code = err && typeof err === "object" && "code" in err ? err.code : undefined;
134
+ // Windows often throws EEXIST when target exists; EPERM/EACCES happen with locks/AV.
135
+ if (code === "EEXIST" || code === "EPERM" || code === "EACCES") {
136
+ await fs.unlink(filepath).catch(() => { });
137
+ try {
138
+ await fs.rename(tempPath, filepath);
139
+ }
140
+ catch (err2) {
141
+ await fs.unlink(tempPath).catch(() => { });
142
+ throw err2;
143
+ }
144
+ }
145
+ else {
146
+ await fs.unlink(tempPath).catch(() => { });
147
+ throw err;
148
+ }
149
+ }
46
150
  }
47
- async clearRecursive(dir) {
48
- let entries;
151
+ /**
152
+ * Recursively removes all files and subdirectories under the given directory, then removes the directory itself.
153
+ * Uses fs.rm with recursive: true and force: true so that symbolic links are removed without following them,
154
+ * avoiding deletion of content outside the keystore.
155
+ *
156
+ * @private
157
+ * @param {string} dir - Directory path to clear
158
+ * @returns {Promise<void>} Resolves when clearing is complete
159
+ * @throws {Error} If directory removal fails for reasons other than non-existence
160
+ */
161
+ async clearDirectory(dir) {
49
162
  try {
50
- entries = await fs.readdir(dir);
163
+ await fs.rm(dir, { recursive: true, force: true });
51
164
  }
52
165
  catch (err) {
53
- if (err.code === "ENOENT") {
166
+ const code = err && typeof err === "object" && "code" in err ? err.code : undefined;
167
+ if (code === "ENOENT") {
54
168
  return;
55
169
  }
56
170
  throw err;
57
171
  }
58
- await Promise.all(entries.map(async (name) => {
59
- const full = path.join(dir, name);
60
- let isDirectory = false;
61
- try {
62
- const stat = await fs.stat(full);
63
- isDirectory = stat.isDirectory();
64
- }
65
- catch {
66
- return;
67
- }
68
- if (isDirectory) {
69
- await this.clearRecursive(full);
70
- }
71
- else if (name.endsWith(".prover") || name.endsWith(".verifier")) {
72
- await fs.unlink(full).catch(() => { });
73
- }
74
- }));
75
172
  }
76
173
  // -------------------------------------------------------
77
174
  // KEYSTORE INTERFACE
78
175
  // -------------------------------------------------------
79
- async getKeys(locator) {
80
- const prover = await this.getProvingKey(locator);
81
- const verifier = await this.getVerifyingKey(locator);
82
- if (!prover || !verifier)
83
- return null;
84
- return [prover, verifier];
85
- }
176
+ /**
177
+ * Retrieves the key bytes from storage and optionally verifies them against a fingerprint.
178
+ *
179
+ * @param {KeyLocator} locator - Object containing a locator string for the key + optional fingerprint for verification.
180
+ * @returns {Promise<Uint8Array | null>} The key bytes if found and verified (if fingerprint provided), null if not found.
181
+ * @throws {KeyVerificationError} If fingerprint verification fails.
182
+ * @example
183
+ * const keyBytes = await getKeyBytes({
184
+ * locator: 'transfer_private.prover.421e5a5',
185
+ * fingerprint: { checksum: '421e5a52f01a1eeb068bbf56d15e19477ff7290e4b988d1013e15563f2b77801', size: 116746954 }
186
+ * });
187
+ * if (keyBytes) {
188
+ * // Use the verified key bytes
189
+ * }
190
+ */
86
191
  async getKeyBytes(locator) {
87
- const prover = await this.getProvingKeyBytes(locator);
88
- const verifier = await this.getVerifyingKeyBytes(locator);
89
- if (!prover || !verifier)
192
+ this.validateLocator(locator.locator);
193
+ // Attempt to read key bytes from storage (under this.directory).
194
+ const keyBytes = await this.readFileOptional(path.join(this.directory, locator.locator));
195
+ // If no key bytes were found, return null.
196
+ if (!keyBytes)
90
197
  return null;
91
- return [prover, verifier];
198
+ // Use caller-provided fingerprint or metadata stored on disk for verification.
199
+ const fingerprint = locator.fingerprint ?? (await this.getKeyMetadata(locator.locator));
200
+ if (fingerprint) {
201
+ await this.keyVerifier.verifyKeyBytes({
202
+ keyBytes,
203
+ locator: locator.locator,
204
+ fingerprint,
205
+ });
206
+ }
207
+ // Return the verified key bytes.
208
+ return keyBytes;
92
209
  }
210
+ /**
211
+ * Retrieves and verifies a proving key from storage.
212
+ *
213
+ * @param {KeyLocator} locator - Object containing the proving key location and optional fingerprint.
214
+ * @returns {Promise<ProvingKey | null>} The proving key if found and verified, null if not found.
215
+ * @throws {KeyVerificationError} If fingerprint verification fails.
216
+ * @throws {Error} If key bytes cannot be parsed into a valid ProvingKey.
217
+ *
218
+ * @example
219
+ * try {
220
+ * const key = await getProvingKey({
221
+ * locator: 'transfer_private.prover.421e5a5'
222
+ * });
223
+ * if (key) {
224
+ * // Use the verified proving key
225
+ * }
226
+ * } catch (err) {
227
+ * if (err instanceof KeyVerificationError) {
228
+ * // Handle verification failure.
229
+ * } else {
230
+ * // Handle key parsing error.
231
+ * }
232
+ * }
233
+ */
93
234
  async getProvingKey(locator) {
94
- const bytes = await this.getProvingKeyBytes(locator);
95
- return bytes ? ProvingKey.fromBytes(bytes) : null;
96
- }
97
- async getProvingKeyBytes(locator) {
98
- return this.readFileOptional(this.proverPath(locator));
235
+ // Get the key bytes from storage.
236
+ const proverBytes = await this.getKeyBytes(locator);
237
+ if (!proverBytes)
238
+ return null;
239
+ // Attempt to parse the key bytes as a WASM ProvingKey (throws if invalid).
240
+ return ProvingKey.fromBytes(proverBytes);
99
241
  }
242
+ /**
243
+ * Retrieves and verifies a verifying key from storage.
244
+ *
245
+ * @param {KeyLocator} locator - Object containing the verifying key location and optional fingerprint.
246
+ * @returns {Promise<VerifyingKey | null>} The verifying key if found and verified, null if not found.
247
+ * @throws {KeyVerificationError} If fingerprint verification fails.
248
+ * @throws {Error} If key bytes cannot be parsed into a valid VerifyingKey.
249
+ *
250
+ * @example
251
+ * try {
252
+ * const key = await getVerifyingKey({
253
+ * locator: 'transfer_private.verifier.4ac2f71'
254
+ * });
255
+ * if (key) {
256
+ * // Use the verified verifying key
257
+ * }
258
+ * } catch (err) {
259
+ * if (err instanceof KeyVerificationError) {
260
+ * // Handle verification failure.
261
+ * } else {
262
+ * // Handle key parsing error.
263
+ * }
264
+ * }
265
+ */
100
266
  async getVerifyingKey(locator) {
101
- const bytes = await this.getVerifyingKeyBytes(locator);
102
- return bytes ? VerifyingKey.fromBytes(bytes) : null;
267
+ // Get the key bytes from storage.
268
+ const verifierBytes = await this.getKeyBytes(locator);
269
+ if (!verifierBytes)
270
+ return null;
271
+ // Attempt to parse the key bytes as a WASM VerifyingKey (throws if invalid).
272
+ return VerifyingKey.fromBytes(verifierBytes);
103
273
  }
104
- async getVerifyingKeyBytes(locator) {
105
- return this.readFileOptional(this.verifierPath(locator));
274
+ /**
275
+ * Stores proving and verifying keys in key storage.
276
+ *
277
+ * @param {KeyLocator} proverLocator The unique locator for the desired proving key.
278
+ * @param {KeyLocator} verifierLocator The unique locator for the desired verifying key.
279
+ * @param {FunctionKeyPair} keys The proving and verifying keys.
280
+ *
281
+ * @example
282
+ * const keys = await generateKeys();
283
+ * await setKeys(
284
+ * { locator: 'transfer_private.prover' },
285
+ * { locator: 'transfer_private.verifier' },
286
+ * keys
287
+ * );
288
+ */
289
+ async setKeys(proverLocator, verifierLocator, keys) {
290
+ this.validateLocator(proverLocator.locator);
291
+ this.validateLocator(verifierLocator.locator);
292
+ // Convert the WASM keys to raw bytes.
293
+ const [provingKey, verifyingKey] = keys;
294
+ const [provingKeyBytes, verifyingKeyBytes] = [
295
+ provingKey.toBytes(),
296
+ verifyingKey.toBytes(),
297
+ ];
298
+ // Compute the fingerprints for the proving and verifying keys, verify against expected fingerprints if provided.
299
+ const [proverFingerPrint, verifierFingerPrint] = await Promise.all([
300
+ this.keyVerifier.computeKeyMetadata({
301
+ keyBytes: provingKeyBytes,
302
+ locator: proverLocator.locator,
303
+ fingerprint: proverLocator.fingerprint,
304
+ }),
305
+ this.keyVerifier.computeKeyMetadata({
306
+ keyBytes: verifyingKeyBytes,
307
+ locator: verifierLocator.locator,
308
+ fingerprint: verifierLocator.fingerprint,
309
+ }),
310
+ ]);
311
+ // Write the proving and verifying key bytes and their metadata to storage (under this.directory).
312
+ await this.writeFileAtomic(path.join(this.directory, proverLocator.locator), provingKeyBytes);
313
+ await this.writeFileAtomic(path.join(this.directory, verifierLocator.locator), verifyingKeyBytes);
314
+ await this.writeKeyMetadata(proverLocator.locator, proverFingerPrint);
315
+ await this.writeKeyMetadata(verifierLocator.locator, verifierFingerPrint);
106
316
  }
107
- async setKeys(locator, keys) {
108
- const [p, v] = keys;
109
- await this.writeFileAtomic(this.proverPath(locator), p.toBytes());
110
- await this.writeFileAtomic(this.verifierPath(locator), v.toBytes());
317
+ /**
318
+ * Store a raw proving or verifying key in storage along with its fingerprint metadata for future verification.
319
+ *
320
+ * @param {Uint8Array} keyBytes The raw proving and verifying key bytes.
321
+ * @param {KeyLocator} locator The unique locator for the desired key pair.
322
+ * @returns {Promise<void>}
323
+ * @throws {Error} If computing key metadata or writing to storage fails
324
+ *
325
+ * @example
326
+ * const keys = await generateKeys();
327
+ * await setKeyBytes(keys.provingKey.toBytes(), { locator: 'transfer_private.prover' });
328
+ */
329
+ async setKeyBytes(keyBytes, locator) {
330
+ this.validateLocator(locator.locator);
331
+ // Compute the key metadata including fingerprint
332
+ const computedMetadata = await this.keyVerifier.computeKeyMetadata({
333
+ keyBytes: keyBytes,
334
+ locator: locator.locator,
335
+ fingerprint: locator.fingerprint,
336
+ });
337
+ // Write the key bytes and metadata atomically (key file under this.directory).
338
+ await this.writeFileAtomic(path.join(this.directory, locator.locator), keyBytes);
339
+ await this.writeKeyMetadata(locator.locator, computedMetadata);
111
340
  }
112
- async setKeyBytes(locator, keys) {
113
- const [proverBytes, verifierBytes] = keys;
114
- await this.writeFileAtomic(this.proverPath(locator), proverBytes);
115
- await this.writeFileAtomic(this.verifierPath(locator), verifierBytes);
341
+ /**
342
+ * Returns stored metadata for a key, if any.
343
+ *
344
+ * @param {string} locator The unique locator for the key.
345
+ * @returns {Promise<KeyFingerprint | null>} The stored fingerprint metadata for that locator, or null if none exists.
346
+ *
347
+ * @example
348
+ * const metadata = await getKeyMetadata('transfer_private.prover.421e5a5');
349
+ * if (metadata) {
350
+ * // Use the stored metadata.
351
+ * }
352
+ */
353
+ async getKeyMetadata(locator) {
354
+ this.validateLocator(locator);
355
+ return this.readKeyMetadata(locator);
116
356
  }
357
+ /**
358
+ * Checks if a key exists at the specified locator path.
359
+ *
360
+ * @param {string} locator - Unique identifier for the key location.
361
+ * @returns {Promise<boolean>} True if key exists at location, false otherwise.
362
+ *
363
+ * @example
364
+ * const exists = await has('transfer_private.prover.421e5a5');
365
+ * if (exists) {
366
+ * // Key exists at location.
367
+ * } else {
368
+ * // Key does not exist at location.
369
+ * }
370
+ */
117
371
  async has(locator) {
118
- const proverExists = await fs
119
- .access(this.proverPath(locator))
120
- .then(() => true)
121
- .catch(() => false);
122
- const verifierExists = await fs
123
- .access(this.verifierPath(locator))
372
+ this.validateLocator(locator);
373
+ const keyPath = path.join(this.directory, locator);
374
+ return await fs
375
+ .access(keyPath)
124
376
  .then(() => true)
125
377
  .catch(() => false);
126
- return proverExists && verifierExists;
127
378
  }
379
+ /**
380
+ * Deletes a key and its associated metadata from storage. Silently ignores errors if files don't exist.
381
+ *
382
+ * @param {string} locator - Unique identifier for the key to delete.
383
+ * @returns {Promise<void>}
384
+ *
385
+ * @example
386
+ * await delete('transfer_private.prover.421e5a5');
387
+ */
128
388
  async delete(locator) {
129
- const p = this.proverPath(locator);
130
- const v = this.verifierPath(locator);
389
+ this.validateLocator(locator);
390
+ const p = path.join(this.directory, locator);
391
+ const m = this.metadataPath(locator);
131
392
  await fs.unlink(p).catch(() => { });
132
- await fs.unlink(v).catch(() => { });
393
+ await fs.unlink(m).catch(() => { });
133
394
  }
395
+ /**
396
+ * Clears the key storage directory by recursively removing all files and subdirectories under it, then removes the keystore directory itself.
397
+ *
398
+ * @returns {Promise<void>}
399
+ * @throws {Error} If directory listing fails for reasons other than non-existence.
400
+ *
401
+ * @example
402
+ * await clear(); // Removes all files under the keystore directory.
403
+ */
134
404
  async clear() {
135
- await this.clearRecursive(this.directory);
405
+ await this.clearDirectory(this.directory);
136
406
  }
137
407
  }
138
408
 
139
- export { LocalFileKeyStore };
409
+ export { InvalidLocatorError, LocalFileKeyStore, MemKeyVerifier };
140
410
  //# sourceMappingURL=node.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"node.js","sources":["../../src/keys/keystore/file.ts"],"sourcesContent":["import * as fs from \"node:fs/promises\";\nimport * as path from \"path\";\n\nimport { CachedKeyPair, FunctionKeyPair } from \"../../models/keyPair.js\";\nimport { KeyStore } from \"./keystore.js\";\nimport { ProvingKey, VerifyingKey } from \"../../wasm.js\";\n\nexport class LocalFileKeyStore implements KeyStore {\n\n private directory: string;\n\n constructor(directory?: string) {\n this.directory = directory ?? path.join(process.cwd(), \"keystore\");\n\n // Ensure directory exists\n fs.mkdir(this.directory, { recursive: true }).catch((err) => {\n console.error(\"Failed to create keystore directory:\", err);\n });\n }\n\n private proverPath(locator: string): string {\n return path.join(this.directory, `${locator}.prover`);\n }\n\n private verifierPath(locator: string): string {\n return path.join(this.directory, `${locator}.verifier`);\n }\n\n private async readFileOptional(filepath: string): Promise<Uint8Array | null> {\n try {\n const data = await fs.readFile(filepath);\n return new Uint8Array(data);\n } catch (err: any) {\n if (err.code === \"ENOENT\") return null;\n throw err;\n }\n }\n\n private async writeFileAtomic(filepath: string, data: Uint8Array): Promise<void> {\n // Ensure parent directories for nested locators exist\n await fs.mkdir(path.dirname(filepath), { recursive: true });\n await fs.writeFile(filepath, data);\n }\n\n private async clearRecursive(dir: string): Promise<void> {\n let entries: string[];\n try {\n entries = await fs.readdir(dir);\n } catch (err: any) {\n if (err.code === \"ENOENT\") {\n return;\n }\n throw err;\n }\n\n await Promise.all(entries.map(async (name) => {\n const full = path.join(dir, name);\n let isDirectory = false;\n try {\n const stat = await fs.stat(full);\n isDirectory = stat.isDirectory();\n } catch {\n return;\n }\n\n if (isDirectory) {\n await this.clearRecursive(full);\n } else if (name.endsWith(\".prover\") || name.endsWith(\".verifier\")) {\n await fs.unlink(full).catch(() => {});\n }\n }));\n }\n\n // -------------------------------------------------------\n // KEYSTORE INTERFACE\n // -------------------------------------------------------\n\n async getKeys(locator: string): Promise<FunctionKeyPair | null> {\n const prover = await this.getProvingKey(locator);\n const verifier = await this.getVerifyingKey(locator);\n if (!prover || !verifier) return null;\n return [prover, verifier];\n }\n\n async getKeyBytes(locator: string): Promise<CachedKeyPair | null> {\n const prover = await this.getProvingKeyBytes(locator);\n const verifier = await this.getVerifyingKeyBytes(locator);\n if (!prover || !verifier) return null;\n return [prover, verifier];\n }\n\n async getProvingKey(locator: string): Promise<ProvingKey | null> {\n const bytes = await this.getProvingKeyBytes(locator);\n return bytes ? ProvingKey.fromBytes(bytes) : null;\n }\n\n async getProvingKeyBytes(locator: string): Promise<Uint8Array | null> {\n return this.readFileOptional(this.proverPath(locator));\n }\n\n async getVerifyingKey(locator: string): Promise<VerifyingKey | null> {\n const bytes = await this.getVerifyingKeyBytes(locator);\n return bytes ? VerifyingKey.fromBytes(bytes) : null;\n }\n\n async getVerifyingKeyBytes(locator: string): Promise<Uint8Array | null> {\n return this.readFileOptional(this.verifierPath(locator));\n }\n\n async setKeys(locator: string, keys: FunctionKeyPair): Promise<void> {\n const [p, v] = keys;\n await this.writeFileAtomic(this.proverPath(locator), p.toBytes());\n await this.writeFileAtomic(this.verifierPath(locator), v.toBytes());\n }\n\n async setKeyBytes(locator: string, keys: CachedKeyPair): Promise<void> {\n const [proverBytes, verifierBytes] = keys;\n await this.writeFileAtomic(this.proverPath(locator), proverBytes);\n await this.writeFileAtomic(this.verifierPath(locator), verifierBytes);\n }\n\n async has(locator: string): Promise<boolean> {\n const proverExists = await fs\n .access(this.proverPath(locator))\n .then(() => true)\n .catch(() => false);\n\n const verifierExists = await fs\n .access(this.verifierPath(locator))\n .then(() => true)\n .catch(() => false);\n\n return proverExists && verifierExists;\n }\n\n async delete(locator: string): Promise<void> {\n const p = this.proverPath(locator);\n const v = this.verifierPath(locator);\n\n await fs.unlink(p).catch(() => {});\n await fs.unlink(v).catch(() => {});\n }\n\n async clear(): Promise<void> {\n await this.clearRecursive(this.directory);\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"node.js","sources":["../../src/keys/keystore/file.ts"],"sourcesContent":["import * as fs from \"node:fs/promises\";\nimport * as fsSync from \"node:fs\";\nimport * as path from \"path\";\n\nimport { FunctionKeyPair } from \"../../models/keyPair.js\";\nimport { KeyFingerprint } from \"../verifier/interface.js\";\nimport { InvalidLocatorError } from \"./error.js\";\nimport { KeyLocator, KeyStore } from \"./interface.js\";\nimport { MemKeyVerifier } from \"../verifier/memory.js\";\nimport { ProvingKey, VerifyingKey } from \"../../wasm.js\";\n\nexport class LocalFileKeyStore implements KeyStore {\n private directory: string;\n private readonly keyVerifier = new MemKeyVerifier();\n\n /**\n * Creates a new directory at the given path or CURRENTDIR/.aleo if none is provided to store keys.\n * If a custom directory is passed and its last path segment is not \".aleo\", \".aleo\" is appended\n * so keys are stored under that subdirectory (e.g. /home/project → /home/project/.aleo).\n *\n * @param {string} [directory] - Optional custom directory path for key storage. Defaults to \".aleo\" in current working directory.\n * @throws {Error} If directory creation fails.\n */\n constructor(directory?: string) {\n this.directory = directory ?? path.join(process.cwd(), \".aleo\");\n if (directory !== undefined && path.basename(this.directory) !== \".aleo\") {\n this.directory = path.join(this.directory, \".aleo\");\n }\n fsSync.mkdirSync(this.directory, { recursive: true });\n }\n\n /**\n * Validates that a locator is a safe filesystem identifier.\n *\n * @private\n * @param {string} locator - Unique identifier used to derive a metadata file path.\n * @throws {InvalidLocatorError} If the locator could cause path traversal.\n */\n private validateLocator(locator: string): void {\n // Reject empty and reserved names that could resolve to the directory or parent\n if (locator === \"\" || locator === \".\" || locator === \"..\") {\n throw new InvalidLocatorError(\n `Invalid locator: reserved or empty name \"${locator}\"`,\n locator,\n \"reserved_name\"\n );\n }\n\n // Explicitly block traversal attempts\n if (locator.includes(\"..\")) {\n throw new InvalidLocatorError(\n \"Invalid locator: path traversal detected\",\n locator,\n \"path_traversal\"\n );\n }\n\n // Block path separators and null byte\n if (locator.includes(\"/\") || locator.includes(\"\\\\\") || locator.includes(\"\\0\")) {\n throw new InvalidLocatorError(\n \"Invalid locator: path separator or null byte not allowed\",\n locator,\n \"path_separator\"\n );\n }\n }\n\n /**\n * Generates the path for a key metadata file based on the locator.\n *\n * @private\n * @param {string} locator - Unique identifier for the key.\n * @returns {string} Full filesystem path to the metadata file.\n */\n private metadataPath(locator: string): string {\n return path.join(this.directory, `${locator}.metadata`);\n }\n\n /**\n * Reads and parses the key fingerprint metadata from storage.\n *\n * @private\n * @param {string} locator - Unique identifier for the key.\n * @returns {Promise<KeyFingerprint | null>} The key fingerprint if found, null if file doesn't exist.\n * @throws {Error} If file read fails for any reason other than not found.\n */\n private async readKeyMetadata(\n locator: string,\n ): Promise<KeyFingerprint | null> {\n try {\n const data = await fs.readFile(this.metadataPath(locator), \"utf-8\");\n return JSON.parse(data) as KeyFingerprint;\n } catch (err: unknown) {\n if (\n err &&\n typeof err === \"object\" &&\n \"code\" in err &&\n err.code === \"ENOENT\"\n )\n return null;\n throw err;\n }\n }\n\n /**\n * Writes key fingerprint metadata to storage.\n *\n * @private\n * @param {string} locator - Unique identifier for the key.\n * @param {KeyFingerprint} metadata - Key fingerprint metadata to store.\n * @returns {Promise<void>}\n * @throws {Error} If directory creation or file write fails.\n */\n private async writeKeyMetadata(\n locator: string,\n metadata: KeyFingerprint,\n ): Promise<void> {\n await fs.mkdir(path.dirname(this.metadataPath(locator)), {\n recursive: true,\n });\n await fs.writeFile(\n this.metadataPath(locator),\n JSON.stringify(metadata, null, 0),\n \"utf-8\",\n );\n }\n\n private async readFileOptional(\n filepath: string,\n ): Promise<Uint8Array | null> {\n try {\n const data = await fs.readFile(filepath);\n return new Uint8Array(data);\n } catch (err: any) {\n if (err.code === \"ENOENT\") return null;\n throw err;\n }\n }\n \n /**\n * Atomically writes data to a file, ensuring the parent directories exist.\n *\n * @private\n * @param {string} filepath - Full path to the file to write\n * @param {Uint8Array} data - Binary data to write to the file\n * @returns {Promise<void>} Resolves when write is complete\n * @throws {Error} If directory creation or file write fails\n */\n private async writeFileAtomic(\n filepath: string,\n data: Uint8Array,\n ): Promise<void> {\n const dir = path.dirname(filepath);\n await fs.mkdir(dir, { recursive: true });\n const tempPath = path.join(\n dir,\n `.${path.basename(filepath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`\n );\n await fs.writeFile(tempPath, data);\n try {\n await fs.rename(tempPath, filepath);\n } catch (err: unknown) {\n const code = err && typeof err === \"object\" && \"code\" in err ? (err as NodeJS.ErrnoException).code : undefined;\n // Windows often throws EEXIST when target exists; EPERM/EACCES happen with locks/AV.\n if (code === \"EEXIST\" || code === \"EPERM\" || code === \"EACCES\") {\n await fs.unlink(filepath).catch(() => {});\n try {\n await fs.rename(tempPath, filepath);\n } catch (err2) {\n await fs.unlink(tempPath).catch(() => {});\n throw err2;\n }\n } else {\n await fs.unlink(tempPath).catch(() => {});\n throw err;\n }\n }\n }\n\n /**\n * Recursively removes all files and subdirectories under the given directory, then removes the directory itself.\n * Uses fs.rm with recursive: true and force: true so that symbolic links are removed without following them,\n * avoiding deletion of content outside the keystore.\n *\n * @private\n * @param {string} dir - Directory path to clear\n * @returns {Promise<void>} Resolves when clearing is complete\n * @throws {Error} If directory removal fails for reasons other than non-existence\n */\n private async clearDirectory(dir: string): Promise<void> {\n try {\n await fs.rm(dir, { recursive: true, force: true });\n } catch (err: unknown) {\n const code = err && typeof err === \"object\" && \"code\" in err ? (err as NodeJS.ErrnoException).code : undefined;\n if (code === \"ENOENT\") {\n return;\n }\n throw err;\n }\n }\n\n // -------------------------------------------------------\n // KEYSTORE INTERFACE\n // -------------------------------------------------------\n\n /**\n * Retrieves the key bytes from storage and optionally verifies them against a fingerprint.\n *\n * @param {KeyLocator} locator - Object containing a locator string for the key + optional fingerprint for verification.\n * @returns {Promise<Uint8Array | null>} The key bytes if found and verified (if fingerprint provided), null if not found.\n * @throws {KeyVerificationError} If fingerprint verification fails.\n * @example\n * const keyBytes = await getKeyBytes({\n * locator: 'transfer_private.prover.421e5a5',\n * fingerprint: { checksum: '421e5a52f01a1eeb068bbf56d15e19477ff7290e4b988d1013e15563f2b77801', size: 116746954 }\n * });\n * if (keyBytes) {\n * // Use the verified key bytes\n * }\n */\n async getKeyBytes(locator: KeyLocator): Promise<Uint8Array | null> {\n this.validateLocator(locator.locator);\n // Attempt to read key bytes from storage (under this.directory).\n const keyBytes = await this.readFileOptional(path.join(this.directory, locator.locator));\n\n // If no key bytes were found, return null.\n if (!keyBytes) return null;\n\n // Use caller-provided fingerprint or metadata stored on disk for verification.\n const fingerprint =\n locator.fingerprint ?? (await this.getKeyMetadata(locator.locator));\n if (fingerprint) {\n await this.keyVerifier.verifyKeyBytes({\n keyBytes,\n locator: locator.locator,\n fingerprint,\n });\n }\n\n // Return the verified key bytes.\n return keyBytes;\n }\n\n /**\n * Retrieves and verifies a proving key from storage.\n *\n * @param {KeyLocator} locator - Object containing the proving key location and optional fingerprint.\n * @returns {Promise<ProvingKey | null>} The proving key if found and verified, null if not found.\n * @throws {KeyVerificationError} If fingerprint verification fails.\n * @throws {Error} If key bytes cannot be parsed into a valid ProvingKey.\n *\n * @example\n * try {\n * const key = await getProvingKey({\n * locator: 'transfer_private.prover.421e5a5'\n * });\n * if (key) {\n * // Use the verified proving key\n * }\n * } catch (err) {\n * if (err instanceof KeyVerificationError) {\n * // Handle verification failure.\n * } else {\n * // Handle key parsing error.\n * }\n * }\n */\n async getProvingKey(locator: KeyLocator): Promise<ProvingKey | null> {\n // Get the key bytes from storage.\n const proverBytes = await this.getKeyBytes(locator);\n if (!proverBytes) return null;\n\n // Attempt to parse the key bytes as a WASM ProvingKey (throws if invalid).\n return ProvingKey.fromBytes(proverBytes);\n }\n\n /**\n * Retrieves and verifies a verifying key from storage.\n *\n * @param {KeyLocator} locator - Object containing the verifying key location and optional fingerprint.\n * @returns {Promise<VerifyingKey | null>} The verifying key if found and verified, null if not found.\n * @throws {KeyVerificationError} If fingerprint verification fails.\n * @throws {Error} If key bytes cannot be parsed into a valid VerifyingKey.\n *\n * @example\n * try {\n * const key = await getVerifyingKey({\n * locator: 'transfer_private.verifier.4ac2f71'\n * });\n * if (key) {\n * // Use the verified verifying key\n * }\n * } catch (err) {\n * if (err instanceof KeyVerificationError) {\n * // Handle verification failure.\n * } else {\n * // Handle key parsing error.\n * }\n * }\n */\n async getVerifyingKey(locator: KeyLocator): Promise<VerifyingKey | null> {\n // Get the key bytes from storage.\n const verifierBytes = await this.getKeyBytes(locator);\n if (!verifierBytes) return null;\n\n // Attempt to parse the key bytes as a WASM VerifyingKey (throws if invalid).\n return VerifyingKey.fromBytes(verifierBytes);\n }\n\n /**\n * Stores proving and verifying keys in key storage.\n *\n * @param {KeyLocator} proverLocator The unique locator for the desired proving key.\n * @param {KeyLocator} verifierLocator The unique locator for the desired verifying key.\n * @param {FunctionKeyPair} keys The proving and verifying keys.\n *\n * @example\n * const keys = await generateKeys();\n * await setKeys(\n * { locator: 'transfer_private.prover' },\n * { locator: 'transfer_private.verifier' },\n * keys\n * );\n */\n async setKeys(\n proverLocator: KeyLocator,\n verifierLocator: KeyLocator,\n keys: FunctionKeyPair,\n ): Promise<void> {\n this.validateLocator(proverLocator.locator);\n this.validateLocator(verifierLocator.locator);\n // Convert the WASM keys to raw bytes.\n const [provingKey, verifyingKey] = keys;\n const [provingKeyBytes, verifyingKeyBytes] = [\n provingKey.toBytes(),\n verifyingKey.toBytes(),\n ];\n\n // Compute the fingerprints for the proving and verifying keys, verify against expected fingerprints if provided.\n const [proverFingerPrint, verifierFingerPrint] = await Promise.all([\n this.keyVerifier.computeKeyMetadata({\n keyBytes: provingKeyBytes,\n locator: proverLocator.locator,\n fingerprint: proverLocator.fingerprint,\n }),\n this.keyVerifier.computeKeyMetadata({\n keyBytes: verifyingKeyBytes,\n locator: verifierLocator.locator,\n fingerprint: verifierLocator.fingerprint,\n }),\n ]);\n\n // Write the proving and verifying key bytes and their metadata to storage (under this.directory).\n await this.writeFileAtomic(path.join(this.directory, proverLocator.locator), provingKeyBytes);\n await this.writeFileAtomic(path.join(this.directory, verifierLocator.locator), verifyingKeyBytes);\n await this.writeKeyMetadata(proverLocator.locator, proverFingerPrint);\n await this.writeKeyMetadata(\n verifierLocator.locator,\n verifierFingerPrint,\n );\n }\n\n /**\n * Store a raw proving or verifying key in storage along with its fingerprint metadata for future verification.\n *\n * @param {Uint8Array} keyBytes The raw proving and verifying key bytes.\n * @param {KeyLocator} locator The unique locator for the desired key pair.\n * @returns {Promise<void>}\n * @throws {Error} If computing key metadata or writing to storage fails\n *\n * @example\n * const keys = await generateKeys();\n * await setKeyBytes(keys.provingKey.toBytes(), { locator: 'transfer_private.prover' });\n */\n async setKeyBytes(keyBytes: Uint8Array, locator: KeyLocator): Promise<void> {\n this.validateLocator(locator.locator);\n // Compute the key metadata including fingerprint\n const computedMetadata = await this.keyVerifier.computeKeyMetadata({\n keyBytes: keyBytes,\n locator: locator.locator,\n fingerprint: locator.fingerprint,\n });\n\n // Write the key bytes and metadata atomically (key file under this.directory).\n await this.writeFileAtomic(path.join(this.directory, locator.locator), keyBytes);\n await this.writeKeyMetadata(locator.locator, computedMetadata);\n }\n\n /**\n * Returns stored metadata for a key, if any.\n *\n * @param {string} locator The unique locator for the key.\n * @returns {Promise<KeyFingerprint | null>} The stored fingerprint metadata for that locator, or null if none exists.\n *\n * @example\n * const metadata = await getKeyMetadata('transfer_private.prover.421e5a5');\n * if (metadata) {\n * // Use the stored metadata.\n * }\n */\n async getKeyMetadata(locator: string): Promise<KeyFingerprint | null> {\n this.validateLocator(locator);\n return this.readKeyMetadata(locator);\n }\n\n /**\n * Checks if a key exists at the specified locator path.\n *\n * @param {string} locator - Unique identifier for the key location.\n * @returns {Promise<boolean>} True if key exists at location, false otherwise.\n *\n * @example\n * const exists = await has('transfer_private.prover.421e5a5');\n * if (exists) {\n * // Key exists at location.\n * } else {\n * // Key does not exist at location.\n * }\n */\n async has(locator: string): Promise<boolean> {\n this.validateLocator(locator);\n const keyPath = path.join(this.directory, locator);\n return await fs\n .access(keyPath)\n .then(() => true)\n .catch(() => false);\n }\n\n /**\n * Deletes a key and its associated metadata from storage. Silently ignores errors if files don't exist.\n *\n * @param {string} locator - Unique identifier for the key to delete.\n * @returns {Promise<void>}\n *\n * @example\n * await delete('transfer_private.prover.421e5a5');\n */\n async delete(locator: string): Promise<void> {\n this.validateLocator(locator);\n const p = path.join(this.directory, locator);\n const m = this.metadataPath(locator);\n\n await fs.unlink(p).catch(() => {});\n await fs.unlink(m).catch(() => {});\n }\n\n /**\n * Clears the key storage directory by recursively removing all files and subdirectories under it, then removes the keystore directory itself.\n *\n * @returns {Promise<void>}\n * @throws {Error} If directory listing fails for reasons other than non-existence.\n *\n * @example\n * await clear(); // Removes all files under the keystore directory.\n */\n async clear(): Promise<void> {\n await this.clearDirectory(this.directory);\n }\n}"],"names":["fsSync"],"mappings":"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"}