decane-connect-kit 2.26.0 → 2.27.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 CHANGED
@@ -14,6 +14,7 @@ __export(errors_exports, {
14
14
  AttestationError: () => AttestationError,
15
15
  CallSequenceError: () => CallSequenceError,
16
16
  DecaneConnectError: () => DecaneConnectError,
17
+ EnclaveHttpError: () => EnclaveHttpError,
17
18
  ExportNotAuthorizedError: () => ExportNotAuthorizedError,
18
19
  InvalidAccessTokenError: () => InvalidAccessTokenError,
19
20
  InvalidApiKeyError: () => InvalidApiKeyError,
@@ -24,6 +25,7 @@ __export(errors_exports, {
24
25
  OriginNotAllowedError: () => OriginNotAllowedError,
25
26
  PromptPasswordNotConfiguredError: () => PromptPasswordNotConfiguredError,
26
27
  PromptPinNotConfiguredError: () => PromptPinNotConfiguredError,
28
+ ProvisioningRateLimitedError: () => ProvisioningRateLimitedError,
27
29
  ProvisioningTimeoutError: () => ProvisioningTimeoutError,
28
30
  ReconnectRequiredError: () => ReconnectRequiredError,
29
31
  RecoveryFailedError: () => RecoveryFailedError,
@@ -34,11 +36,12 @@ __export(errors_exports, {
34
36
  UnlockRequiredError: () => UnlockRequiredError,
35
37
  UnlockTokenRejectedError: () => UnlockTokenRejectedError,
36
38
  UserCancelledError: () => UserCancelledError,
39
+ WalletEnrolmentError: () => WalletEnrolmentError,
37
40
  WebAuthnNotSupportedError: () => WebAuthnNotSupportedError,
38
41
  WrongPasswordError: () => WrongPasswordError,
39
42
  WrongUnlockPasswordError: () => WrongUnlockPasswordError
40
43
  });
41
- var DecaneConnectError, InvalidApiKeyError, OriginNotAllowedError, SessionExpiredError, UnlockRequiredError, ReconnectRequiredError, UserCancelledError, WebAuthnNotSupportedError, InvalidPinError, CallSequenceError, NetworkError, ShareCorruptedError, ProvisioningTimeoutError, NewDeviceError, StaleDeviceShareError, PromptPinNotConfiguredError, PromptPasswordNotConfiguredError, WrongUnlockPasswordError, InvalidAccessTokenError, UnlockTokenRejectedError, AttestationError, RecoveryFailedError, InvalidRecoveryFileError, WrongPasswordError, RecoveryWalletMismatchError, ExportNotAuthorizedError;
44
+ var DecaneConnectError, InvalidApiKeyError, OriginNotAllowedError, SessionExpiredError, UnlockRequiredError, ReconnectRequiredError, UserCancelledError, WebAuthnNotSupportedError, InvalidPinError, CallSequenceError, NetworkError, ShareCorruptedError, ProvisioningTimeoutError, NewDeviceError, StaleDeviceShareError, PromptPinNotConfiguredError, PromptPasswordNotConfiguredError, WrongUnlockPasswordError, InvalidAccessTokenError, UnlockTokenRejectedError, AttestationError, RecoveryFailedError, InvalidRecoveryFileError, WrongPasswordError, RecoveryWalletMismatchError, ExportNotAuthorizedError, WalletEnrolmentError, ProvisioningRateLimitedError, EnclaveHttpError;
42
45
  var init_errors = __esm({
43
46
  "src/social/errors.ts"() {
44
47
  "use strict";
@@ -187,6 +190,31 @@ var init_errors = __esm({
187
190
  super("EXPORT_NOT_AUTHORIZED", "Export requires a fresh security check", true);
188
191
  }
189
192
  };
193
+ WalletEnrolmentError = class extends DecaneConnectError {
194
+ constructor(cause) {
195
+ super(
196
+ "WALLET_ENROLMENT_FAILED",
197
+ "Your wallet could not be set up: the signing enclave did not accept it. Nothing was created \u2014 sign in again to try again.",
198
+ true
199
+ );
200
+ if (cause !== void 0) this.cause = cause;
201
+ }
202
+ };
203
+ ProvisioningRateLimitedError = class extends DecaneConnectError {
204
+ constructor() {
205
+ super(
206
+ "PROVISIONING_RATE_LIMITED",
207
+ "This wallet has been opened on too many devices or tabs in the last hour. Wait a little and sign in again.",
208
+ true
209
+ );
210
+ }
211
+ };
212
+ EnclaveHttpError = class extends DecaneConnectError {
213
+ constructor(status, message) {
214
+ super("ENCLAVE_HTTP", message, status >= 500);
215
+ this.status = status;
216
+ }
217
+ };
190
218
  }
191
219
  });
192
220
 
@@ -2114,7 +2142,8 @@ var ApiClient = class {
2114
2142
  wrappedShareMeta: btoa(JSON.stringify(share.wrappedShareMeta)),
2115
2143
  evmAddress: share.evmAddress,
2116
2144
  solanaAddress: share.solanaAddress,
2117
- tronAddress: share.tronAddress
2145
+ tronAddress: share.tronAddress,
2146
+ ...share.pendingEnrolment === void 0 ? {} : { pendingEnrolment: share.pendingEnrolment }
2118
2147
  })
2119
2148
  });
2120
2149
  }
@@ -2698,7 +2727,8 @@ var TeeClient = class {
2698
2727
  });
2699
2728
  if (!res.ok) {
2700
2729
  const detail = await res.text().catch(() => "");
2701
- throw new Error(
2730
+ throw new EnclaveHttpError(
2731
+ res.status,
2702
2732
  `auth share enrolment failed (HTTP ${res.status})${detail ? `: ${detail.slice(0, 200)}` : ""}`
2703
2733
  );
2704
2734
  }
@@ -2719,9 +2749,11 @@ var TeeClient = class {
2719
2749
  headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" }
2720
2750
  });
2721
2751
  if (res.status === 409) return null;
2752
+ if (res.status === 429) throw new ProvisioningRateLimitedError();
2722
2753
  if (!res.ok) {
2723
2754
  const detail = await res.text().catch(() => "");
2724
- throw new Error(
2755
+ throw new EnclaveHttpError(
2756
+ res.status,
2725
2757
  `device share provisioning failed (HTTP ${res.status})${detail ? `: ${detail.slice(0, 200)}` : ""}`
2726
2758
  );
2727
2759
  }
@@ -2936,6 +2968,35 @@ var SessionManager = class {
2936
2968
  }
2937
2969
  };
2938
2970
 
2971
+ // src/social/identityTier.ts
2972
+ function resolveProtectionTier(config) {
2973
+ if (config.protection) return config.protection;
2974
+ return config.deferDeviceProtection === true ? "identity" : "device";
2975
+ }
2976
+ function resumeAcrossTabsDefault(config, identityTier) {
2977
+ return config.resumeSessionAcrossTabs ?? identityTier;
2978
+ }
2979
+ var ENROL_BACKOFF_MS = [0, 1e3, 3e3];
2980
+ function enrolmentRetryable(status) {
2981
+ return status !== 429 && status !== 403;
2982
+ }
2983
+ function shouldTryProvisionFirst(identityTier, hasStoredShare) {
2984
+ return identityTier || !hasStoredShare;
2985
+ }
2986
+ function routeAfterProvision(input) {
2987
+ switch (input.outcome) {
2988
+ case "share":
2989
+ return "session";
2990
+ case "rate-limited":
2991
+ return "fail";
2992
+ case "not-enrolled":
2993
+ if (!input.identityTier) return "recover";
2994
+ return input.hasStoredShare ? "migrate" : "new-device";
2995
+ case "error":
2996
+ return input.identityTier ? "fail" : "recover";
2997
+ }
2998
+ }
2999
+
2939
3000
  // src/social/crypto/shares.ts
2940
3001
  import { secp256k1 } from "@noble/curves/secp256k1";
2941
3002
  import { split, combine } from "shamir-secret-sharing";
@@ -3846,7 +3907,8 @@ function clearSessionPersist(key) {
3846
3907
  async function createDecaneConnect(config) {
3847
3908
  if (!config.appId) throw new Error("decane-connect-kit: appId is required");
3848
3909
  if (!config.apiKey) throw new Error("decane-connect-kit: apiKey is required");
3849
- useCrossTabSessionStore(config.resumeSessionAcrossTabs === true);
3910
+ const identityTier = resolveProtectionTier(config) === "identity";
3911
+ useCrossTabSessionStore(resumeAcrossTabsDefault(config, identityTier));
3850
3912
  if (!config.chains?.length)
3851
3913
  throw new Error("decane-connect-kit: at least one chain is required");
3852
3914
  if (config.rotateOnNewDeviceRecovery && !config.onRecoveryRotated) {
@@ -3884,7 +3946,6 @@ async function createDecaneConnect(config) {
3884
3946
  let lastUserId = loadLastUser(LAST_USER_KEY) ?? (LEGACY_LAST_USER_KEY !== LAST_USER_KEY ? loadLastUser(LEGACY_LAST_USER_KEY) : null);
3885
3947
  let ethProvider = null;
3886
3948
  const persistSession = config.persistSession !== false;
3887
- const deferDeviceProtection = config.deferDeviceProtection === true;
3888
3949
  const serverAssistedRecovery = true;
3889
3950
  const RECOVERY_OFFER_TIMEOUT_MS = 5 * 6e4;
3890
3951
  const selfHealAttempted = /* @__PURE__ */ new Set();
@@ -3905,22 +3966,27 @@ async function createDecaneConnect(config) {
3905
3966
  zeroize(share);
3906
3967
  }
3907
3968
  }
3908
- async function enrolInBackground(jwt, share) {
3969
+ async function enrolBlocking(jwt, share, budgetMs) {
3970
+ const startedAt = Date.now();
3909
3971
  try {
3910
- for (let attempt = 1; attempt <= 2; attempt++) {
3972
+ let lastError;
3973
+ for (const wait of ENROL_BACKOFF_MS) {
3974
+ if (wait) await new Promise((r) => setTimeout(r, wait));
3911
3975
  try {
3912
- await new TeeClient(teeUrl).enrolAuthShare(jwt, share);
3976
+ await withDeadline(
3977
+ new TeeClient(teeUrl).enrolAuthShare(jwt, share),
3978
+ budgetMs - (Date.now() - startedAt),
3979
+ "enrolling your wallet"
3980
+ );
3913
3981
  return;
3914
3982
  } catch (e) {
3915
- if (attempt === 2) {
3916
- events.emit("enrolment-failed");
3917
- console.warn(
3918
- "decane-connect-kit: could not enrol this wallet for server-assisted recovery. The wallet is fine and fully usable; it will be re-enrolled automatically on the next unlock. Until then a brand-new device would need a passkey backup or a recovery file.",
3919
- e
3920
- );
3921
- }
3983
+ if (e instanceof AttestationError || e instanceof ProvisioningTimeoutError) throw e;
3984
+ lastError = e;
3985
+ if (!enrolmentRetryable(e.status)) break;
3922
3986
  }
3923
3987
  }
3988
+ events.emit("enrolment-failed");
3989
+ throw new WalletEnrolmentError(lastError);
3924
3990
  } finally {
3925
3991
  zeroize(share);
3926
3992
  }
@@ -4016,6 +4082,7 @@ async function createDecaneConnect(config) {
4016
4082
  else scheduleAccessTokenExpiry(saved.jwt, saved.expiresAt);
4017
4083
  auth = { jwt: saved.jwt, userId: saved.userId, addresses: saved.addresses };
4018
4084
  persisted = { userId: saved.userId, addresses: saved.addresses };
4085
+ if (saved.handle) armTokenRefresh(saved.jwt);
4019
4086
  } catch {
4020
4087
  dropLiveSession();
4021
4088
  }
@@ -4025,6 +4092,13 @@ async function createDecaneConnect(config) {
4025
4092
  if (LEGACY_SESSION_KEY !== SESSION_KEY) clearSessionPersist(LEGACY_SESSION_KEY);
4026
4093
  }
4027
4094
  events.on("session-expired", () => dropLiveSession());
4095
+ function armTokenRefresh(jwt) {
4096
+ const expiresAt = decodeAccessToken(jwt)?.expiresAt;
4097
+ if (expiresAt) scheduleTokenRefresh(jwt, expiresAt);
4098
+ }
4099
+ events.on("connected", () => {
4100
+ if (auth) armTokenRefresh(auth.jwt);
4101
+ });
4028
4102
  async function passwordSetup() {
4029
4103
  if (!config.promptUnlockPassword) throw new PromptPasswordNotConfiguredError();
4030
4104
  const password = await config.promptUnlockPassword({ kind: "set" });
@@ -4249,7 +4323,7 @@ async function createDecaneConnect(config) {
4249
4323
  let wrappingKey = null;
4250
4324
  let meta = {};
4251
4325
  let unlockTokenKey = null;
4252
- if (deferDeviceProtection) {
4326
+ if (identityTier) {
4253
4327
  } else if (isPasskeySupported()) {
4254
4328
  const prfSalt = generateRandomBytes(32);
4255
4329
  try {
@@ -4321,14 +4395,29 @@ async function createDecaneConnect(config) {
4321
4395
  iv: serverIv,
4322
4396
  wrappedShareMeta: {
4323
4397
  // The server records this on the wallet_created event and nothing else.
4324
- unlockMethod: deferDeviceProtection ? "deferred" : unlockMethod
4398
+ unlockMethod: identityTier ? "identity" : unlockMethod
4325
4399
  // credential IDs, prfSalt, pinSalt stay on-device — never sent to server
4326
4400
  },
4327
4401
  evmAddress,
4328
4402
  solanaAddress,
4329
- tronAddress
4403
+ tronAddress,
4404
+ // Provisional until the enclave has sealed the auth share, just below. A
4405
+ // backend that knows the flag keeps this row invisible to hasShare until
4406
+ // then, so a creation that fails past this point leaves no wallet behind
4407
+ // and the next sign-in simply creates again — with a new key, which is
4408
+ // why the backend also replaces the recorded addresses outright.
4409
+ pendingEnrolment: true
4330
4410
  }), remainingBudget(), "storing your wallet");
4331
4411
  zeroize(shareSet.server);
4412
+ try {
4413
+ await enrolBlocking(jwt, new Uint8Array(shareSet.recovery), remainingBudget());
4414
+ } catch (e) {
4415
+ zeroize(shareSet.device);
4416
+ zeroize(shareSet.recovery);
4417
+ if (wrappingKey) await storage2.deleteShare(userId).catch(() => {
4418
+ });
4419
+ throw e;
4420
+ }
4332
4421
  const addresses = { evm: evmAddress, solana: solanaAddress, tron: tronAddress };
4333
4422
  if (unlockMethod === "passkey" && meta.credentialId && meta.prfSalt && wrappedDeviceShare && iv) {
4334
4423
  try {
@@ -4357,10 +4446,7 @@ async function createDecaneConnect(config) {
4357
4446
  addresses.evm = evmAddress = confirmed.evm;
4358
4447
  addresses.solana = solanaAddress = confirmed.solana;
4359
4448
  addresses.tron = tronAddress = confirmed.tron ?? evmToTronAddress2(confirmed.evm);
4360
- if (serverAssistedRecovery) {
4361
- void enrolInBackground(jwt, new Uint8Array(shareSet.recovery));
4362
- }
4363
- if (config.offerRecoveryAtSignup === true && config.onRecoveryShareOffer) {
4449
+ if (!identityTier && config.offerRecoveryAtSignup === true && config.onRecoveryShareOffer) {
4364
4450
  void offerRecoveryShare(
4365
4451
  jwt,
4366
4452
  new Uint8Array(shareSet.recovery),
@@ -4407,31 +4493,44 @@ async function createDecaneConnect(config) {
4407
4493
  const stored = await storage2.getShare(userId);
4408
4494
  let deviceShare;
4409
4495
  let joinedViaPasskeySync = false;
4410
- if (!stored) {
4411
- if (serverAssistedRecovery) {
4496
+ let migrating = false;
4497
+ if (serverAssistedRecovery && shouldTryProvisionFirst(identityTier, !!stored)) {
4498
+ let provisioned = null;
4499
+ let failure;
4500
+ let outcome;
4501
+ try {
4502
+ provisioned = await new TeeClient(teeUrl).provisionDeviceShare(jwt);
4503
+ outcome = provisioned ? "share" : "not-enrolled";
4504
+ } catch (e) {
4505
+ failure = e;
4506
+ outcome = e instanceof ProvisioningRateLimitedError ? "rate-limited" : "error";
4507
+ }
4508
+ const route = routeAfterProvision({ identityTier, hasStoredShare: !!stored, outcome });
4509
+ if (route === "session" && provisioned) {
4510
+ if (!identityTier) await persistProvisionedShare(userId, jwt, provisioned);
4511
+ let addrs;
4412
4512
  try {
4413
- const tee = new TeeClient(teeUrl);
4414
- const provisioned = await tee.provisionDeviceShare(jwt);
4415
- if (provisioned) {
4416
- if (!deferDeviceProtection) await persistProvisionedShare(userId, jwt, provisioned);
4417
- let addrs;
4418
- try {
4419
- addrs = await session.start(provisioned, jwt, recordedAddresses);
4420
- } finally {
4421
- zeroize(provisioned);
4422
- }
4423
- return addrs;
4424
- }
4425
- console.warn(
4426
- "decane-connect-kit: this wallet is not enrolled for server-assisted provisioning (/signer/provision returned 409 not_enrolled), so a device share cannot be issued from the JWT alone. Falling back to passkey sync, then the recovery file."
4427
- );
4428
- } catch (e) {
4429
- console.warn(
4430
- "decane-connect-kit: server-assisted provisioning unavailable; falling back to passkey/recovery-file recovery.",
4431
- e
4432
- );
4513
+ addrs = await session.start(provisioned, jwt, recordedAddresses);
4514
+ } finally {
4515
+ zeroize(provisioned);
4433
4516
  }
4517
+ return addrs;
4518
+ }
4519
+ if (route === "fail") throw failure;
4520
+ if (route === "new-device") throw new NewDeviceError();
4521
+ if (route === "migrate") migrating = true;
4522
+ if (route === "recover" && outcome === "not-enrolled") {
4523
+ console.warn(
4524
+ "decane-connect-kit: this wallet is not enrolled for server-assisted provisioning (/signer/provision returned 409 not_enrolled), so a device share cannot be issued from the JWT alone. Falling back to passkey sync, then the recovery file."
4525
+ );
4526
+ } else if (route === "recover") {
4527
+ console.warn(
4528
+ "decane-connect-kit: server-assisted provisioning unavailable; falling back to passkey/recovery-file recovery.",
4529
+ failure
4530
+ );
4434
4531
  }
4532
+ }
4533
+ if (!stored) {
4435
4534
  if (!config.onRecoveryRotated) {
4436
4535
  throw new CallSequenceError(
4437
4536
  "Recovery rotates the share set and issues a new recovery file, but no onRecoveryRotated callback is configured to save it. Configure onRecoveryRotated before allowing recovery."
@@ -4457,7 +4556,7 @@ async function createDecaneConnect(config) {
4457
4556
  });
4458
4557
  deviceShare = recovered.deviceShare;
4459
4558
  joinedViaPasskeySync = recovered.flow === "passkey-sync";
4460
- if (!deferDeviceProtection && !await storage2.getShare(userId) && isPasskeySupported()) {
4559
+ if (!identityTier && !await storage2.getShare(userId) && isPasskeySupported()) {
4461
4560
  await registerPasskeyAndBackup(userId, jwt, deviceShare);
4462
4561
  }
4463
4562
  } else {
@@ -4471,6 +4570,14 @@ async function createDecaneConnect(config) {
4471
4570
  } catch {
4472
4571
  throw stored.unlockMethod === "pin" ? new InvalidPinError() : new ShareCorruptedError();
4473
4572
  }
4573
+ if (migrating) {
4574
+ try {
4575
+ await enrolBlocking(jwt, new Uint8Array(deviceShare), PROVISIONING_BUDGET_MS);
4576
+ } catch (e) {
4577
+ zeroize(deviceShare);
4578
+ throw e;
4579
+ }
4580
+ }
4474
4581
  }
4475
4582
  let addresses;
4476
4583
  try {
@@ -4485,7 +4592,11 @@ async function createDecaneConnect(config) {
4485
4592
  }
4486
4593
  throw e;
4487
4594
  }
4488
- void selfHealEnrolment(userId, jwt, new Uint8Array(deviceShare));
4595
+ if (migrating) {
4596
+ events.emit("migrated-to-identity");
4597
+ } else if (!identityTier) {
4598
+ void selfHealEnrolment(userId, jwt, new Uint8Array(deviceShare));
4599
+ }
4489
4600
  zeroize(deviceShare);
4490
4601
  if (recordedAddresses && recordedAddresses.evm.toLowerCase() !== addresses.evm.toLowerCase()) {
4491
4602
  console.warn(
@@ -4668,7 +4779,7 @@ async function createDecaneConnect(config) {
4668
4779
  if (auth && session.isActive()) {
4669
4780
  return { addresses: auth.addresses, isNewUser: false };
4670
4781
  }
4671
- const candidate = await passkeyLoginCandidate();
4782
+ const candidate = identityTier ? null : await passkeyLoginCandidate();
4672
4783
  if (candidate) {
4673
4784
  try {
4674
4785
  return await passkeyLogin(candidate);
@@ -4778,9 +4889,15 @@ async function createDecaneConnect(config) {
4778
4889
  return handleAuthResult(result);
4779
4890
  },
4780
4891
  async canSignInWithPasskey() {
4892
+ if (identityTier) return false;
4781
4893
  return canOfferPasskey();
4782
4894
  },
4783
4895
  async signInWithPasskey() {
4896
+ if (identityTier) {
4897
+ throw new CallSequenceError(
4898
+ "signInWithPasskey() is not available in the identity tier (protection: 'identity'); use connect()."
4899
+ );
4900
+ }
4784
4901
  const candidate = await passkeyDeviceCandidate();
4785
4902
  if (candidate) return passkeyLogin(candidate);
4786
4903
  const known = persisted?.userId ?? lastUserId;
@@ -4916,6 +5033,11 @@ async function createDecaneConnect(config) {
4916
5033
  return stored?.unlockMethod === "passkey";
4917
5034
  },
4918
5035
  async addPasskey() {
5036
+ if (identityTier) {
5037
+ throw new CallSequenceError(
5038
+ "addPasskey() is not available in the identity tier (protection: 'identity'): nothing is stored on the device for a passkey to protect."
5039
+ );
5040
+ }
4919
5041
  if (!auth) throw new ReconnectRequiredError();
4920
5042
  if (!isPasskeySupported()) throw new WebAuthnNotSupportedError();
4921
5043
  const stored = await storage2.getShare(auth.userId);
@@ -4954,6 +5076,7 @@ async function createDecaneConnect(config) {
4954
5076
  return await storage2.getShare(auth.userId) !== null;
4955
5077
  },
4956
5078
  async protectDevice() {
5079
+ if (identityTier) return false;
4957
5080
  if (!auth) throw new ReconnectRequiredError();
4958
5081
  if (await storage2.getShare(auth.userId)) return true;
4959
5082
  if (!serverAssistedRecovery) throw new NewDeviceError();
@@ -4969,7 +5092,7 @@ async function createDecaneConnect(config) {
4969
5092
  },
4970
5093
  async unlock() {
4971
5094
  if (!auth) {
4972
- const candidate = await passkeyLoginCandidate();
5095
+ const candidate = identityTier ? null : await passkeyLoginCandidate();
4973
5096
  if (candidate) {
4974
5097
  await passkeyLogin(candidate);
4975
5098
  return;
@@ -5138,6 +5261,8 @@ async function createDecaneConnect(config) {
5138
5261
  },
5139
5262
  async disconnect() {
5140
5263
  session.end();
5264
+ if (tokenRefresh) clearTimeout(tokenRefresh);
5265
+ tokenRefresh = null;
5141
5266
  if (auth?.jwt) {
5142
5267
  await api.revoke(auth.jwt).catch(() => {
5143
5268
  });
@@ -7595,7 +7720,9 @@ function DecaneKit({ config, children }) {
7595
7720
  chains,
7596
7721
  rpcUrls,
7597
7722
  requireAssertionPerSignature,
7723
+ protection,
7598
7724
  deferDeviceProtection,
7725
+ resumeSessionAcrossTabs,
7599
7726
  // Recovery callbacks. Forwarding these is what makes recovery
7600
7727
  // configurable at all from <DecaneKit>; before, they were silently
7601
7728
  // dropped and the headless client was constructed without them.
@@ -7616,7 +7743,9 @@ function DecaneKit({ config, children }) {
7616
7743
  promptPin,
7617
7744
  promptUnlockPassword,
7618
7745
  requireAssertionPerSignature,
7746
+ protection,
7619
7747
  deferDeviceProtection,
7748
+ resumeSessionAcrossTabs,
7620
7749
  offerRecoveryAtSignup,
7621
7750
  onRecoveryShareOffer,
7622
7751
  onRecoveryFileReady,
@@ -8823,6 +8952,7 @@ export {
8823
8952
  DecaneLogo,
8824
8953
  DecaneMark,
8825
8954
  DecaneWordmark,
8955
+ EnclaveHttpError,
8826
8956
  ExportNotAuthorizedError,
8827
8957
  InvalidAccessTokenError,
8828
8958
  InvalidApiKeyError,
@@ -8834,6 +8964,7 @@ export {
8834
8964
  OriginNotAllowedError,
8835
8965
  PromptPasswordNotConfiguredError,
8836
8966
  PromptPinNotConfiguredError,
8967
+ ProvisioningRateLimitedError,
8837
8968
  ProvisioningTimeoutError,
8838
8969
  ReconnectRequiredError,
8839
8970
  RecoveryFailedError,
@@ -8845,6 +8976,7 @@ export {
8845
8976
  UnlockRequiredError,
8846
8977
  UnlockTokenRejectedError,
8847
8978
  UserCancelledError,
8979
+ WalletEnrolmentError,
8848
8980
  WalletSelector,
8849
8981
  WeakPasswordError,
8850
8982
  WebAuthnNotSupportedError,