decane-connect-kit 2.24.1 → 2.26.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.cjs CHANGED
@@ -2276,6 +2276,17 @@ var ApiClient = class {
2276
2276
  headers: { Authorization: `Bearer ${jwt}` }
2277
2277
  });
2278
2278
  }
2279
+ /**
2280
+ * Trade a still-valid token for a fresh one, so an active user is never
2281
+ * signed out mid-use. The backend caps the whole chain by session age, so
2282
+ * this cannot renew forever; a 401 means "sign in again", not "retry".
2283
+ */
2284
+ async refreshAccessToken(jwt) {
2285
+ return this._request("/auth/refresh", {
2286
+ method: "POST",
2287
+ headers: { Authorization: `Bearer ${jwt}` }
2288
+ });
2289
+ }
2279
2290
  /** Redeem a decrypted unlock token for a session. */
2280
2291
  async exchangeUnlockToken(token) {
2281
2292
  return this._request("/auth/unlock-token/exchange", {
@@ -2416,6 +2427,54 @@ var import_browser = require("@simplewebauthn/browser");
2416
2427
 
2417
2428
  // src/social/attestation.ts
2418
2429
  var import_dcap_qvl = require("@phala/dcap-qvl");
2430
+
2431
+ // src/social/collateralCache.ts
2432
+ var CACHE_PREFIX = "decane:collateral:v1:";
2433
+ var COLLATERAL_TTL_MS = 12 * 60 * 60 * 1e3;
2434
+ function storage() {
2435
+ try {
2436
+ return typeof localStorage !== "undefined" ? localStorage : null;
2437
+ } catch {
2438
+ return null;
2439
+ }
2440
+ }
2441
+ function keyFor(teeUrl) {
2442
+ return `${CACHE_PREFIX}${teeUrl}`;
2443
+ }
2444
+ function readCollateral(teeUrl) {
2445
+ const store = storage();
2446
+ if (!store) return null;
2447
+ try {
2448
+ const raw = store.getItem(keyFor(teeUrl));
2449
+ if (!raw) return null;
2450
+ const entry = JSON.parse(raw);
2451
+ if (!entry?.at || Date.now() - entry.at > COLLATERAL_TTL_MS) {
2452
+ store.removeItem(keyFor(teeUrl));
2453
+ return null;
2454
+ }
2455
+ return entry.collateral ?? null;
2456
+ } catch {
2457
+ return null;
2458
+ }
2459
+ }
2460
+ function writeCollateral(teeUrl, collateral) {
2461
+ const store = storage();
2462
+ if (!store) return;
2463
+ try {
2464
+ store.setItem(keyFor(teeUrl), JSON.stringify({ at: Date.now(), collateral }));
2465
+ } catch {
2466
+ }
2467
+ }
2468
+ function dropCollateral(teeUrl) {
2469
+ const store = storage();
2470
+ if (!store) return;
2471
+ try {
2472
+ store.removeItem(keyFor(teeUrl));
2473
+ } catch {
2474
+ }
2475
+ }
2476
+
2477
+ // src/social/attestation.ts
2419
2478
  init_errors();
2420
2479
 
2421
2480
  // ../../infra/tee-measurement.json
@@ -2443,6 +2502,9 @@ function hexToBytes(hex) {
2443
2502
  function bytesToHex(bytes) {
2444
2503
  return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
2445
2504
  }
2505
+ function nowSeconds() {
2506
+ return Math.floor(Date.now() / 1e3);
2507
+ }
2446
2508
  async function verifyTeeAttestation(teeUrl, nonce) {
2447
2509
  const res = await fetch(`${teeUrl}/attestation`, {
2448
2510
  method: "POST",
@@ -2452,9 +2514,22 @@ async function verifyTeeAttestation(teeUrl, nonce) {
2452
2514
  if (!res.ok) throw new AttestationError("quote fetch failed");
2453
2515
  const { quote, measurement } = await res.json();
2454
2516
  let verified;
2517
+ const cached = readCollateral(teeUrl);
2455
2518
  try {
2456
- verified = await (0, import_dcap_qvl.getCollateralAndVerify)(hexToBytes(quote));
2457
- } catch {
2519
+ if (cached) {
2520
+ try {
2521
+ verified = await (0, import_dcap_qvl.verify)(hexToBytes(quote), cached, nowSeconds());
2522
+ } catch {
2523
+ dropCollateral(teeUrl);
2524
+ verified = await (0, import_dcap_qvl.getCollateralAndVerify)(hexToBytes(quote));
2525
+ }
2526
+ } else {
2527
+ const collateral = await (0, import_dcap_qvl.getCollateral)(import_dcap_qvl.PHALA_PCCS_URL, hexToBytes(quote));
2528
+ verified = await (0, import_dcap_qvl.verify)(hexToBytes(quote), collateral, nowSeconds());
2529
+ writeCollateral(teeUrl, collateral);
2530
+ }
2531
+ } catch (e) {
2532
+ if (e instanceof AttestationError) throw e;
2458
2533
  throw new AttestationError("quote signature invalid");
2459
2534
  }
2460
2535
  if (verified.status === "Revoked") {
@@ -2496,14 +2571,51 @@ async function teeFetch(url, init) {
2496
2571
  }
2497
2572
  var ATTESTATION_TTL_MS = 10 * 6e4;
2498
2573
  var attestationCache = /* @__PURE__ */ new Map();
2574
+ var ATTESTATION_PERSIST_PREFIX = "decane:attested:v1:";
2575
+ function persistedAt(teeUrl) {
2576
+ try {
2577
+ if (typeof sessionStorage === "undefined") return null;
2578
+ const raw = sessionStorage.getItem(ATTESTATION_PERSIST_PREFIX + teeUrl);
2579
+ const at = raw ? Number(raw) : NaN;
2580
+ return Number.isFinite(at) ? at : null;
2581
+ } catch {
2582
+ return null;
2583
+ }
2584
+ }
2585
+ function rememberAttested(teeUrl, at) {
2586
+ try {
2587
+ if (typeof sessionStorage !== "undefined") {
2588
+ sessionStorage.setItem(ATTESTATION_PERSIST_PREFIX + teeUrl, String(at));
2589
+ }
2590
+ } catch {
2591
+ }
2592
+ }
2593
+ function forgetAttested(teeUrl) {
2594
+ try {
2595
+ if (typeof sessionStorage !== "undefined") {
2596
+ sessionStorage.removeItem(ATTESTATION_PERSIST_PREFIX + teeUrl);
2597
+ }
2598
+ } catch {
2599
+ }
2600
+ }
2499
2601
  function attestOnce(teeUrl, verify) {
2500
2602
  const hit = attestationCache.get(teeUrl);
2501
2603
  if (hit && Date.now() - hit.at < ATTESTATION_TTL_MS) return hit.promise;
2502
- const promise = verify().catch((e) => {
2604
+ const at = persistedAt(teeUrl);
2605
+ if (at && Date.now() - at < ATTESTATION_TTL_MS) {
2606
+ const resolved = Promise.resolve();
2607
+ attestationCache.set(teeUrl, { at, promise: resolved });
2608
+ return resolved;
2609
+ }
2610
+ const startedAt = Date.now();
2611
+ const promise = verify().then(() => {
2612
+ rememberAttested(teeUrl, startedAt);
2613
+ }).catch((e) => {
2503
2614
  attestationCache.delete(teeUrl);
2615
+ forgetAttested(teeUrl);
2504
2616
  throw e;
2505
2617
  });
2506
- attestationCache.set(teeUrl, { at: Date.now(), promise });
2618
+ attestationCache.set(teeUrl, { at: startedAt, promise });
2507
2619
  return promise;
2508
2620
  }
2509
2621
  function prewarmAttestation(teeUrl) {
@@ -3775,29 +3887,44 @@ function clearLastUser(key) {
3775
3887
  function sessionPersistKey(apiKey) {
3776
3888
  return `decane:sess:${apiKey.slice(0, 20)}`;
3777
3889
  }
3890
+ var sessionStore = () => typeof sessionStorage !== "undefined" ? sessionStorage : null;
3891
+ function useCrossTabSessionStore(enabled) {
3892
+ sessionStore = enabled ? () => typeof localStorage !== "undefined" ? localStorage : null : () => typeof sessionStorage !== "undefined" ? sessionStorage : null;
3893
+ }
3778
3894
  function loadSession(key) {
3779
3895
  try {
3780
- const raw = typeof sessionStorage !== "undefined" ? sessionStorage.getItem(key) : null;
3781
- return raw ? JSON.parse(raw) : null;
3896
+ const raw = sessionStore()?.getItem(key) ?? (typeof sessionStorage !== "undefined" ? sessionStorage.getItem(key) : null) ?? (typeof localStorage !== "undefined" ? localStorage.getItem(key) : null);
3897
+ if (!raw) return null;
3898
+ const parsed = JSON.parse(raw);
3899
+ if (parsed?.expiresAt && parsed.expiresAt <= Date.now()) {
3900
+ clearSessionPersist(key);
3901
+ return null;
3902
+ }
3903
+ return parsed;
3782
3904
  } catch {
3783
3905
  return null;
3784
3906
  }
3785
3907
  }
3786
3908
  function saveSession(key, s) {
3787
3909
  try {
3788
- sessionStorage.setItem(key, JSON.stringify(s));
3910
+ sessionStore()?.setItem(key, JSON.stringify(s));
3789
3911
  } catch {
3790
3912
  }
3791
3913
  }
3792
3914
  function clearSessionPersist(key) {
3793
3915
  try {
3794
- sessionStorage.removeItem(key);
3916
+ if (typeof sessionStorage !== "undefined") sessionStorage.removeItem(key);
3917
+ } catch {
3918
+ }
3919
+ try {
3920
+ if (typeof localStorage !== "undefined") localStorage.removeItem(key);
3795
3921
  } catch {
3796
3922
  }
3797
3923
  }
3798
3924
  async function createDecaneConnect(config) {
3799
3925
  if (!config.appId) throw new Error("decane-connect-kit: appId is required");
3800
3926
  if (!config.apiKey) throw new Error("decane-connect-kit: apiKey is required");
3927
+ useCrossTabSessionStore(config.resumeSessionAcrossTabs === true);
3801
3928
  if (!config.chains?.length)
3802
3929
  throw new Error("decane-connect-kit: at least one chain is required");
3803
3930
  if (config.rotateOnNewDeviceRecovery && !config.onRecoveryRotated) {
@@ -3816,7 +3943,7 @@ async function createDecaneConnect(config) {
3816
3943
  const teeUrl = config.teeUrl ?? DEFAULT_TEE_URL;
3817
3944
  const events = new EventEmitter();
3818
3945
  const api = new ApiClient(baseUrl, config.apiKey, config.appId);
3819
- const storage = new Storage();
3946
+ const storage2 = new Storage();
3820
3947
  const session = new SessionManager(
3821
3948
  events,
3822
3949
  durationMs,
@@ -3914,6 +4041,7 @@ async function createDecaneConnect(config) {
3914
4041
  clearSessionPersist(SESSION_KEY);
3915
4042
  }
3916
4043
  let accessTokenExpiry = null;
4044
+ let tokenRefresh = null;
3917
4045
  function scheduleAccessTokenExpiry(jwt, expiresAt) {
3918
4046
  if (accessTokenExpiry) clearTimeout(accessTokenExpiry);
3919
4047
  accessTokenExpiry = setTimeout(() => {
@@ -3923,6 +4051,40 @@ async function createDecaneConnect(config) {
3923
4051
  dropLiveSession();
3924
4052
  events.emit("session-expired");
3925
4053
  }, Math.max(0, expiresAt - Date.now()));
4054
+ scheduleTokenRefresh(jwt, expiresAt);
4055
+ }
4056
+ function scheduleTokenRefresh(jwt, expiresAt) {
4057
+ if (tokenRefresh) clearTimeout(tokenRefresh);
4058
+ const lifetime = expiresAt - Date.now();
4059
+ if (lifetime <= 0) return;
4060
+ const at = Math.max(5e3, lifetime * 0.75);
4061
+ tokenRefresh = setTimeout(() => {
4062
+ tokenRefresh = null;
4063
+ void renewAccessToken(jwt);
4064
+ }, at);
4065
+ }
4066
+ async function renewAccessToken(expected) {
4067
+ if (auth?.jwt !== expected) return;
4068
+ if (typeof document !== "undefined" && document.visibilityState === "hidden") {
4069
+ const onVisible = () => {
4070
+ document.removeEventListener("visibilitychange", onVisible);
4071
+ if (auth?.jwt === expected) void renewAccessToken(expected);
4072
+ };
4073
+ document.addEventListener("visibilitychange", onVisible);
4074
+ return;
4075
+ }
4076
+ try {
4077
+ const { jwt: fresh } = await api.refreshAccessToken(expected);
4078
+ if (auth?.jwt !== expected) return;
4079
+ auth = { ...auth, jwt: fresh };
4080
+ const freshExpiry = decodeAccessToken(fresh)?.expiresAt;
4081
+ if (freshExpiry) {
4082
+ scheduleAccessTokenExpiry(fresh, freshExpiry);
4083
+ persistLiveSession();
4084
+ }
4085
+ events.emit("session-renewed");
4086
+ } catch {
4087
+ }
3926
4088
  }
3927
4089
  if (persistSession) {
3928
4090
  const saved = loadSession(SESSION_KEY) ?? (LEGACY_SESSION_KEY !== SESSION_KEY ? loadSession(LEGACY_SESSION_KEY) : null);
@@ -3959,7 +4121,7 @@ async function createDecaneConnect(config) {
3959
4121
  }
3960
4122
  async function attachUnlockToken(userId, jwt, tokenKey) {
3961
4123
  try {
3962
- const stored = await storage.getShare(userId);
4124
+ const stored = await storage2.getShare(userId);
3963
4125
  if (!stored) return;
3964
4126
  const { token } = await api.issueUnlockToken(jwt);
3965
4127
  const unlockTokenIv = generateRandomBytes(12);
@@ -3968,13 +4130,13 @@ async function createDecaneConnect(config) {
3968
4130
  new TextEncoder().encode(token),
3969
4131
  unlockTokenIv
3970
4132
  );
3971
- await storage.putShare({ ...stored, wrappedUnlockToken, unlockTokenIv });
4133
+ await storage2.putShare({ ...stored, wrappedUnlockToken, unlockTokenIv });
3972
4134
  } catch (e) {
3973
4135
  console.warn("decane-connect-kit: could not store an unlock token for this device.", e);
3974
4136
  }
3975
4137
  }
3976
4138
  async function persistRotatedDeviceShare(userId, deviceShare) {
3977
- const stored = await storage.getShare(userId);
4139
+ const stored = await storage2.getShare(userId);
3978
4140
  if (!stored) {
3979
4141
  throw new CallSequenceError(
3980
4142
  "Share set was rotated but this device has no stored share to update. Recover the wallet on this device before rotating."
@@ -3983,21 +4145,21 @@ async function createDecaneConnect(config) {
3983
4145
  const wrappingKey = await getWrappingKey(stored);
3984
4146
  const iv = generateRandomBytes(12);
3985
4147
  const wrappedDeviceShare = await aesGcmEncrypt(wrappingKey, deviceShare, iv);
3986
- await storage.putShare({ ...stored, wrappedDeviceShare, iv });
4148
+ await storage2.putShare({ ...stored, wrappedDeviceShare, iv });
3987
4149
  }
3988
4150
  function hasPasswordUnlock(stored) {
3989
4151
  return !!stored && stored.unlockMethod === "password" && !!stored.passwordSalt && !!stored.wrappedUnlockToken && !!stored.unlockTokenIv;
3990
4152
  }
3991
4153
  async function passwordDeviceCandidate() {
3992
4154
  if (persisted?.userId) {
3993
- const stored = await storage.getShare(persisted.userId);
4155
+ const stored = await storage2.getShare(persisted.userId);
3994
4156
  return hasPasswordUnlock(stored) ? stored : null;
3995
4157
  }
3996
4158
  if (lastUserId) {
3997
- const stored = await storage.getShare(lastUserId);
4159
+ const stored = await storage2.getShare(lastUserId);
3998
4160
  return hasPasswordUnlock(stored) ? stored : null;
3999
4161
  }
4000
- const candidates = (await storage.listShares()).filter(hasPasswordUnlock);
4162
+ const candidates = (await storage2.listShares()).filter(hasPasswordUnlock);
4001
4163
  return candidates.length === 1 ? candidates[0] : null;
4002
4164
  }
4003
4165
  async function getWrappingKey(stored) {
@@ -4025,7 +4187,7 @@ async function createDecaneConnect(config) {
4025
4187
  let credentialId;
4026
4188
  let prfOutput;
4027
4189
  try {
4028
- const label = (await storage.getShare(userId))?.profile?.email;
4190
+ const label = (await storage2.getShare(userId))?.profile?.email;
4029
4191
  ({ credentialId, prfOutput } = await registerWebAuthnCredential({
4030
4192
  api,
4031
4193
  jwt,
@@ -4057,8 +4219,8 @@ async function createDecaneConnect(config) {
4057
4219
  const wrappingKey = await importAesKey(prfOutput);
4058
4220
  const iv = generateRandomBytes(12);
4059
4221
  const wrappedDeviceShare = await aesGcmEncrypt(wrappingKey, deviceShare, iv);
4060
- const existing = await storage.getShare(userId);
4061
- await storage.putShare({
4222
+ const existing = await storage2.getShare(userId);
4223
+ await storage2.putShare({
4062
4224
  ...existing,
4063
4225
  userId,
4064
4226
  wrappedDeviceShare,
@@ -4142,7 +4304,7 @@ async function createDecaneConnect(config) {
4142
4304
  const { wrappingKey, tokenKey, meta } = await passwordSetup();
4143
4305
  const iv = generateRandomBytes(12);
4144
4306
  const wrappedDeviceShare = await aesGcmEncrypt(wrappingKey, deviceShare, iv);
4145
- await storage.putShare({
4307
+ await storage2.putShare({
4146
4308
  userId,
4147
4309
  wrappedDeviceShare,
4148
4310
  iv,
@@ -4216,7 +4378,7 @@ async function createDecaneConnect(config) {
4216
4378
  shareSet.device,
4217
4379
  iv
4218
4380
  );
4219
- await storage.putShare({
4381
+ await storage2.putShare({
4220
4382
  userId,
4221
4383
  wrappedDeviceShare,
4222
4384
  iv,
@@ -4320,7 +4482,7 @@ async function createDecaneConnect(config) {
4320
4482
  async function returningUserUnlock(userId, jwt) {
4321
4483
  const rawAddresses = await api.getAddresses(jwt);
4322
4484
  const recordedAddresses = rawAddresses.evm && rawAddresses.solana ? { evm: rawAddresses.evm, solana: rawAddresses.solana, tron: rawAddresses.tron ?? evmToTronAddress2(rawAddresses.evm) } : null;
4323
- const stored = await storage.getShare(userId);
4485
+ const stored = await storage2.getShare(userId);
4324
4486
  let deviceShare;
4325
4487
  let joinedViaPasskeySync = false;
4326
4488
  if (!stored) {
@@ -4359,7 +4521,7 @@ async function createDecaneConnect(config) {
4359
4521
  rpId,
4360
4522
  teeUrl,
4361
4523
  api,
4362
- storage,
4524
+ storage: storage2,
4363
4525
  onProgress: config.onRecoveryProgress,
4364
4526
  promptForRecoveryFile: config.promptForRecoveryFile,
4365
4527
  onNewRecoveryShare: async (recoveryShare, shareSetVersion) => {
@@ -4373,7 +4535,7 @@ async function createDecaneConnect(config) {
4373
4535
  });
4374
4536
  deviceShare = recovered.deviceShare;
4375
4537
  joinedViaPasskeySync = recovered.flow === "passkey-sync";
4376
- if (!deferDeviceProtection && !await storage.getShare(userId) && isPasskeySupported()) {
4538
+ if (!deferDeviceProtection && !await storage2.getShare(userId) && isPasskeySupported()) {
4377
4539
  await registerPasskeyAndBackup(userId, jwt, deviceShare);
4378
4540
  }
4379
4541
  } else {
@@ -4394,7 +4556,7 @@ async function createDecaneConnect(config) {
4394
4556
  } catch (e) {
4395
4557
  if (e instanceof StaleDeviceShareError) {
4396
4558
  zeroize(deviceShare);
4397
- await storage.deleteShare(userId);
4559
+ await storage2.deleteShare(userId);
4398
4560
  if (stored) return returningUserUnlock(userId, jwt);
4399
4561
  } else {
4400
4562
  zeroize(deviceShare);
@@ -4418,7 +4580,7 @@ async function createDecaneConnect(config) {
4418
4580
  const result = await tee.rotateShares(jwt);
4419
4581
  try {
4420
4582
  await persistRotatedDeviceShare(userId, result.deviceShare);
4421
- const refreshed = await storage.getShare(userId);
4583
+ const refreshed = await storage2.getShare(userId);
4422
4584
  if (refreshed?.unlockMethod === "passkey" && refreshed.credentialId && refreshed.prfSalt) {
4423
4585
  await api.putRecoveryBackup(jwt, {
4424
4586
  wrappedDeviceShare: refreshed.wrappedDeviceShare,
@@ -4451,13 +4613,13 @@ async function createDecaneConnect(config) {
4451
4613
  }
4452
4614
  async function passkeyLoginCandidate() {
4453
4615
  if (!persisted?.userId || !isPasskeySupported()) return null;
4454
- return usablePasskeyShare(await storage.getShare(persisted.userId));
4616
+ return usablePasskeyShare(await storage2.getShare(persisted.userId));
4455
4617
  }
4456
4618
  async function passkeyDeviceCandidate() {
4457
4619
  if (!isPasskeySupported()) return null;
4458
4620
  if (persisted?.userId) return passkeyLoginCandidate();
4459
- if (lastUserId) return usablePasskeyShare(await storage.getShare(lastUserId));
4460
- const candidates = (await storage.listShares()).map(usablePasskeyShare).filter(Boolean);
4621
+ if (lastUserId) return usablePasskeyShare(await storage2.getShare(lastUserId));
4622
+ const candidates = (await storage2.listShares()).map(usablePasskeyShare).filter(Boolean);
4461
4623
  return candidates.length === 1 ? candidates[0] : null;
4462
4624
  }
4463
4625
  async function canOfferPasskey() {
@@ -4465,15 +4627,15 @@ async function createDecaneConnect(config) {
4465
4627
  if (await passkeyDeviceCandidate()) return true;
4466
4628
  const known = persisted?.userId ?? lastUserId;
4467
4629
  if (!known) return false;
4468
- return await storage.getShare(known) == null;
4630
+ return await storage2.getShare(known) == null;
4469
4631
  }
4470
4632
  async function rememberProfile(userId, profile) {
4471
4633
  const incoming = Object.fromEntries(Object.entries(profile).filter(([, v]) => v));
4472
4634
  if (!Object.keys(incoming).length) return;
4473
4635
  try {
4474
- const stored = await storage.getShare(userId);
4636
+ const stored = await storage2.getShare(userId);
4475
4637
  if (!stored) return;
4476
- await storage.putShare({ ...stored, profile: { ...stored.profile, ...incoming } });
4638
+ await storage2.putShare({ ...stored, profile: { ...stored.profile, ...incoming } });
4477
4639
  } catch {
4478
4640
  }
4479
4641
  }
@@ -4497,7 +4659,7 @@ async function createDecaneConnect(config) {
4497
4659
  savePersisted(PERSIST_KEY, persisted);
4498
4660
  events.emit("connected");
4499
4661
  persistLiveSession();
4500
- const stored = await storage.getShare(userId);
4662
+ const stored = await storage2.getShare(userId);
4501
4663
  return {
4502
4664
  addresses,
4503
4665
  isNewUser: false,
@@ -4670,7 +4832,7 @@ async function createDecaneConnect(config) {
4670
4832
  events.emit("connected");
4671
4833
  persistLiveSession();
4672
4834
  scheduleAccessTokenExpiry(token, claims.expiresAt);
4673
- const stored = await storage.getShare(claims.userId);
4835
+ const stored = await storage2.getShare(claims.userId);
4674
4836
  return {
4675
4837
  addresses,
4676
4838
  isNewUser: false,
@@ -4700,7 +4862,7 @@ async function createDecaneConnect(config) {
4700
4862
  const candidate = await passkeyDeviceCandidate();
4701
4863
  if (candidate) return passkeyLogin(candidate);
4702
4864
  const known = persisted?.userId ?? lastUserId;
4703
- if (isPasskeySupported() && known && await storage.getShare(known) == null) {
4865
+ if (isPasskeySupported() && known && await storage2.getShare(known) == null) {
4704
4866
  return passkeyLoginWithoutShare(known);
4705
4867
  }
4706
4868
  throw new NewDeviceError();
@@ -4719,7 +4881,7 @@ async function createDecaneConnect(config) {
4719
4881
  async setUnlockPassword(password) {
4720
4882
  if (!auth) throw new ReconnectRequiredError();
4721
4883
  validateUnlockPassword(password);
4722
- const stored = await storage.getShare(auth.userId);
4884
+ const stored = await storage2.getShare(auth.userId);
4723
4885
  if (!stored) throw new NewDeviceError();
4724
4886
  const deviceShare = await aesGcmDecrypt(
4725
4887
  await getWrappingKey(stored),
@@ -4738,7 +4900,7 @@ async function createDecaneConnect(config) {
4738
4900
  );
4739
4901
  const iv = generateRandomBytes(12);
4740
4902
  const wrappedDeviceShare = await aesGcmEncrypt(shareKey, deviceShare, iv);
4741
- await storage.putShare({
4903
+ await storage2.putShare({
4742
4904
  ...stored,
4743
4905
  unlockMethod: "password",
4744
4906
  wrappedDeviceShare,
@@ -4818,9 +4980,9 @@ async function createDecaneConnect(config) {
4818
4980
  async removeUnlockPassword() {
4819
4981
  if (!auth) throw new ReconnectRequiredError();
4820
4982
  await api.revokeUnlockTokens(auth.jwt);
4821
- const stored = await storage.getShare(auth.userId);
4983
+ const stored = await storage2.getShare(auth.userId);
4822
4984
  if (!stored || stored.unlockMethod !== "password") return;
4823
- await storage.putShare({
4985
+ await storage2.putShare({
4824
4986
  ...stored,
4825
4987
  wrappedUnlockToken: void 0,
4826
4988
  unlockTokenIv: void 0
@@ -4828,13 +4990,13 @@ async function createDecaneConnect(config) {
4828
4990
  },
4829
4991
  async hasPasskey() {
4830
4992
  if (!auth) return false;
4831
- const stored = await storage.getShare(auth.userId);
4993
+ const stored = await storage2.getShare(auth.userId);
4832
4994
  return stored?.unlockMethod === "passkey";
4833
4995
  },
4834
4996
  async addPasskey() {
4835
4997
  if (!auth) throw new ReconnectRequiredError();
4836
4998
  if (!isPasskeySupported()) throw new WebAuthnNotSupportedError();
4837
- const stored = await storage.getShare(auth.userId);
4999
+ const stored = await storage2.getShare(auth.userId);
4838
5000
  if (stored?.unlockMethod === "passkey") return;
4839
5001
  if (!stored) {
4840
5002
  if (!serverAssistedRecovery) throw new NewDeviceError();
@@ -4867,11 +5029,11 @@ async function createDecaneConnect(config) {
4867
5029
  },
4868
5030
  async deviceProtected() {
4869
5031
  if (!auth) return false;
4870
- return await storage.getShare(auth.userId) !== null;
5032
+ return await storage2.getShare(auth.userId) !== null;
4871
5033
  },
4872
5034
  async protectDevice() {
4873
5035
  if (!auth) throw new ReconnectRequiredError();
4874
- if (await storage.getShare(auth.userId)) return true;
5036
+ if (await storage2.getShare(auth.userId)) return true;
4875
5037
  if (!serverAssistedRecovery) throw new NewDeviceError();
4876
5038
  const tee = new TeeClient(teeUrl);
4877
5039
  const provisioned = await tee.provisionDeviceShare(auth.jwt);
@@ -4881,7 +5043,7 @@ async function createDecaneConnect(config) {
4881
5043
  } finally {
4882
5044
  zeroize(provisioned);
4883
5045
  }
4884
- return await storage.getShare(auth.userId) !== null;
5046
+ return await storage2.getShare(auth.userId) !== null;
4885
5047
  },
4886
5048
  async unlock() {
4887
5049
  if (!auth) {