@cryptforge/auth 0.1.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/index.js ADDED
@@ -0,0 +1,1198 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AuthClient: () => AuthClient,
24
+ createAuthClient: () => createAuthClient
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/AuthClient.ts
29
+ var import_bip39 = require("@scure/bip39");
30
+ var import_english = require("@scure/bip39/wordlists/english.js");
31
+ var import_bip32 = require("@scure/bip32");
32
+ var AuthClient = class {
33
+ state = {
34
+ identity: null,
35
+ keys: null,
36
+ currentChain: null,
37
+ isLocked: true
38
+ };
39
+ listeners = /* @__PURE__ */ new Set();
40
+ lockTimer;
41
+ decryptedMnemonic = null;
42
+ // Blockchain adapter registry
43
+ adapters = /* @__PURE__ */ new Map();
44
+ currentAdapter = null;
45
+ /**
46
+ * Register a blockchain adapter for a specific chain
47
+ * @param chainId - Unique chain identifier (e.g., 'ethereum', 'bitcoin')
48
+ * @param adapter - BlockchainAdapter implementation
49
+ */
50
+ registerAdapter = (chainId, adapter) => {
51
+ this.adapters.set(chainId, adapter);
52
+ };
53
+ /**
54
+ * Get the adapter for a specific chain
55
+ * @param chainId - Chain identifier
56
+ * @returns BlockchainAdapter instance
57
+ * @throws Error if no adapter is registered for the chain
58
+ */
59
+ getAdapter(chainId) {
60
+ const adapter = this.adapters.get(chainId);
61
+ if (!adapter) {
62
+ throw new Error(
63
+ `No adapter registered for chain: ${chainId}. Please register an adapter using registerAdapter().`
64
+ );
65
+ }
66
+ return adapter;
67
+ }
68
+ /**
69
+ * Get all registered chain IDs
70
+ * @returns Array of registered chain IDs
71
+ */
72
+ getRegisteredChains = () => {
73
+ return Array.from(this.adapters.keys());
74
+ };
75
+ // Identity Creation & Restoration
76
+ /**
77
+ * Generates a BIP39 mnemonic phrase (12 or 24 words).
78
+ * @param options - Optional configuration for word count
79
+ * @returns BIP39 mnemonic phrase
80
+ */
81
+ generateMnemonic = (options) => {
82
+ const wordCount = options?.wordCount || 12;
83
+ const strength = wordCount === 24 ? 256 : 128;
84
+ return (0, import_bip39.generateMnemonic)(import_english.wordlist, strength);
85
+ };
86
+ /**
87
+ * Creates a new identity from a mnemonic and encrypts it with a password.
88
+ * Optionally unlocks with a specific blockchain.
89
+ * @param options - Identity creation options including mnemonic, password, and optional chainId
90
+ * @returns Promise resolving to the created identity and keys
91
+ * @throws {Error} If mnemonic is invalid
92
+ */
93
+ createIdentity = async (options) => {
94
+ const { mnemonic, password, label, metadata = {}, chainId } = options;
95
+ if (!(0, import_bip39.validateMnemonic)(mnemonic, import_english.wordlist)) {
96
+ throw new Error("Invalid mnemonic");
97
+ }
98
+ const fingerprint = getMasterFingerprint(mnemonic);
99
+ const publicKey = getMasterPublicKey(mnemonic);
100
+ const id = "identity_" + fingerprint;
101
+ const keystoreJson = await encryptMnemonic(mnemonic, password);
102
+ const storedIdentity = {
103
+ id,
104
+ fingerprint,
105
+ publicKey,
106
+ label: label || "Unnamed Wallet",
107
+ metadata,
108
+ keystore: keystoreJson,
109
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
110
+ lastAccess: (/* @__PURE__ */ new Date()).toISOString()
111
+ };
112
+ await saveIdentityToDB(storedIdentity);
113
+ const identity = {
114
+ id: storedIdentity.id,
115
+ publicKey: storedIdentity.publicKey,
116
+ fingerprint: storedIdentity.fingerprint,
117
+ label: storedIdentity.label,
118
+ metadata: storedIdentity.metadata,
119
+ createdAt: new Date(storedIdentity.createdAt),
120
+ lastAccess: storedIdentity.lastAccess ? new Date(storedIdentity.lastAccess) : void 0
121
+ };
122
+ this.state.identity = identity;
123
+ this.decryptedMnemonic = mnemonic;
124
+ let keys = null;
125
+ let chain = null;
126
+ if (chainId) {
127
+ const adapter = this.getAdapter(chainId);
128
+ keys = await this.deriveKeysWithAdapter(
129
+ mnemonic,
130
+ chainId,
131
+ adapter,
132
+ identity
133
+ );
134
+ chain = {
135
+ id: chainId,
136
+ name: adapter.chainData.name,
137
+ symbol: adapter.chainData.symbol
138
+ };
139
+ this.state.keys = keys;
140
+ this.state.currentChain = chain;
141
+ this.currentAdapter = adapter;
142
+ this.state.isLocked = false;
143
+ } else {
144
+ this.state.isLocked = true;
145
+ }
146
+ this.notifyListeners("IDENTITY_CREATED", keys);
147
+ return { identity, keys };
148
+ };
149
+ // Key Management
150
+ /**
151
+ * Unlocks the wallet by decrypting the keystore and deriving keys for a blockchain.
152
+ * @param options - Unlock options including password, chainId, and optional duration
153
+ * @returns Promise resolving to the derived keys
154
+ * @throws {Error} If password is incorrect or no identity is selected
155
+ */
156
+ unlock = async (options) => {
157
+ const { password, identityId, chainId, duration } = options;
158
+ let stored;
159
+ if (identityId) {
160
+ stored = await getIdentityFromDB(identityId);
161
+ } else if (this.state.identity) {
162
+ stored = await getIdentityFromDB(this.state.identity.id);
163
+ }
164
+ if (!stored) throw new Error("No identity selected");
165
+ const mnemonic = await decryptMnemonic(stored.keystore, password);
166
+ if (!(0, import_bip39.validateMnemonic)(mnemonic, import_english.wordlist)) {
167
+ throw new Error("Decrypted mnemonic is invalid");
168
+ }
169
+ this.decryptedMnemonic = mnemonic;
170
+ const identity = {
171
+ id: stored.id,
172
+ publicKey: stored.publicKey,
173
+ fingerprint: stored.fingerprint,
174
+ label: stored.label,
175
+ metadata: stored.metadata,
176
+ createdAt: new Date(stored.createdAt),
177
+ lastAccess: stored.lastAccess ? new Date(stored.lastAccess) : void 0
178
+ };
179
+ if (!chainId) {
180
+ throw new Error(
181
+ "chainId is required to unlock. Please specify which blockchain to use."
182
+ );
183
+ }
184
+ const adapter = this.getAdapter(chainId);
185
+ const keys = await this.deriveKeysWithAdapter(
186
+ mnemonic,
187
+ chainId,
188
+ adapter,
189
+ identity,
190
+ duration
191
+ // Pass duration to keys
192
+ );
193
+ const targetChain = {
194
+ id: chainId,
195
+ name: adapter.chainData.name,
196
+ symbol: adapter.chainData.symbol
197
+ };
198
+ this.state.identity = identity;
199
+ this.state.keys = keys;
200
+ this.state.currentChain = targetChain;
201
+ this.currentAdapter = adapter;
202
+ this.state.isLocked = false;
203
+ stored.lastAccess = (/* @__PURE__ */ new Date()).toISOString();
204
+ await saveIdentityToDB(stored);
205
+ if (duration) {
206
+ this.setAutoLockTimer(duration);
207
+ }
208
+ this.notifyListeners("UNLOCKED", keys);
209
+ return { keys };
210
+ };
211
+ /**
212
+ * Locks the wallet and clears all keys from memory.
213
+ * The encrypted keystore remains in IndexedDB.
214
+ * @returns Promise that resolves when wallet is locked
215
+ */
216
+ lock = async () => {
217
+ if (this.decryptedMnemonic) {
218
+ this.decryptedMnemonic = null;
219
+ }
220
+ this.state.keys = null;
221
+ this.state.isLocked = true;
222
+ if (this.lockTimer) {
223
+ clearTimeout(this.lockTimer);
224
+ this.lockTimer = void 0;
225
+ }
226
+ this.notifyListeners("LOCKED", null);
227
+ };
228
+ /**
229
+ * Switches to a different blockchain while preserving the same identity.
230
+ * @param chainId - Target blockchain identifier
231
+ * @param password - Optional password if wallet is locked
232
+ * @returns Promise resolving to keys for the new chain
233
+ * @throws {Error} If locked without password or adapter not registered
234
+ */
235
+ switchChain = async (chainId, password) => {
236
+ if (this.state.isLocked && !password) {
237
+ throw new Error(
238
+ "Identity is locked. Password required to switch chains."
239
+ );
240
+ }
241
+ let mnemonic = this.decryptedMnemonic;
242
+ if (!mnemonic && password && this.state.identity) {
243
+ const stored = await getIdentityFromDB(this.state.identity.id);
244
+ if (!stored) throw new Error("Identity not found");
245
+ mnemonic = await decryptMnemonic(stored.keystore, password);
246
+ this.decryptedMnemonic = mnemonic;
247
+ }
248
+ if (!mnemonic || !this.state.identity) {
249
+ throw new Error("No active identity or mnemonic");
250
+ }
251
+ const adapter = this.getAdapter(chainId);
252
+ const duration = this.state.keys ? this.state.keys.expiresAt.getTime() - Date.now() : void 0;
253
+ const keys = await this.deriveKeysWithAdapter(
254
+ mnemonic,
255
+ chainId,
256
+ adapter,
257
+ this.state.identity,
258
+ duration && duration > 0 ? duration : void 0
259
+ );
260
+ const newChain = {
261
+ id: chainId,
262
+ name: adapter.chainData.name,
263
+ symbol: adapter.chainData.symbol
264
+ };
265
+ this.state.keys = keys;
266
+ this.state.currentChain = newChain;
267
+ this.currentAdapter = adapter;
268
+ this.state.isLocked = false;
269
+ this.notifyListeners("CHAIN_SWITCHED", keys);
270
+ return { keys };
271
+ };
272
+ /**
273
+ * Rotates to a new set of keys at the next address index or custom path.
274
+ * Preserves key expiration times from current session.
275
+ * @param newDerivationPath - Optional custom BIP44 path (defaults to next index)
276
+ * @returns Promise resolving to the new keys
277
+ * @throws {Error} If wallet is locked
278
+ */
279
+ rotateKeys = async (newDerivationPath) => {
280
+ if (this.state.isLocked || !this.decryptedMnemonic || !this.state.identity || !this.currentAdapter || !this.state.currentChain) {
281
+ throw new Error("Identity must be unlocked to rotate keys");
282
+ }
283
+ if (newDerivationPath) {
284
+ const keyData2 = await this.currentAdapter.deriveKeysAtPath(
285
+ this.decryptedMnemonic,
286
+ newDerivationPath
287
+ );
288
+ const expiresAt2 = this.state.keys?.expiresAt || new Date(Date.now() + 36e5);
289
+ const expiresIn2 = this.state.keys?.expiresIn || 3600;
290
+ const keys2 = {
291
+ privateKey: keyData2.privateKey,
292
+ privateKeyHex: keyData2.privateKeyHex,
293
+ publicKey: keyData2.publicKey,
294
+ publicKeyHex: keyData2.publicKeyHex,
295
+ address: keyData2.address,
296
+ derivationPath: keyData2.path,
297
+ chain: this.state.currentChain,
298
+ expiresAt: expiresAt2,
299
+ expiresIn: expiresIn2,
300
+ identity: this.state.identity
301
+ };
302
+ this.state.keys = keys2;
303
+ this.notifyListeners("KEYS_ROTATED", keys2);
304
+ return { keys: keys2 };
305
+ }
306
+ const currentPath = this.state.keys?.derivationPath || "";
307
+ const pathParts = currentPath.split("/");
308
+ const lastIndex = parseInt(pathParts[pathParts.length - 1]) || 0;
309
+ const newIndex = lastIndex + 1;
310
+ const keyData = await this.currentAdapter.deriveKeysAtIndex(
311
+ this.decryptedMnemonic,
312
+ newIndex
313
+ );
314
+ const expiresAt = this.state.keys?.expiresAt || new Date(Date.now() + 36e5);
315
+ const expiresIn = this.state.keys?.expiresIn || 3600;
316
+ const keys = {
317
+ privateKey: keyData.privateKey,
318
+ privateKeyHex: keyData.privateKeyHex,
319
+ publicKey: keyData.publicKey,
320
+ publicKeyHex: keyData.publicKeyHex,
321
+ address: keyData.address,
322
+ derivationPath: keyData.path,
323
+ chain: this.state.currentChain,
324
+ expiresAt,
325
+ expiresIn,
326
+ identity: this.state.identity
327
+ };
328
+ this.state.keys = keys;
329
+ this.notifyListeners("KEYS_ROTATED", keys);
330
+ return { keys };
331
+ };
332
+ /**
333
+ * Derives a one-time key at a custom BIP44 path without storing it in the session.
334
+ * Useful for signing with different addresses or accounts.
335
+ * @param options - Derivation options with custom path
336
+ * @returns Promise resolving to the derived key data
337
+ * @throws {Error} If wallet is locked
338
+ */
339
+ deriveKey = async (options) => {
340
+ if (this.state.isLocked || !this.decryptedMnemonic || !this.currentAdapter) {
341
+ throw new Error("Identity must be unlocked to derive keys");
342
+ }
343
+ const keyData = await this.currentAdapter.deriveKeysAtPath(
344
+ this.decryptedMnemonic,
345
+ options.path
346
+ );
347
+ return {
348
+ privateKey: keyData.privateKeyHex,
349
+ publicKey: keyData.publicKeyHex,
350
+ address: keyData.address,
351
+ path: keyData.path
352
+ };
353
+ };
354
+ /**
355
+ * Derives a deterministic document ID using BIP44-style hierarchical derivation.
356
+ * Returns a hex-encoded ID (32 bytes / 64 hex characters).
357
+ * Path: m/44'/[appId]'/[account]'/[purpose]/[index]
358
+ * @param options - BIP44 derivation parameters (appId required, others default to 0)
359
+ * @returns Promise resolving to hex-encoded document ID (64 characters)
360
+ * @throws {Error} If wallet is locked or parameters are out of range
361
+ */
362
+ deriveBIP44DocumentID = async (options) => {
363
+ if (this.state.isLocked || !this.decryptedMnemonic) {
364
+ throw new Error(
365
+ "Wallet is locked. Call unlock() first to derive document IDs."
366
+ );
367
+ }
368
+ const { appId, account = 0, purpose = 0, index = 0 } = options;
369
+ if (appId === void 0 || appId === null) {
370
+ throw new Error(
371
+ "appId is required but was undefined. Please provide a valid appId number."
372
+ );
373
+ }
374
+ if (typeof appId !== "number" || isNaN(appId)) {
375
+ throw new Error(
376
+ `appId must be a valid number, received: ${typeof appId}`
377
+ );
378
+ }
379
+ const MAX_HARDENED = 2147483647;
380
+ if (appId < 0 || appId > MAX_HARDENED) {
381
+ throw new Error(
382
+ `Invalid appId: ${appId}. Must be between 0 and ${MAX_HARDENED}`
383
+ );
384
+ }
385
+ if (account < 0 || account > MAX_HARDENED) {
386
+ throw new Error(
387
+ `Invalid account: ${account}. Must be between 0 and ${MAX_HARDENED}`
388
+ );
389
+ }
390
+ if (purpose < 0 || purpose > MAX_HARDENED) {
391
+ throw new Error(
392
+ `Invalid purpose: ${purpose}. Must be between 0 and ${MAX_HARDENED}`
393
+ );
394
+ }
395
+ if (index < 0 || index > MAX_HARDENED) {
396
+ throw new Error(
397
+ `Invalid index: ${index}. Must be between 0 and ${MAX_HARDENED}`
398
+ );
399
+ }
400
+ const path = `m/44'/${appId}'/${account}'/${purpose}/${index}`;
401
+ const seed = (0, import_bip39.mnemonicToSeedSync)(this.decryptedMnemonic);
402
+ const masterKey = import_bip32.HDKey.fromMasterSeed(seed);
403
+ const derivedKey = masterKey.derive(path);
404
+ if (!derivedKey.publicKey) {
405
+ throw new Error(`Failed to derive key at path: ${path}`);
406
+ }
407
+ const publicKeyBuffer = new Uint8Array(derivedKey.publicKey);
408
+ const hashBuffer = await crypto.subtle.digest("SHA-256", publicKeyBuffer);
409
+ const hash = new Uint8Array(hashBuffer);
410
+ return bufferToHex(hash);
411
+ };
412
+ /**
413
+ * Derives a data encryption key using HKDF for encrypting/decrypting data.
414
+ * This key is deterministic (derived from mnemonic) and chain-independent.
415
+ * Perfect for document encryption, file storage, etc.
416
+ *
417
+ * @param options - Derivation options including purpose, version, algorithm
418
+ * @returns CryptoKey ready for use with Web Crypto API
419
+ *
420
+ * @example
421
+ * ```typescript
422
+ * const key = await auth.deriveDataEncryptionKey({
423
+ * purpose: 'automerge-documents',
424
+ * version: 1,
425
+ * });
426
+ *
427
+ * // Use with Web Crypto API
428
+ * const encrypted = await crypto.subtle.encrypt(
429
+ * { name: 'AES-GCM', iv },
430
+ * key,
431
+ * data
432
+ * );
433
+ * ```
434
+ */
435
+ deriveDataEncryptionKey = async (options) => {
436
+ if (this.state.isLocked || !this.decryptedMnemonic) {
437
+ throw new Error(
438
+ "Wallet is locked. Call unlock() first to derive data encryption keys."
439
+ );
440
+ }
441
+ const purpose = options.purpose;
442
+ const version = options.version || 1;
443
+ const algorithm = options.algorithm || "AES-GCM";
444
+ const length = options.length || 256;
445
+ const extractable = options.extractable || false;
446
+ const seed = (0, import_bip39.mnemonicToSeedSync)(this.decryptedMnemonic);
447
+ const info = new TextEncoder().encode(`CryptForge-${purpose}-v${version}`);
448
+ const seedBuffer = new Uint8Array(seed);
449
+ const keyMaterial = await crypto.subtle.importKey(
450
+ "raw",
451
+ seedBuffer,
452
+ "HKDF",
453
+ false,
454
+ ["deriveKey"]
455
+ );
456
+ const key = await crypto.subtle.deriveKey(
457
+ {
458
+ name: "HKDF",
459
+ hash: "SHA-256",
460
+ salt: new Uint8Array(),
461
+ // Empty salt (could be customized if needed)
462
+ info
463
+ },
464
+ keyMaterial,
465
+ {
466
+ name: algorithm,
467
+ length
468
+ },
469
+ extractable,
470
+ ["encrypt", "decrypt"]
471
+ );
472
+ return key;
473
+ };
474
+ /**
475
+ * Gets the address for a specific blockchain at a given index.
476
+ * @param chainId - Blockchain identifier
477
+ * @param index - Address index (default: 0)
478
+ * @returns Promise resolving to address, public key, and derivation path
479
+ * @throws {Error} If wallet is locked or adapter not registered
480
+ */
481
+ getAddressForChain = async (chainId, index = 0) => {
482
+ if (this.state.isLocked || !this.decryptedMnemonic) {
483
+ throw new Error("Identity must be unlocked to get addresses");
484
+ }
485
+ const adapter = this.getAdapter(chainId);
486
+ const result = await adapter.getAddressAtIndex(
487
+ this.decryptedMnemonic,
488
+ index
489
+ );
490
+ return {
491
+ address: result.address,
492
+ publicKey: result.publicKey,
493
+ derivationPath: result.path
494
+ };
495
+ };
496
+ /**
497
+ * Verify password without unlocking wallet
498
+ * Useful for transaction confirmation
499
+ * @param password - Password to verify
500
+ * @returns Promise resolving to true if password is correct
501
+ */
502
+ verifyPassword = async (password) => {
503
+ if (!this.state.identity) {
504
+ throw new Error("No identity selected");
505
+ }
506
+ try {
507
+ const stored = await getIdentityFromDB(this.state.identity.id);
508
+ if (!stored) return false;
509
+ await decryptMnemonic(stored.keystore, password);
510
+ return true;
511
+ } catch (error) {
512
+ return false;
513
+ }
514
+ };
515
+ // Cryptographic Operations
516
+ /**
517
+ * Signs a message using the current or specified private key.
518
+ * Performs soft expiration check (warns but doesn't block).
519
+ * @param options - Message and optional derivation path
520
+ * @returns Promise resolving to signature, address, and public key
521
+ * @throws {Error} If wallet is locked
522
+ */
523
+ signMessage = async (options) => {
524
+ if (this.state.isLocked || !this.state.keys || !this.currentAdapter) {
525
+ throw new Error("Identity must be unlocked to sign messages");
526
+ }
527
+ this.checkKeysExpiration();
528
+ let privateKey = this.state.keys.privateKey;
529
+ let address = this.state.keys.address;
530
+ let publicKey = this.state.keys.publicKeyHex;
531
+ if (options.derivationPath && this.decryptedMnemonic) {
532
+ const keyData = await this.currentAdapter.deriveKeysAtPath(
533
+ this.decryptedMnemonic,
534
+ options.derivationPath
535
+ );
536
+ privateKey = keyData.privateKey;
537
+ address = keyData.address;
538
+ publicKey = keyData.publicKeyHex;
539
+ }
540
+ const result = await this.currentAdapter.signMessage(
541
+ privateKey,
542
+ options.message
543
+ );
544
+ return {
545
+ signature: result.signature,
546
+ address,
547
+ publicKey
548
+ };
549
+ };
550
+ /**
551
+ * Signs a blockchain transaction using the current or specified private key.
552
+ * Performs soft expiration check (warns but doesn't block).
553
+ * @param options - Transaction object and optional derivation path
554
+ * @returns Promise resolving to signed transaction and signature
555
+ * @throws {Error} If wallet is locked
556
+ */
557
+ signTransaction = async (options) => {
558
+ if (this.state.isLocked || !this.state.keys || !this.currentAdapter) {
559
+ throw new Error("Identity must be unlocked to sign transactions");
560
+ }
561
+ this.checkKeysExpiration();
562
+ let privateKey = this.state.keys.privateKey;
563
+ if (options.derivationPath && this.decryptedMnemonic) {
564
+ const keyData = await this.currentAdapter.deriveKeysAtPath(
565
+ this.decryptedMnemonic,
566
+ options.derivationPath
567
+ );
568
+ privateKey = keyData.privateKey;
569
+ }
570
+ const result = await this.currentAdapter.signTransaction(
571
+ privateKey,
572
+ options.transaction
573
+ );
574
+ return {
575
+ signedTransaction: result.signedTransaction,
576
+ signature: result.signature
577
+ };
578
+ };
579
+ /**
580
+ * Verifies a signature against a message and public key using the current adapter.
581
+ * @param message - Message that was signed (string or bytes)
582
+ * @param signature - Signature to verify
583
+ * @param publicKey - Public key to verify against
584
+ * @returns Promise resolving to true if signature is valid
585
+ * @throws {Error} If no adapter is selected
586
+ */
587
+ verifySignature = async (message, signature, publicKey) => {
588
+ if (!this.currentAdapter) {
589
+ throw new Error("No adapter selected. Please unlock with a chain first.");
590
+ }
591
+ return this.currentAdapter.verifySignature(message, signature, publicKey);
592
+ };
593
+ // Identity Management
594
+ /**
595
+ * Lists all identities stored in IndexedDB.
596
+ * @returns Promise resolving to array of all identities
597
+ */
598
+ listIdentities = async () => {
599
+ const stored = await getAllIdentitiesFromDB();
600
+ return stored.map((s) => ({
601
+ id: s.id,
602
+ publicKey: s.publicKey,
603
+ fingerprint: s.fingerprint,
604
+ label: s.label,
605
+ metadata: s.metadata,
606
+ createdAt: new Date(s.createdAt),
607
+ lastAccess: s.lastAccess ? new Date(s.lastAccess) : void 0
608
+ }));
609
+ };
610
+ /**
611
+ * Switches to a different identity. Locks the current wallet first.
612
+ * @param identityId - ID of the identity to switch to
613
+ * @returns Promise resolving to the selected identity
614
+ * @throws {Error} If identity not found
615
+ */
616
+ switchIdentity = async (identityId) => {
617
+ const stored = await getIdentityFromDB(identityId);
618
+ if (!stored) throw new Error("Identity not found");
619
+ await this.lock();
620
+ const identity = {
621
+ id: stored.id,
622
+ publicKey: stored.publicKey,
623
+ fingerprint: stored.fingerprint,
624
+ label: stored.label,
625
+ metadata: stored.metadata,
626
+ createdAt: new Date(stored.createdAt),
627
+ lastAccess: stored.lastAccess ? new Date(stored.lastAccess) : void 0
628
+ };
629
+ this.state.identity = identity;
630
+ this.notifyListeners("IDENTITY_SWITCHED", null);
631
+ return { identity };
632
+ };
633
+ /**
634
+ * Updates the label or metadata for an identity.
635
+ * @param identityId - ID of the identity to update
636
+ * @param updates - Label and/or metadata to update
637
+ * @returns Promise resolving to the updated identity
638
+ * @throws {Error} If identity not found
639
+ */
640
+ updateIdentity = async (identityId, updates) => {
641
+ const stored = await getIdentityFromDB(identityId);
642
+ if (!stored) throw new Error("Identity not found");
643
+ if (updates.label !== void 0) {
644
+ stored.label = updates.label;
645
+ }
646
+ if (updates.metadata !== void 0) {
647
+ stored.metadata = { ...stored.metadata, ...updates.metadata };
648
+ }
649
+ await saveIdentityToDB(stored);
650
+ const identity = {
651
+ id: stored.id,
652
+ publicKey: stored.publicKey,
653
+ fingerprint: stored.fingerprint,
654
+ label: stored.label,
655
+ metadata: stored.metadata,
656
+ createdAt: new Date(stored.createdAt),
657
+ lastAccess: stored.lastAccess ? new Date(stored.lastAccess) : void 0
658
+ };
659
+ if (this.state.identity?.id === identityId) {
660
+ this.state.identity = identity;
661
+ }
662
+ this.notifyListeners("IDENTITY_UPDATED", this.state.keys);
663
+ return { identity };
664
+ };
665
+ /**
666
+ * Permanently deletes an identity from IndexedDB. Requires password verification.
667
+ * Locks wallet if deleting current identity.
668
+ * @param identityId - ID of the identity to delete
669
+ * @param password - Password to verify ownership
670
+ * @returns Promise that resolves when deleted
671
+ * @throws {Error} If identity not found or password incorrect
672
+ */
673
+ deleteIdentity = async (identityId, password) => {
674
+ const stored = await getIdentityFromDB(identityId);
675
+ if (!stored) throw new Error("Identity not found");
676
+ try {
677
+ await decryptMnemonic(stored.keystore, password);
678
+ } catch (e) {
679
+ throw new Error("Invalid password");
680
+ }
681
+ if (this.state.identity?.id === identityId) {
682
+ await this.lock();
683
+ this.state.identity = null;
684
+ }
685
+ await deleteIdentityFromDB(identityId);
686
+ this.notifyListeners("IDENTITY_DELETED", this.state.keys);
687
+ };
688
+ /**
689
+ * Changes the password for an identity's encrypted keystore.
690
+ * Re-encrypts the mnemonic with the new password.
691
+ * @param identityId - ID of the identity
692
+ * @param oldPassword - Current password
693
+ * @param newPassword - New password
694
+ * @returns Promise that resolves when password is changed
695
+ * @throws {Error} If identity not found or old password incorrect
696
+ */
697
+ changePassword = async (identityId, oldPassword, newPassword) => {
698
+ const stored = await getIdentityFromDB(identityId);
699
+ if (!stored) throw new Error("Identity not found");
700
+ const mnemonic = await decryptMnemonic(stored.keystore, oldPassword);
701
+ const newKeystore = await encryptMnemonic(mnemonic, newPassword);
702
+ stored.keystore = newKeystore;
703
+ await saveIdentityToDB(stored);
704
+ this.notifyListeners("PASSWORD_CHANGED", this.state.keys);
705
+ };
706
+ // Import/Export
707
+ /**
708
+ * Exports the mnemonic phrase for an identity.
709
+ * Requires password verification to decrypt the keystore.
710
+ * ⚠️ Security: Only export mnemonics to secure locations (password managers, paper backup).
711
+ * @param identityId - ID of the identity to export
712
+ * @param password - Password to decrypt the keystore
713
+ * @returns Promise resolving to the mnemonic phrase
714
+ * @throws {Error} If identity not found or password incorrect
715
+ */
716
+ exportMnemonic = async (identityId, password) => {
717
+ const stored = await getIdentityFromDB(identityId);
718
+ if (!stored) throw new Error("Identity not found");
719
+ const mnemonic = await decryptMnemonic(stored.keystore, password);
720
+ return mnemonic;
721
+ };
722
+ /**
723
+ * Exports the encrypted keystore JSON for an identity.
724
+ * No password required - keystore is already encrypted.
725
+ * Perfect for encrypted backup files.
726
+ * @param identityId - ID of the identity to export
727
+ * @returns Promise resolving to encrypted keystore JSON string
728
+ * @throws {Error} If identity not found
729
+ */
730
+ exportKeystore = async (identityId) => {
731
+ const stored = await getIdentityFromDB(identityId);
732
+ if (!stored) throw new Error("Identity not found");
733
+ return stored.keystore;
734
+ };
735
+ /**
736
+ * Exports the complete StoredIdentity object including metadata.
737
+ * No password required - keystore within is already encrypted.
738
+ * Perfect for migrating identities between devices/browsers with all metadata intact.
739
+ * @param identityId - ID of the identity to export
740
+ * @returns Promise resolving to complete StoredIdentity object
741
+ * @throws {Error} If identity not found
742
+ */
743
+ exportIdentity = async (identityId) => {
744
+ const stored = await getIdentityFromDB(identityId);
745
+ if (!stored) throw new Error("Identity not found");
746
+ return stored;
747
+ };
748
+ /**
749
+ * Imports an identity from a mnemonic phrase.
750
+ * Creates and encrypts a new identity in IndexedDB with the provided password.
751
+ * @param mnemonic - BIP39 mnemonic phrase (12 or 24 words)
752
+ * @param password - Password to encrypt the new identity
753
+ * @param label - Optional label for the wallet (default: "Imported Wallet")
754
+ * @returns Promise resolving to the created identity
755
+ * @throws {Error} If mnemonic is invalid
756
+ */
757
+ importMnemonic = async (mnemonic, password, label) => {
758
+ const trimmedMnemonic = mnemonic.trim();
759
+ if (!(0, import_bip39.validateMnemonic)(trimmedMnemonic, import_english.wordlist)) {
760
+ throw new Error("Invalid mnemonic phrase");
761
+ }
762
+ const result = await this.createIdentity({
763
+ mnemonic: trimmedMnemonic,
764
+ password,
765
+ label: label || "Imported Wallet"
766
+ });
767
+ return { identity: result.identity };
768
+ };
769
+ /**
770
+ * Imports an identity from an encrypted keystore JSON.
771
+ * Decrypts the keystore and creates a new identity in IndexedDB.
772
+ * @param keystoreJson - Encrypted keystore JSON string
773
+ * @param password - Password to decrypt the keystore
774
+ * @param label - Optional label for the wallet (default: "Imported Wallet")
775
+ * @returns Promise resolving to the created identity
776
+ * @throws {Error} If keystore is invalid or password incorrect
777
+ */
778
+ importKeystore = async (keystoreJson, password, label) => {
779
+ const mnemonic = await decryptMnemonic(keystoreJson, password);
780
+ if (!(0, import_bip39.validateMnemonic)(mnemonic, import_english.wordlist)) {
781
+ throw new Error("Decrypted mnemonic is invalid");
782
+ }
783
+ const result = await this.createIdentity({
784
+ mnemonic,
785
+ password,
786
+ label: label || "Imported Wallet"
787
+ });
788
+ return { identity: result.identity };
789
+ };
790
+ /**
791
+ * Imports a complete StoredIdentity object.
792
+ * No password required - keystore is already encrypted.
793
+ * Perfect for migrating identities between devices/browsers with all metadata intact.
794
+ * Note: This will overwrite any existing identity with the same ID.
795
+ * @param storedIdentity - Complete StoredIdentity object to import
796
+ * @returns Promise resolving to the imported identity
797
+ * @throws {Error} If stored identity data is invalid
798
+ */
799
+ importIdentity = async (storedIdentity) => {
800
+ if (!storedIdentity.id || !storedIdentity.keystore || !storedIdentity.fingerprint) {
801
+ throw new Error(
802
+ "Invalid StoredIdentity object - missing required fields"
803
+ );
804
+ }
805
+ await saveIdentityToDB(storedIdentity);
806
+ const identity = {
807
+ id: storedIdentity.id,
808
+ publicKey: storedIdentity.publicKey,
809
+ fingerprint: storedIdentity.fingerprint,
810
+ label: storedIdentity.label,
811
+ metadata: storedIdentity.metadata,
812
+ createdAt: new Date(storedIdentity.createdAt),
813
+ lastAccess: storedIdentity.lastAccess ? new Date(storedIdentity.lastAccess) : void 0
814
+ };
815
+ this.notifyListeners("IDENTITY_IMPORTED", null);
816
+ return { identity };
817
+ };
818
+ // Address Management
819
+ /**
820
+ * Gets multiple addresses for a blockchain starting from a specific index.
821
+ * @param chainId - Blockchain identifier
822
+ * @param start - Starting index (default: 0)
823
+ * @param count - Number of addresses to generate (default: 20)
824
+ * @returns Promise resolving to array of addresses with paths
825
+ * @throws {Error} If wallet is locked or adapter not registered
826
+ */
827
+ getAddresses = async (chainId, start = 0, count = 20) => {
828
+ if (this.state.isLocked || !this.decryptedMnemonic) {
829
+ throw new Error("Identity must be unlocked to get addresses");
830
+ }
831
+ const adapter = this.getAdapter(chainId);
832
+ return adapter.getAddresses(this.decryptedMnemonic, start, count);
833
+ };
834
+ /**
835
+ * Finds all used addresses by checking balances with BIP44 gap limit of 20.
836
+ * Useful for account discovery when restoring wallets.
837
+ * @param chainId - Blockchain identifier
838
+ * @param checkBalance - Function that returns true if address has balance
839
+ * @returns Promise resolving to array of used addresses
840
+ * @throws {Error} If wallet is locked or adapter not registered
841
+ */
842
+ findUsedAddresses = async (chainId, checkBalance) => {
843
+ if (this.state.isLocked || !this.decryptedMnemonic) {
844
+ throw new Error("Identity must be unlocked to find addresses");
845
+ }
846
+ const adapter = this.getAdapter(chainId);
847
+ const usedAddresses = [];
848
+ let gapCount = 0;
849
+ const gapLimit = 20;
850
+ let index = 0;
851
+ while (gapCount < gapLimit) {
852
+ const addresses = await adapter.getAddresses(
853
+ this.decryptedMnemonic,
854
+ index,
855
+ 1
856
+ );
857
+ const addressData = addresses[0];
858
+ const hasBalance = await checkBalance(addressData.address);
859
+ if (hasBalance) {
860
+ usedAddresses.push(addressData);
861
+ gapCount = 0;
862
+ } else {
863
+ gapCount++;
864
+ }
865
+ index++;
866
+ }
867
+ return usedAddresses;
868
+ };
869
+ // State Management
870
+ /**
871
+ * Subscribes to authentication state changes.
872
+ * @param callback - Function called on each auth event with event type and keys
873
+ * @returns Unsubscribe function
874
+ */
875
+ onAuthStateChange = (callback) => {
876
+ this.listeners.add(callback);
877
+ return () => {
878
+ this.listeners.delete(callback);
879
+ };
880
+ };
881
+ // Getters for current state
882
+ /** Gets the current active identity, or null if none selected. */
883
+ get currentIdentity() {
884
+ return this.state.identity;
885
+ }
886
+ /** Gets the current derived keys, or null if wallet is locked. */
887
+ get currentKeys() {
888
+ return this.state.keys;
889
+ }
890
+ /** Gets the current blockchain, or null if none selected. */
891
+ get currentChain() {
892
+ return this.state.currentChain;
893
+ }
894
+ /** Gets the current blockchain address, or null if locked. */
895
+ get currentAddress() {
896
+ return this.state.keys?.address ?? null;
897
+ }
898
+ /** Gets the current public key as hex string, or null if locked. */
899
+ get currentPublicKey() {
900
+ return this.state.keys?.publicKeyHex ?? null;
901
+ }
902
+ /** Gets the key expiration date, or null if no expiration set. */
903
+ get currentExpiresAt() {
904
+ return this.state.keys?.expiresAt ?? null;
905
+ }
906
+ /** Gets the remaining seconds until key expiration, or null if no expiration set. */
907
+ get currentExpiresIn() {
908
+ if (!this.state.keys?.expiresAt) return null;
909
+ const remaining = Math.floor(
910
+ (this.state.keys.expiresAt.getTime() - Date.now()) / 1e3
911
+ );
912
+ return Math.max(0, remaining);
913
+ }
914
+ /** Returns true if wallet is locked (keys cleared from memory). */
915
+ get isLocked() {
916
+ return this.state.isLocked;
917
+ }
918
+ /** Returns true if wallet is unlocked with active keys. */
919
+ get isUnlocked() {
920
+ return !this.state.isLocked && this.state.keys !== null;
921
+ }
922
+ /** Returns true if an identity has been created or selected. */
923
+ get hasIdentity() {
924
+ return this.state.identity !== null;
925
+ }
926
+ /**
927
+ * Gets the chain-independent master public key (33 bytes, compressed secp256k1).
928
+ * Safe to expose publicly - does NOT include chaincode.
929
+ * Perfect for document ownership and cross-chain identity verification.
930
+ * @returns Hex-encoded master public key, or null if locked
931
+ */
932
+ get masterPublicKey() {
933
+ if (this.state.isLocked || !this.decryptedMnemonic) {
934
+ return null;
935
+ }
936
+ const seed = (0, import_bip39.mnemonicToSeedSync)(this.decryptedMnemonic);
937
+ const masterNode = import_bip32.HDKey.fromMasterSeed(seed);
938
+ return bufferToHex(masterNode.publicKey);
939
+ }
940
+ // Private Methods
941
+ isKeysExpired() {
942
+ if (!this.state.keys?.expiresAt) return false;
943
+ return Date.now() >= this.state.keys.expiresAt.getTime();
944
+ }
945
+ checkKeysExpiration() {
946
+ if (this.isKeysExpired()) {
947
+ console.warn(
948
+ "CryptForge: Keys have expired. Consider unlocking again for security."
949
+ );
950
+ this.notifyListeners("KEYS_EXPIRED", null);
951
+ }
952
+ }
953
+ async deriveKeysWithAdapter(mnemonic, chainId, adapter, identity, duration) {
954
+ const keyData = await adapter.deriveKeys(mnemonic);
955
+ const durationMs = duration || 36e5;
956
+ const expiresAt = new Date(Date.now() + durationMs);
957
+ const expiresIn = Math.floor(durationMs / 1e3);
958
+ return {
959
+ privateKey: keyData.privateKey,
960
+ privateKeyHex: keyData.privateKeyHex,
961
+ publicKey: keyData.publicKey,
962
+ publicKeyHex: keyData.publicKeyHex,
963
+ address: keyData.address,
964
+ derivationPath: keyData.path,
965
+ chain: {
966
+ id: chainId,
967
+ name: adapter.chainData.name,
968
+ symbol: adapter.chainData.symbol
969
+ },
970
+ expiresAt,
971
+ expiresIn,
972
+ identity
973
+ };
974
+ }
975
+ notifyListeners(event, keys) {
976
+ this.listeners.forEach((callback) => callback(event, keys));
977
+ }
978
+ setAutoLockTimer(duration) {
979
+ if (this.lockTimer) {
980
+ window.clearTimeout(this.lockTimer);
981
+ }
982
+ this.lockTimer = window.setTimeout(() => this.lock(), duration);
983
+ }
984
+ };
985
+ var createAuthClient = () => {
986
+ return new AuthClient();
987
+ };
988
+ var getMasterNode = (mnemonic) => {
989
+ const seed = (0, import_bip39.mnemonicToSeedSync)(mnemonic);
990
+ return import_bip32.HDKey.fromMasterSeed(seed);
991
+ };
992
+ var getMasterFingerprint = (mnemonic) => {
993
+ const root = getMasterNode(mnemonic);
994
+ return root.fingerprint.toString(16).padStart(8, "0").toUpperCase();
995
+ };
996
+ var getMasterPublicKey = (mnemonic) => {
997
+ const root = getMasterNode(mnemonic);
998
+ return bufferToHex(root.publicKey);
999
+ };
1000
+ function bufferToHex(buf) {
1001
+ return Array.from(buf).map((b) => b.toString(16).padStart(2, "0")).join("");
1002
+ }
1003
+ function concatUint8(a, b) {
1004
+ const c = new Uint8Array(a.length + b.length);
1005
+ c.set(a, 0);
1006
+ c.set(b, a.length);
1007
+ return c;
1008
+ }
1009
+ function hexToUint8(hex) {
1010
+ if (hex.length % 2 !== 0) throw new Error("Invalid hex string");
1011
+ const arr = new Uint8Array(hex.length / 2);
1012
+ for (let i = 0; i < arr.length; i++) {
1013
+ arr[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
1014
+ }
1015
+ return arr;
1016
+ }
1017
+ function arraysEqual(a, b) {
1018
+ if (a.length !== b.length) return false;
1019
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
1020
+ return true;
1021
+ }
1022
+ var PBKDF2_ITERATIONS = 1e5;
1023
+ var KEY_LENGTH = 32;
1024
+ function randomBytes(length) {
1025
+ const arr = new Uint8Array(length);
1026
+ crypto.getRandomValues(arr);
1027
+ return arr;
1028
+ }
1029
+ var encryptMnemonic = async (mnemonic, password) => {
1030
+ const salt = randomBytes(32);
1031
+ const iv = randomBytes(16);
1032
+ const keyMaterial = await crypto.subtle.importKey(
1033
+ "raw",
1034
+ new TextEncoder().encode(password),
1035
+ "PBKDF2",
1036
+ false,
1037
+ ["deriveKey"]
1038
+ );
1039
+ const key = await crypto.subtle.deriveKey(
1040
+ {
1041
+ name: "PBKDF2",
1042
+ salt,
1043
+ iterations: PBKDF2_ITERATIONS,
1044
+ hash: "SHA-256"
1045
+ },
1046
+ keyMaterial,
1047
+ { name: "AES-CBC", length: 256 },
1048
+ true,
1049
+ ["encrypt", "decrypt"]
1050
+ );
1051
+ const encryptedBuffer = await crypto.subtle.encrypt(
1052
+ { name: "AES-CBC", iv },
1053
+ key,
1054
+ new TextEncoder().encode(mnemonic)
1055
+ );
1056
+ const ciphertext = new Uint8Array(encryptedBuffer);
1057
+ const macKey = await crypto.subtle.importKey(
1058
+ "raw",
1059
+ await crypto.subtle.exportKey("raw", key),
1060
+ { name: "HMAC", hash: "SHA-256" },
1061
+ false,
1062
+ ["sign"]
1063
+ );
1064
+ const macBuffer = await crypto.subtle.sign(
1065
+ "HMAC",
1066
+ macKey,
1067
+ concatUint8(ciphertext, iv)
1068
+ );
1069
+ const keystore = {
1070
+ version: 1,
1071
+ id: bufferToHex(randomBytes(16)),
1072
+ crypto: {
1073
+ cipher: "aes-256-cbc",
1074
+ ciphertext: bufferToHex(ciphertext),
1075
+ cipherparams: { iv: bufferToHex(iv) },
1076
+ kdf: "pbkdf2",
1077
+ kdfparams: {
1078
+ salt: bufferToHex(salt),
1079
+ iterations: PBKDF2_ITERATIONS,
1080
+ keylen: KEY_LENGTH
1081
+ },
1082
+ mac: bufferToHex(new Uint8Array(macBuffer))
1083
+ }
1084
+ };
1085
+ return JSON.stringify(keystore);
1086
+ };
1087
+ async function decryptMnemonic(keystoreJson, password) {
1088
+ const keystore = JSON.parse(keystoreJson);
1089
+ const salt = hexToUint8(keystore.crypto.kdfparams.salt);
1090
+ const iv = hexToUint8(keystore.crypto.cipherparams.iv);
1091
+ const ciphertext = hexToUint8(keystore.crypto.ciphertext);
1092
+ const storedMac = hexToUint8(keystore.crypto.mac);
1093
+ const keyMaterial = await crypto.subtle.importKey(
1094
+ "raw",
1095
+ new TextEncoder().encode(password),
1096
+ "PBKDF2",
1097
+ false,
1098
+ ["deriveKey"]
1099
+ );
1100
+ const key = await crypto.subtle.deriveKey(
1101
+ {
1102
+ name: "PBKDF2",
1103
+ salt,
1104
+ iterations: keystore.crypto.kdfparams.iterations,
1105
+ hash: "SHA-256"
1106
+ },
1107
+ keyMaterial,
1108
+ { name: "AES-CBC", length: 256 },
1109
+ true,
1110
+ ["encrypt", "decrypt"]
1111
+ );
1112
+ const macKey = await crypto.subtle.importKey(
1113
+ "raw",
1114
+ await crypto.subtle.exportKey("raw", key),
1115
+ { name: "HMAC", hash: "SHA-256" },
1116
+ false,
1117
+ ["sign"]
1118
+ );
1119
+ const computedMacBuffer = await crypto.subtle.sign(
1120
+ "HMAC",
1121
+ macKey,
1122
+ concatUint8(ciphertext, iv)
1123
+ );
1124
+ const computedMac = new Uint8Array(computedMacBuffer);
1125
+ if (!arraysEqual(computedMac, storedMac)) {
1126
+ throw new Error("Invalid password - MAC verification failed");
1127
+ }
1128
+ const decryptedBuffer = await crypto.subtle.decrypt(
1129
+ { name: "AES-CBC", iv },
1130
+ key,
1131
+ ciphertext
1132
+ );
1133
+ const mnemonic = new TextDecoder().decode(decryptedBuffer);
1134
+ if (!mnemonic) {
1135
+ throw new Error("Invalid password - decryption failed");
1136
+ }
1137
+ return mnemonic;
1138
+ }
1139
+ var DB_NAME = "CryptoAuthDB";
1140
+ var STORE_NAME = "identities";
1141
+ var openDB = () => {
1142
+ return new Promise((resolve, reject) => {
1143
+ const request = indexedDB.open(DB_NAME, 1);
1144
+ request.onerror = () => reject(request.error);
1145
+ request.onsuccess = () => resolve(request.result);
1146
+ request.onupgradeneeded = (event) => {
1147
+ const db = event.target.result;
1148
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
1149
+ db.createObjectStore(STORE_NAME, { keyPath: "id" });
1150
+ }
1151
+ };
1152
+ });
1153
+ };
1154
+ var saveIdentityToDB = async (identity) => {
1155
+ const db = await openDB();
1156
+ return new Promise((resolve, reject) => {
1157
+ const transaction = db.transaction([STORE_NAME], "readwrite");
1158
+ const store = transaction.objectStore(STORE_NAME);
1159
+ const request = store.put(identity);
1160
+ request.onsuccess = () => resolve();
1161
+ request.onerror = () => reject(request.error);
1162
+ });
1163
+ };
1164
+ var getAllIdentitiesFromDB = async () => {
1165
+ const db = await openDB();
1166
+ return new Promise((resolve, reject) => {
1167
+ const transaction = db.transaction([STORE_NAME], "readonly");
1168
+ const store = transaction.objectStore(STORE_NAME);
1169
+ const request = store.getAll();
1170
+ request.onsuccess = () => resolve(request.result);
1171
+ request.onerror = () => reject(request.error);
1172
+ });
1173
+ };
1174
+ var getIdentityFromDB = async (id) => {
1175
+ const db = await openDB();
1176
+ return new Promise((resolve, reject) => {
1177
+ const transaction = db.transaction([STORE_NAME], "readonly");
1178
+ const store = transaction.objectStore(STORE_NAME);
1179
+ const request = store.get(id);
1180
+ request.onsuccess = () => resolve(request.result);
1181
+ request.onerror = () => reject(request.error);
1182
+ });
1183
+ };
1184
+ var deleteIdentityFromDB = async (id) => {
1185
+ const db = await openDB();
1186
+ return new Promise((resolve, reject) => {
1187
+ const transaction = db.transaction([STORE_NAME], "readwrite");
1188
+ const store = transaction.objectStore(STORE_NAME);
1189
+ const request = store.delete(id);
1190
+ request.onsuccess = () => resolve();
1191
+ request.onerror = () => reject(request.error);
1192
+ });
1193
+ };
1194
+ // Annotate the CommonJS export names for ESM import in node:
1195
+ 0 && (module.exports = {
1196
+ AuthClient,
1197
+ createAuthClient
1198
+ });