@sovereignbase/explorer 0.0.0-alpha.4 → 0.0.0-alpha.6

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/class.cjs CHANGED
@@ -57,10 +57,11 @@ function unknownError(cause, operation) {
57
57
  }
58
58
  // src/CredentialEntries/class.ts
59
59
  /**
60
- * Maintains the database's credential entries.
60
+ * Maintains the database's registered credentials.
61
61
  *
62
- * Entries are identified by credential ID and synchronized through
63
- * a sequenced array. Changes are persisted as encrypted snapshots.
62
+ * Entries are identified by their object and credential identifiers.
63
+ * Changes are synchronized through a sequenced array and persisted
64
+ * as encrypted snapshots.
64
65
  */
65
66
  var CredentialEntries = class {
66
67
  id;
@@ -74,7 +75,7 @@ var CredentialEntries = class {
74
75
  *
75
76
  * @param id The identifier of the persisted entries object.
76
77
  * @param cipherKey The key used to encrypt the entries object.
77
- * @param sessionCredentialID The credential ID of the current session.
78
+ * @param sessionCredentialID The WebAuthn credential ID of the current session.
78
79
  * @param actorID The actor identifier used by the sequenced array.
79
80
  * @param trustedSnapshot An optional snapshot used to initialize the state.
80
81
  */
@@ -100,13 +101,17 @@ var CredentialEntries = class {
100
101
  this.state.addEventListener("change", ({ detail }) => {
101
102
  this.dispatchEvent("change", detail);
102
103
  });
103
- const seen = /* @__PURE__ */ new Set();
104
+ const seenObjects = /* @__PURE__ */ new Set();
105
+ const seenCredentials = /* @__PURE__ */ new Set();
104
106
  const duplicates = [];
105
107
  for (let index = 0; index < this.state.length; index++) {
106
108
  const entry = this.state.at(index);
107
109
  if (!entry) continue;
108
- if (seen.has(entry.id)) duplicates.push(index);
109
- else seen.add(entry.id);
110
+ if (seenObjects.has(entry.objectID) || seenCredentials.has(entry.credentialID)) duplicates.push(index);
111
+ else {
112
+ seenObjects.add(entry.objectID);
113
+ seenCredentials.add(entry.credentialID);
114
+ }
110
115
  }
111
116
  for (let index = duplicates.length - 1; index >= 0; index--) this.state.delete(duplicates[index]);
112
117
  if (duplicates.length > 0 || this.deltaBuffer.length > 0) this.state.snapshot();
@@ -127,17 +132,17 @@ var CredentialEntries = class {
127
132
  record(credentialEvent) {
128
133
  try {
129
134
  if (!credentialEvent || typeof credentialEvent !== "object") throw new ExplorerError("INVALID_CREDENTIAL_EVENT", "A credential event must be an object.");
130
- const { id, timestamp, userAgent, name, entropy, storage } = credentialEvent;
131
- if (typeof id !== "string" || typeof timestamp !== "number" || !Number.isFinite(timestamp) || typeof userAgent !== "string") throw new ExplorerError("INVALID_CREDENTIAL_EVENT", "A credential event requires an ID, a finite timestamp, and a user agent.");
135
+ const { objectID, credentialID, timestamp, userAgent, name, entropy, storage } = credentialEvent;
136
+ if (typeof objectID !== "string" || typeof timestamp !== "number" || !Number.isFinite(timestamp) || typeof userAgent !== "string") throw new ExplorerError("INVALID_CREDENTIAL_EVENT", "A credential event requires an object ID, a finite timestamp, and a user agent.");
132
137
  let existing;
133
138
  for (let index = this.state.length - 1; index >= 0; index--) {
134
139
  const entry = this.state.at(index);
135
- if (entry?.id === id) {
140
+ if (entry?.objectID === objectID || credentialID !== void 0 && entry?.credentialID === credentialID) {
136
141
  existing = entry;
137
142
  break;
138
143
  }
139
144
  }
140
- if (!existing && (typeof name !== "string" || !(entropy instanceof Uint8Array) || typeof storage !== "string")) throw new ExplorerError("MISSING_CREDENTIAL_SETUP_PROPERTIES", "A new credential requires a name, entropy, and binding storage.");
145
+ if (!existing && (typeof credentialID !== "string" || typeof name !== "string" || !(entropy instanceof Uint8Array) || typeof storage !== "string")) throw new ExplorerError("MISSING_CREDENTIAL_SETUP_PROPERTIES", "A new credential requires a credential ID, name, entropy, and binding storage.");
141
146
  const userAgents = existing?.userAgents.map((agent) => ({ ...agent })) ?? [];
142
147
  const agent = userAgents.find((agent) => agent.name === userAgent);
143
148
  if (agent) agent.lastSeen = Math.max(agent.lastSeen, timestamp);
@@ -146,14 +151,18 @@ var CredentialEntries = class {
146
151
  lastSeen: timestamp
147
152
  });
148
153
  const entry = {
149
- id,
154
+ objectID,
155
+ credentialID: credentialID ?? existing.credentialID,
150
156
  name: name ?? existing.name,
151
157
  entropy: entropy ?? existing.entropy,
152
158
  storage: storage ?? existing.storage,
153
159
  lastUsed: Math.max(existing?.lastUsed ?? timestamp, timestamp),
154
160
  userAgents
155
161
  };
156
- for (let index = this.state.length - 1; index >= 0; index--) if (this.state.at(index)?.id === id) this.state.delete(index);
162
+ for (let index = this.state.length - 1; index >= 0; index--) {
163
+ const current = this.state.at(index);
164
+ if (current?.objectID === entry.objectID || current?.credentialID === entry.credentialID) this.state.delete(index);
165
+ }
157
166
  this.state.unshift(entry);
158
167
  this.state.snapshot();
159
168
  } catch (cause) {
@@ -161,24 +170,33 @@ var CredentialEntries = class {
161
170
  }
162
171
  }
163
172
  /**
164
- * Revokes a credential by deleting its persisted data and list entries.
173
+ * Revokes a credential and removes its registered entries.
165
174
  *
166
- * The list remains unchanged if deletion of the persisted credential fails.
175
+ * Deletes the credential's persisted objects before removing its entries.
176
+ * The entries remain unchanged if deletion fails. Credential invalidation
177
+ * is requested on a best-effort basis after successful removal.
167
178
  *
168
- * @param credentialID The identifier of the credential to revoke.
179
+ * @param credentialID The WebAuthn credential identifier to revoke.
169
180
  */
170
181
  async revoke(credentialID) {
171
182
  try {
172
- let exists = false;
183
+ const objectIDs = /* @__PURE__ */ new Set();
173
184
  for (let index = this.state.length - 1; index >= 0; index--) {
174
- if (this.state.at(index)?.id !== credentialID) continue;
175
- exists = true;
176
- break;
185
+ const entry = this.state.at(index);
186
+ if (entry?.credentialID === credentialID) objectIDs.add(entry.objectID);
177
187
  }
178
- if (!exists) return;
179
- await Explorer.deleteObjectByID(credentialID);
180
- for (let index = this.state.length - 1; index >= 0; index--) if (this.state.at(index)?.id === credentialID) this.state.delete(index);
181
- this.state.snapshot();
188
+ if (objectIDs.size === 0) return;
189
+ for (const objectID of objectIDs) await Explorer.deleteObjectByID(objectID);
190
+ let removed = false;
191
+ for (let index = this.state.length - 1; index >= 0; index--) if (this.state.at(index)?.credentialID === credentialID) {
192
+ this.state.delete(index);
193
+ removed = true;
194
+ }
195
+ if (removed) this.state.snapshot();
196
+ try {
197
+ await (0, _sovereignbase_hardware_bound.invalidateDeviceBinding)(credentialID);
198
+ } catch {}
199
+ if (credentialID === this.sessionCredentialID) window.location.reload();
182
200
  } catch (cause) {
183
201
  throw unknownError(cause, "CredentialEntries.revoke()");
184
202
  }
@@ -186,11 +204,11 @@ var CredentialEntries = class {
186
204
  /**
187
205
  * Returns the credential entries ordered by most recent use.
188
206
  *
189
- * Entries with equal timestamps are ordered by identifier.
207
+ * Entries with equal timestamps are ordered by credential identifier.
190
208
  */
191
209
  list() {
192
210
  try {
193
- return this.state.slice().sort((a, b) => b.lastUsed - a.lastUsed || a.id.localeCompare(b.id));
211
+ return this.state.slice().sort((a, b) => b.lastUsed - a.lastUsed || a.credentialID.localeCompare(b.credentialID));
194
212
  } catch (cause) {
195
213
  throw unknownError(cause, "CredentialEntries.list()");
196
214
  }
@@ -439,20 +457,27 @@ var RecentEntries = class {
439
457
  };
440
458
  // src/class.ts
441
459
  /**
442
- * Provides authentication, encrypted object storage, and access to
443
- * the database's synchronized entries.
460
+ * Provides access to an authenticated Sovereignbase database.
444
461
  *
445
- * Maintains the authenticated database context and exposes static methods
446
- * for managing stored objects, observing entries, and applying remote deltas.
462
+ * Manages database authentication, encrypted object storage, credential
463
+ * registration, database linking, and synchronized entries.
447
464
  */
448
465
  var Explorer = class {
449
466
  /** The identifier of the authenticated database. */
450
467
  static databaseID;
451
- /** Indicates whether the database has been authenticated. */
468
+ /** Indicates whether a database has been authenticated. */
452
469
  static isAuthenticated;
470
+ /** The base URL used to access database objects. */
453
471
  static storageURL;
472
+ /** The event target used for Explorer events. */
454
473
  static eventTarget;
474
+ /** The data PIN associated with the current session. */
475
+ static dataPIN;
476
+ /** The virtual entropy associated with the authenticated database. */
477
+ static virtualEntropy;
478
+ /** The secret used to access the authenticated database. */
455
479
  static databaseSecret;
480
+ /** The credential information associated with the current authentication. */
456
481
  static sessionCredential = {};
457
482
  /**
458
483
  * Caches cipher keys by object identifier.
@@ -462,46 +487,50 @@ var Explorer = class {
462
487
  */
463
488
  static cipherKeyCache = /* @__PURE__ */ new Map();
464
489
  /**
465
- * Authenticates a database using a data PIN and device-bound entropy.
490
+ * Authenticates a database using a data PIN and an existing device binding.
491
+ *
492
+ * Establishes the authenticated database context and records the credential
493
+ * used for authentication.
466
494
  *
467
- * Derives the credential and database identifiers from cryptographic
468
- * secrets. When setup parameters are provided, creates and stores a
469
- * new credential. Otherwise, loads the existing credential.
495
+ * When setup parameters are provided, registers a credential using the
496
+ * supplied virtual entropy or generates new virtual entropy.
470
497
  *
471
- * Records the authenticated credential in the database's credential list.
498
+ * @param dataPIN The PIN associated with the database.
499
+ * @param storageURL The base URL used to access database objects.
500
+ * @param setupParams Optional parameters for registering a credential.
472
501
  *
473
- * @param dataPIN The PIN used to derive the credential and database secrets.
474
- * @param storageURL The base URL used to access persisted database objects.
475
- * @param setupParams Optional parameters for creating a new credential.
502
+ * @param credentialId An optional credential identifier used to restrict credential selection.
476
503
  * @returns The authentication result.
477
504
  */
478
- static async authenticate(dataPIN, storageURL, setupParams) {
505
+ static async authenticate(dataPIN, storageURL, setupParams, credentialId) {
479
506
  try {
507
+ this.dataPIN = dataPIN;
480
508
  this.storageURL = storageURL;
481
- const deviceEntropy = await (0, _sovereignbase_hardware_bound.deriveDeviceEntropy)();
482
- if (!deviceEntropy) return "authenticator-error";
509
+ const deviceBinding = await (0, _sovereignbase_hardware_bound.accessDeviceBinding)(credentialId);
510
+ if (!Array.isArray(deviceBinding)) return "authenticator-error";
511
+ const [credentialID, deviceEntropy] = deviceBinding;
483
512
  this.sessionCredential = {
484
513
  timestamp: Date.now(),
485
514
  userAgent: (0, _sovereignbase_dom_utils.readableUserAgent)()
486
515
  };
487
516
  const dataPINBytes = _sovereignbase_bytecodec.Bytes.utf8.decode(dataPIN);
488
517
  const credentialSecret = await _sovereignbase_bytecodec.Bytes.derive(deviceEntropy, dataPINBytes, 32);
489
- const credentialID = await _sovereignbase_cryptosuite.Cryptographic.identifier.derive(credentialSecret, _sovereignbase_bytecodec.Bytes.utf8.decode("@sovereignbase/explorer:CredentialID"), 32);
490
- this.sessionCredential.id = credentialID;
518
+ const credentialObjectID = await _sovereignbase_cryptosuite.Cryptographic.identifier.derive(credentialSecret, _sovereignbase_bytecodec.Bytes.utf8.decode("@sovereignbase/explorer:CredentialObjectID"), 32);
519
+ this.sessionCredential.objectID = credentialObjectID;
520
+ this.sessionCredential.credentialID = credentialID;
491
521
  const credentialCipherKey = await _sovereignbase_cryptosuite.Cryptographic.cipherMessage.deriveKey(credentialSecret, _sovereignbase_bytecodec.Bytes.utf8.decode("@sovereignbase/explorer:CredentialCipherKey"));
492
- let virtualEntropy;
493
522
  if ((0, _sovereignbase_utils.isRecord)(setupParams)) {
494
- virtualEntropy = _sovereignbase_bytecodec.Bytes.generate(64);
495
- await this.storeObjectByID(credentialID, virtualEntropy, credentialCipherKey);
523
+ this.virtualEntropy = setupParams.virtualEntropy instanceof Uint8Array ? setupParams.virtualEntropy : _sovereignbase_bytecodec.Bytes.generate(64);
524
+ await this.storeObjectByID(credentialObjectID, this.virtualEntropy, credentialCipherKey);
496
525
  this.sessionCredential.name = setupParams.credentialName;
497
526
  this.sessionCredential.entropy = deviceEntropy;
498
527
  this.sessionCredential.storage = setupParams.bindingStorage;
499
528
  } else {
500
- const result = await this.loadObjectByID(credentialID, credentialCipherKey);
529
+ const result = await this.loadObjectByID(credentialObjectID, credentialCipherKey);
501
530
  if (!(result instanceof Uint8Array) || result.byteLength !== 64) return "invalid-data-pin";
502
- virtualEntropy = result;
531
+ this.virtualEntropy = result;
503
532
  }
504
- this.databaseSecret = await _sovereignbase_bytecodec.Bytes.derive(virtualEntropy, dataPINBytes, 64);
533
+ this.databaseSecret = await _sovereignbase_bytecodec.Bytes.derive(this.virtualEntropy, dataPINBytes, 64);
505
534
  this.databaseID = await _sovereignbase_cryptosuite.Cryptographic.identifier.derive(this.databaseSecret, _sovereignbase_bytecodec.Bytes.utf8.decode("@sovereignbase/explorer:DatabaseID"), 32);
506
535
  this.isAuthenticated = true;
507
536
  (await this.loadCredentialEntries()).record(this.sessionCredential);
@@ -512,10 +541,71 @@ var Explorer = class {
512
541
  throw unknownError(cause, "Explorer.authenticate()");
513
542
  }
514
543
  }
544
+ /** The number of consecutive failed database linking PIN attempts. */
545
+ static failCounter = 0;
515
546
  /**
516
- * Permanently revokes a credential and deletes its persisted data.
547
+ * Prepares an authenticated database for linking to another device.
517
548
  *
518
- * Removes the credential from the database's registered credentials.
549
+ * Verifies the current data PIN and prepares an encrypted transfer
550
+ * containing the information required to access the same database.
551
+ *
552
+ * Repeated PIN failures cause the current page to reload.
553
+ *
554
+ * @param dataPIN The PIN associated with the authenticated database.
555
+ * @param encapsulateKey The key used to establish encryption for the transfer.
556
+ * @returns The key offer and encrypted transfer message, or `false`
557
+ * if the supplied PIN is incorrect.
558
+ */
559
+ static async prepareDatabaseLink(dataPIN, encapsulateKey) {
560
+ try {
561
+ if (!this.isAuthenticated) throw new ExplorerError("NOT_AUTHENTICATED");
562
+ if (dataPIN !== this.dataPIN) {
563
+ if (this.failCounter >= 2) window.location.reload();
564
+ this.failCounter++;
565
+ return false;
566
+ }
567
+ this.failCounter = 0;
568
+ const { keyOffer, cipherKey } = await _sovereignbase_cryptosuite.Cryptographic.keyAgreement.encapsulate(encapsulateKey);
569
+ return [keyOffer, await _sovereignbase_cryptosuite.Cryptographic.cipherMessage.encrypt(cipherKey, _sovereignbase_bytecodec.Bytes.concat([this.virtualEntropy, _sovereignbase_bytecodec.Bytes.utf8.decode(dataPIN)]))];
570
+ } catch (cause) {
571
+ throw unknownError(cause, "Explorer.prepareDatabaseLink()");
572
+ }
573
+ }
574
+ /**
575
+ * Links the current device to an existing database.
576
+ *
577
+ * Accesses the transferred database information, creates a device binding,
578
+ * and registers a credential for the existing database.
579
+ *
580
+ * @param keyOffer The key offer associated with the database link.
581
+ * @param cipherMessage The encrypted database linking message.
582
+ * @param decapsulateKey The key used to establish decryption for the transfer.
583
+ * @param credentialName The display name assigned to the new credential.
584
+ * @param storageURL The base URL used to access database objects.
585
+ * @returns `true` if the database was linked and authenticated;
586
+ * otherwise, `false`.
587
+ */
588
+ static async linkToDatabase(keyOffer, cipherMessage, decapsulateKey, credentialName, storageURL) {
589
+ try {
590
+ const { cipherKey } = await _sovereignbase_cryptosuite.Cryptographic.keyAgreement.decapsulate(keyOffer, decapsulateKey);
591
+ const raw = await _sovereignbase_cryptosuite.Cryptographic.cipherMessage.decrypt(cipherKey, cipherMessage);
592
+ const setupResult = await (0, _sovereignbase_hardware_bound.createDeviceBinding)(credentialName);
593
+ if (!Array.isArray(setupResult)) return false;
594
+ const [credentialId, bindingStorage] = setupResult;
595
+ return await this.authenticate(_sovereignbase_bytecodec.Bytes.utf8.encode(raw.slice(64)), storageURL, {
596
+ credentialName,
597
+ virtualEntropy: raw.slice(0, 64),
598
+ bindingStorage
599
+ }, credentialId) === "authenticated" ? true : false;
600
+ } catch (cause) {
601
+ throw unknownError(cause, "Explorer.linkToDatabase()");
602
+ }
603
+ }
604
+ /**
605
+ * Permanently revokes a registered database credential.
606
+ *
607
+ * Removes the credential's persisted data and registration from
608
+ * the authenticated database.
519
609
  *
520
610
  * @param credentialID The identifier of the credential to revoke.
521
611
  * @throws {ExplorerError} If the database is not authenticated.
@@ -529,15 +619,14 @@ var Explorer = class {
529
619
  }
530
620
  }
531
621
  /**
532
- * Returns the registered credentials and optionally observes their changes.
622
+ * Returns the registered database credentials.
533
623
  *
534
- * The returned tuple contains a cleanup function, the current credential
535
- * entries, and the identifier of the current session's credential.
536
- *
537
- * The cleanup function removes the registered change listener, if any.
624
+ * Optionally registers a listener for changes to the credential entries.
625
+ * The returned cleanup function removes the registered listener.
538
626
  *
539
627
  * @param onChange An optional callback invoked when the entries change.
540
- * @returns The cleanup function, credential entries, and session credential ID.
628
+ * @returns The cleanup function, credential entries, and identifier
629
+ * of the current session's credential.
541
630
  * @throws {ExplorerError} If the database is not authenticated.
542
631
  */
543
632
  static async listCredentialEntries(onChange) {
@@ -557,11 +646,10 @@ var Explorer = class {
557
646
  }
558
647
  }
559
648
  /**
560
- * Returns the recently accessed objects and optionally observes their changes.
649
+ * Returns the recently accessed database objects.
561
650
  *
562
- * The returned tuple contains a cleanup function and the current recent
563
- * entries. The cleanup function removes the registered change listener,
564
- * if any.
651
+ * Optionally registers a listener for changes to the recent entries.
652
+ * The returned cleanup function removes the registered listener.
565
653
  *
566
654
  * @param onChange An optional callback invoked when the entries change.
567
655
  * @returns The cleanup function and recent entries.
@@ -580,9 +668,9 @@ var Explorer = class {
580
668
  }
581
669
  }
582
670
  /**
583
- * Loads an encrypted object using its identifier and cipher key.
671
+ * Loads an encrypted database object by its identifier.
584
672
  *
585
- * Caches the cipher key if the identifier has not been encountered before.
673
+ * Caches the supplied cipher key if no key has been cached for the object.
586
674
  *
587
675
  * @typeParam T The expected type of the loaded object.
588
676
  * @param id The identifier of the object to load.
@@ -599,9 +687,9 @@ var Explorer = class {
599
687
  }
600
688
  }
601
689
  /**
602
- * Encrypts and stores an object using its identifier and cipher key.
690
+ * Encrypts and stores a database object by its identifier.
603
691
  *
604
- * Caches the cipher key if the identifier has not been encountered before.
692
+ * Caches the supplied cipher key if no key has been cached for the object.
605
693
  *
606
694
  * @typeParam T The type of the object to store.
607
695
  * @param id The identifier of the object to store.
@@ -618,7 +706,9 @@ var Explorer = class {
618
706
  }
619
707
  }
620
708
  /**
621
- * Deletes a persisted object using its identifier.
709
+ * Deletes a database object by its identifier.
710
+ *
711
+ * Removes the persisted object and its corresponding recent entry.
622
712
  *
623
713
  * @param id The identifier of the object to delete.
624
714
  */
@@ -658,8 +748,9 @@ var Explorer = class {
658
748
  });
659
749
  }
660
750
  /**
661
- * Registers an event listener for the specified event type.
751
+ * Registers an event listener for the specified Explorer event.
662
752
  *
753
+ * @typeParam K The event name that determines the event detail type.
663
754
  * @param type The event type.
664
755
  * @param listener The event listener, or `null`.
665
756
  * @param options The event listener options.
@@ -675,6 +766,7 @@ var Explorer = class {
675
766
  * Removes an event listener previously registered with
676
767
  * {@link addEventListener}.
677
768
  *
769
+ * @typeParam K The event name that determines the listener type.
678
770
  * @param type The event type.
679
771
  * @param listener The event listener to remove, or `null`.
680
772
  * @param options The event listener options.
@@ -687,8 +779,9 @@ var Explorer = class {
687
779
  }
688
780
  }
689
781
  /**
690
- * Dispatches an event to the registered listeners.
782
+ * Dispatches an Explorer event to registered listeners.
691
783
  *
784
+ * @typeParam K The event name that determines the event detail type.
692
785
  * @param type The event type.
693
786
  * @param detail The value exposed through `CustomEvent.detail`.
694
787
  */
@@ -708,6 +801,7 @@ var Explorer = class {
708
801
  static isExplorerDelta(data) {
709
802
  return Array.isArray(data) && typeof data[0] === "string";
710
803
  }
804
+ /** The cached recent entries list. */
711
805
  static recentEntries;
712
806
  /**
713
807
  * Loads or returns the cached recent entries list.
@@ -731,6 +825,7 @@ var Explorer = class {
731
825
  throw unknownError(cause, "Explorer.loadRecentEntries()");
732
826
  }
733
827
  }
828
+ /** The cached credential entries list. */
734
829
  static credentialEntries;
735
830
  /**
736
831
  * Loads or returns the cached credential entries list.
@@ -748,7 +843,7 @@ var Explorer = class {
748
843
  const id = await _sovereignbase_cryptosuite.Cryptographic.identifier.derive(this.databaseSecret, _sovereignbase_bytecodec.Bytes.utf8.decode("@sovereignbase/explorer:CredentialEntriesID"), 32);
749
844
  const ck = await _sovereignbase_cryptosuite.Cryptographic.cipherMessage.deriveKey(this.databaseSecret, _sovereignbase_bytecodec.Bytes.utf8.decode("@sovereignbase/explorer:CredentialEntriesCipherKey"));
750
845
  const trustedSnapshot = await this.loadObjectByID(id, ck, (snapshot) => void this.credentialEntries.merge(snapshot));
751
- this.credentialEntries = new CredentialEntries(id, ck, this.sessionCredential.id, 0, trustedSnapshot);
846
+ this.credentialEntries = new CredentialEntries(id, ck, this.sessionCredential.credentialID, 0, trustedSnapshot);
752
847
  return this.credentialEntries;
753
848
  } catch (cause) {
754
849
  throw unknownError(cause, "Explorer.loadCredentialEntries()");
@@ -756,5 +851,6 @@ var Explorer = class {
756
851
  }
757
852
  };
758
853
  exports.Explorer = Explorer;
854
+ exports.ExplorerError = ExplorerError;
759
855
 
760
856
  //# sourceMappingURL=class.cjs.map