@bounded-sh/client 0.0.111 → 0.0.112-ux-audit.2
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/auth/index.d.ts +3 -1
- package/dist/auth/oidc-auth.d.ts +3 -1
- package/dist/auth/providers/email-auth-provider.d.ts +1 -1
- package/dist/auth/providers/guest-auth-provider.d.ts +1 -1
- package/dist/auth/providers/injected-evm-wallet-provider.d.ts +1 -1
- package/dist/auth/providers/injected-wallet-provider.d.ts +1 -1
- package/dist/auth/providers/offchain-auth-provider.d.ts +1 -1
- package/dist/auth/providers/privy-expo-provider.d.ts +1 -1
- package/dist/{email-auth-provider-DxS2WYxM.js → email-auth-provider-53sA5_i2.js} +4 -3
- package/dist/email-auth-provider-53sA5_i2.js.map +1 -0
- package/dist/{email-auth-provider-CVp6hSCo.mjs → email-auth-provider-BfCH7K6N.mjs} +4 -3
- package/dist/email-auth-provider-BfCH7K6N.mjs.map +1 -0
- package/dist/{email-auth-provider-BfBvF_4M.mjs → email-auth-provider-C7RXLVd9.mjs} +4 -3
- package/dist/email-auth-provider-C7RXLVd9.mjs.map +1 -0
- package/dist/{email-auth-provider-CiqhQ1c2.js → email-auth-provider-DTrCfOJd.js} +4 -3
- package/dist/email-auth-provider-DTrCfOJd.js.map +1 -0
- package/dist/{guest-auth-provider-DDBXeHoo.js → guest-auth-provider-00KkSNpE.js} +10 -5
- package/dist/guest-auth-provider-00KkSNpE.js.map +1 -0
- package/dist/{guest-auth-provider-Bm_yqQF6.mjs → guest-auth-provider-2J4fnTX5.mjs} +10 -5
- package/dist/guest-auth-provider-2J4fnTX5.mjs.map +1 -0
- package/dist/{guest-auth-provider-Cc8y4Qd1.mjs → guest-auth-provider-DjOFjtnk.mjs} +10 -5
- package/dist/guest-auth-provider-DjOFjtnk.mjs.map +1 -0
- package/dist/{guest-auth-provider-D9FGNuP9.js → guest-auth-provider-Tndt6tzJ.js} +10 -5
- package/dist/guest-auth-provider-Tndt6tzJ.js.map +1 -0
- package/dist/{index-B9__gwTi.mjs → index-D3kdhCpH.mjs} +313 -84
- package/dist/index-D3kdhCpH.mjs.map +1 -0
- package/dist/{index-BghQ8jX0.js → index-DJeEMevo.js} +312 -83
- package/dist/index-DJeEMevo.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{index.native-BHjpXkKQ.mjs → index.native-CAH_ks0s.mjs} +200 -56
- package/dist/index.native-CAH_ks0s.mjs.map +1 -0
- package/dist/{index.native-B_AFa0GD.js → index.native-ingNhWPw.js} +199 -55
- package/dist/index.native-ingNhWPw.js.map +1 -0
- package/dist/index.native.js +1 -1
- package/dist/index.native.mjs +1 -1
- package/dist/{injected-evm-wallet-provider-CIeCSOPL.mjs → injected-evm-wallet-provider-BtyG1HOX.mjs} +4 -3
- package/dist/injected-evm-wallet-provider-BtyG1HOX.mjs.map +1 -0
- package/dist/{injected-evm-wallet-provider-DeLUwvGs.js → injected-evm-wallet-provider-Cao1U0NZ.js} +4 -3
- package/dist/{injected-evm-wallet-provider-DeLUwvGs.js.map → injected-evm-wallet-provider-Cao1U0NZ.js.map} +1 -1
- package/dist/{injected-evm-wallet-provider-BUjqxQxp.mjs → injected-evm-wallet-provider-DXjwPjLW.mjs} +4 -3
- package/dist/{injected-evm-wallet-provider-BUjqxQxp.mjs.map → injected-evm-wallet-provider-DXjwPjLW.mjs.map} +1 -1
- package/dist/{injected-evm-wallet-provider-Ckb85p6a.js → injected-evm-wallet-provider-IlkuKffc.js} +4 -3
- package/dist/injected-evm-wallet-provider-IlkuKffc.js.map +1 -0
- package/dist/{injected-wallet-provider-BlzA0J_V.mjs → injected-wallet-provider-0SSONh1d.mjs} +4 -3
- package/dist/{injected-wallet-provider-BlzA0J_V.mjs.map → injected-wallet-provider-0SSONh1d.mjs.map} +1 -1
- package/dist/{injected-wallet-provider-Cfb4ayCP.js → injected-wallet-provider-BEYwsn6M.js} +4 -3
- package/dist/{injected-wallet-provider-Cfb4ayCP.js.map → injected-wallet-provider-BEYwsn6M.js.map} +1 -1
- package/dist/{injected-wallet-provider-BEuj4sM3.mjs → injected-wallet-provider-CfYNIIHd.mjs} +4 -3
- package/dist/{injected-wallet-provider-BEuj4sM3.mjs.map → injected-wallet-provider-CfYNIIHd.mjs.map} +1 -1
- package/dist/{injected-wallet-provider-CUKdAuFu.js → injected-wallet-provider-DSlHfgMU.js} +4 -3
- package/dist/{injected-wallet-provider-CUKdAuFu.js.map → injected-wallet-provider-DSlHfgMU.js.map} +1 -1
- package/package.json +2 -2
- package/dist/email-auth-provider-BfBvF_4M.mjs.map +0 -1
- package/dist/email-auth-provider-CVp6hSCo.mjs.map +0 -1
- package/dist/email-auth-provider-CiqhQ1c2.js.map +0 -1
- package/dist/email-auth-provider-DxS2WYxM.js.map +0 -1
- package/dist/guest-auth-provider-Bm_yqQF6.mjs.map +0 -1
- package/dist/guest-auth-provider-Cc8y4Qd1.mjs.map +0 -1
- package/dist/guest-auth-provider-D9FGNuP9.js.map +0 -1
- package/dist/guest-auth-provider-DDBXeHoo.js.map +0 -1
- package/dist/index-B9__gwTi.mjs.map +0 -1
- package/dist/index-BghQ8jX0.js.map +0 -1
- package/dist/index.native-BHjpXkKQ.mjs.map +0 -1
- package/dist/index.native-B_AFa0GD.js.map +0 -1
- package/dist/injected-evm-wallet-provider-CIeCSOPL.mjs.map +0 -1
- package/dist/injected-evm-wallet-provider-Ckb85p6a.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getConfig, getActiveSessionManager, WebSessionManager, ReactNativeSessionManager, revokeSession, reconnectWithNewAuth, init as init$2,
|
|
1
|
+
import { getConfig, getActiveSessionManager, WebSessionManager, ReactNativeSessionManager, revokeSession, reconnectWithNewAuth, deriveUserIdentityFromIdToken, init as init$2, onSessionCleared, subscribe, getFreshAuthToken, getSessionGeneration, getIdToken as getIdToken$1, genAuthNonce, genSolanaMessage, createSessionWithSignature } from '@bounded-sh/core';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
|
|
4
4
|
function walletContextFromClaims(claims, baseUrl, expectedAppId, tenantOrigin) {
|
|
@@ -35,6 +35,13 @@ function walletOperationGuard() {
|
|
|
35
35
|
throw new Error('wallet_session_changed');
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
|
+
function walletLoginGuard(signal) {
|
|
39
|
+
const generation = ++loginGeneration;
|
|
40
|
+
return () => {
|
|
41
|
+
if ((signal === null || signal === void 0 ? void 0 : signal.aborted) || generation !== loginGeneration)
|
|
42
|
+
throw new Error('wallet_login_cancelled');
|
|
43
|
+
};
|
|
44
|
+
}
|
|
38
45
|
// This realm owns one active SDK session and one retained signer frame.
|
|
39
46
|
let activeWalletState;
|
|
40
47
|
function setWalletSessionState(key, state) { activeWalletState = { key, state }; }
|
|
@@ -256,8 +263,9 @@ class OffchainAuthProvider {
|
|
|
256
263
|
async logout() {
|
|
257
264
|
await this.wrappedProvider.logout();
|
|
258
265
|
}
|
|
259
|
-
async restoreSession() {
|
|
260
|
-
const
|
|
266
|
+
async restoreSession(beforeCommit) {
|
|
267
|
+
const provider = this.wrappedProvider;
|
|
268
|
+
const user = await provider.restoreSession(beforeCommit);
|
|
261
269
|
if (user) {
|
|
262
270
|
return Object.assign(Object.assign({}, user), { provider: this });
|
|
263
271
|
}
|
|
@@ -5511,7 +5519,8 @@ async function loginWithRedirect(opts) {
|
|
|
5511
5519
|
return runNativeLogin(opts);
|
|
5512
5520
|
if (!hasDOM$2())
|
|
5513
5521
|
throw new Error('loginWithRedirect requires a browser or a configured React Native platform');
|
|
5514
|
-
const { url, pkce } = await buildAuthorize(opts);
|
|
5522
|
+
const { url, pkce } = await untilAborted(buildAuthorize(opts), opts.signal);
|
|
5523
|
+
throwIfCancelled(opts.signal);
|
|
5515
5524
|
// Stash the verifier + state so the redirect_uri page can finish the exchange. sessionStorage
|
|
5516
5525
|
// is per-tab and cleared on close — appropriate for a short-lived auth handshake. Keyed by
|
|
5517
5526
|
// this attempt's own state so a second concurrent login cannot overwrite it.
|
|
@@ -5540,9 +5549,29 @@ async function completeLoginFromRedirect() {
|
|
|
5540
5549
|
throw error;
|
|
5541
5550
|
return result.user;
|
|
5542
5551
|
}
|
|
5552
|
+
function throwIfCancelled(signal) {
|
|
5553
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted)
|
|
5554
|
+
throw new Error('cancelled');
|
|
5555
|
+
}
|
|
5556
|
+
async function untilAborted(work, signal) {
|
|
5557
|
+
if (!signal)
|
|
5558
|
+
return work;
|
|
5559
|
+
throwIfCancelled(signal);
|
|
5560
|
+
let onAbort;
|
|
5561
|
+
try {
|
|
5562
|
+
return await Promise.race([work, new Promise((_, reject) => {
|
|
5563
|
+
onAbort = () => reject(new Error('cancelled'));
|
|
5564
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
5565
|
+
})]);
|
|
5566
|
+
}
|
|
5567
|
+
finally {
|
|
5568
|
+
signal.removeEventListener('abort', onAbort);
|
|
5569
|
+
}
|
|
5570
|
+
}
|
|
5543
5571
|
/** Popup variant: open the hosted login in a popup; resolves with the User once the popup's
|
|
5544
5572
|
* redirect_uri page initializes the SDK, which hands the code back automatically. */
|
|
5545
5573
|
async function loginWithPopup(opts) {
|
|
5574
|
+
throwIfCancelled(opts.signal);
|
|
5546
5575
|
if (!hasDOM$2())
|
|
5547
5576
|
throw new Error('loginWithPopup is web-only — on React Native use loginWithRedirect()');
|
|
5548
5577
|
// Open synchronously, before PKCE/config awaits consume the click's user-
|
|
@@ -5560,7 +5589,7 @@ async function loginWithPopup(opts) {
|
|
|
5560
5589
|
throw new Error('Popup blocked — use loginWithRedirect() instead');
|
|
5561
5590
|
let authorization;
|
|
5562
5591
|
try {
|
|
5563
|
-
authorization = await buildAuthorize(opts, 'popup');
|
|
5592
|
+
authorization = await untilAborted(buildAuthorize(opts, 'popup'), opts.signal);
|
|
5564
5593
|
}
|
|
5565
5594
|
catch (error) {
|
|
5566
5595
|
try {
|
|
@@ -5577,6 +5606,7 @@ async function loginWithPopup(opts) {
|
|
|
5577
5606
|
// window with no listener or watchdog attached.
|
|
5578
5607
|
let expectedOrigin;
|
|
5579
5608
|
try {
|
|
5609
|
+
throwIfCancelled(opts.signal);
|
|
5580
5610
|
expectedOrigin = new URL(pkce.redirectUri).origin;
|
|
5581
5611
|
sessionStorage.setItem(pkceKey(pkce.state), JSON.stringify(pkce));
|
|
5582
5612
|
}
|
|
@@ -5608,20 +5638,42 @@ async function loginWithPopup(opts) {
|
|
|
5608
5638
|
setAuthLoading(true); // reflect "signing in…" while the popup is open
|
|
5609
5639
|
try {
|
|
5610
5640
|
return await new Promise((resolve, reject) => {
|
|
5641
|
+
var _a, _b;
|
|
5611
5642
|
let settled = false;
|
|
5643
|
+
let handedOff = false;
|
|
5644
|
+
let committing = false;
|
|
5612
5645
|
let timer;
|
|
5613
5646
|
let navigationTimer;
|
|
5614
5647
|
let completionTimer;
|
|
5615
5648
|
const cleanup = () => {
|
|
5616
|
-
settled = true;
|
|
5617
5649
|
clearInterval(timer);
|
|
5618
5650
|
clearTimeout(navigationTimer);
|
|
5619
5651
|
clearTimeout(completionTimer);
|
|
5620
5652
|
window.removeEventListener('message', onMsg);
|
|
5621
5653
|
removeAttempt(pkce.state);
|
|
5622
5654
|
};
|
|
5655
|
+
const finish = (error, user) => {
|
|
5656
|
+
var _a;
|
|
5657
|
+
if (settled)
|
|
5658
|
+
return;
|
|
5659
|
+
settled = true;
|
|
5660
|
+
cleanup();
|
|
5661
|
+
(_a = opts.signal) === null || _a === void 0 ? void 0 : _a.removeEventListener('abort', onAbort);
|
|
5662
|
+
try {
|
|
5663
|
+
popup.close();
|
|
5664
|
+
}
|
|
5665
|
+
catch ( /* ignore */_b) { /* ignore */ }
|
|
5666
|
+
if (error)
|
|
5667
|
+
reject(error);
|
|
5668
|
+
else
|
|
5669
|
+
resolve(user);
|
|
5670
|
+
};
|
|
5671
|
+
// Provider adoption commits synchronously after its final guard. An auth
|
|
5672
|
+
// listener dismissing the card there cannot cancel an already signed-in user.
|
|
5673
|
+
const onAbort = () => { if (!committing)
|
|
5674
|
+
finish(new Error('cancelled')); };
|
|
5623
5675
|
const onMsg = async (ev) => {
|
|
5624
|
-
if (settled || ev.origin !== expectedOrigin || ev.source !== popup)
|
|
5676
|
+
if (settled || handedOff || ev.origin !== expectedOrigin || ev.source !== popup)
|
|
5625
5677
|
return;
|
|
5626
5678
|
const d = ev.data;
|
|
5627
5679
|
if (!d || d.type !== 'bounded-oidc-code' ||
|
|
@@ -5635,35 +5687,30 @@ async function loginWithPopup(opts) {
|
|
|
5635
5687
|
return;
|
|
5636
5688
|
if (d.appId !== pkce.appId || d.issuer !== pkce.issuer)
|
|
5637
5689
|
return;
|
|
5690
|
+
handedOff = true;
|
|
5638
5691
|
cleanup();
|
|
5639
5692
|
try {
|
|
5693
|
+
throwIfCancelled(opts.signal);
|
|
5640
5694
|
await validateAttempt(pkce, new URL(d.callbackUrl));
|
|
5695
|
+
throwIfCancelled(opts.signal);
|
|
5641
5696
|
popup.postMessage({ type: 'bounded-oidc-accepted', state: pkce.state }, expectedOrigin);
|
|
5642
5697
|
if (d.error)
|
|
5643
5698
|
throw new Error(typeof d.errorDescription === 'string' ? d.errorDescription : `Login failed: ${d.error}`);
|
|
5644
|
-
const user = await exchangeCode(d.code, pkce);
|
|
5645
|
-
|
|
5646
|
-
popup.close();
|
|
5647
|
-
}
|
|
5648
|
-
catch ( /* ignore */_a) { /* ignore */ }
|
|
5649
|
-
resolve(user);
|
|
5699
|
+
const user = await exchangeCode(d.code, pkce, opts.signal, () => { committing = true; });
|
|
5700
|
+
finish(undefined, user);
|
|
5650
5701
|
}
|
|
5651
5702
|
catch (e) {
|
|
5652
|
-
|
|
5653
|
-
popup.close();
|
|
5654
|
-
}
|
|
5655
|
-
catch ( /* ignore */_b) { /* ignore */ }
|
|
5656
|
-
reject(e);
|
|
5703
|
+
finish(e);
|
|
5657
5704
|
}
|
|
5658
5705
|
};
|
|
5706
|
+
(_a = opts.signal) === null || _a === void 0 ? void 0 : _a.addEventListener('abort', onAbort, { once: true });
|
|
5707
|
+
if ((_b = opts.signal) === null || _b === void 0 ? void 0 : _b.aborted) {
|
|
5708
|
+
onAbort();
|
|
5709
|
+
return;
|
|
5710
|
+
}
|
|
5659
5711
|
window.addEventListener('message', onMsg);
|
|
5660
5712
|
completionTimer = setTimeout(() => {
|
|
5661
|
-
|
|
5662
|
-
try {
|
|
5663
|
-
popup.close();
|
|
5664
|
-
}
|
|
5665
|
-
catch ( /* ignore */_a) { /* ignore */ }
|
|
5666
|
-
reject(new Error('Login expired or its popup disconnected. Start sign-in again.'));
|
|
5713
|
+
finish(new Error('Login expired or its popup disconnected. Start sign-in again.'));
|
|
5667
5714
|
}, LOGIN_TIMEOUT_MS);
|
|
5668
5715
|
// Some browser/extension combinations can return a real popup handle but
|
|
5669
5716
|
// strand the window at about:blank instead of navigating to the hosted
|
|
@@ -5684,23 +5731,18 @@ async function loginWithPopup(opts) {
|
|
|
5684
5731
|
const NAVIGATION_RECHECK_MS = 2000;
|
|
5685
5732
|
const navigationStartedAt = Date.now();
|
|
5686
5733
|
const checkNavigation = () => {
|
|
5687
|
-
if (settled || popup.closed)
|
|
5734
|
+
if (settled || handedOff || popup.closed)
|
|
5688
5735
|
return;
|
|
5689
5736
|
try {
|
|
5690
5737
|
if (popup.location.href === 'about:blank') {
|
|
5691
5738
|
if (Date.now() - navigationStartedAt >= NAVIGATION_GRACE_MS) {
|
|
5692
|
-
|
|
5693
|
-
try {
|
|
5694
|
-
popup.close();
|
|
5695
|
-
}
|
|
5696
|
-
catch ( /* ignore */_a) { /* ignore */ }
|
|
5697
|
-
reject(new Error('Popup stalled at about:blank - use loginWithRedirect() instead'));
|
|
5739
|
+
finish(new Error('Popup stalled at about:blank - use loginWithRedirect() instead'));
|
|
5698
5740
|
return;
|
|
5699
5741
|
}
|
|
5700
5742
|
navigationTimer = setTimeout(checkNavigation, NAVIGATION_RECHECK_MS);
|
|
5701
5743
|
}
|
|
5702
5744
|
}
|
|
5703
|
-
catch ( /* cross-origin hosted auth loaded normally */
|
|
5745
|
+
catch ( /* cross-origin hosted auth loaded normally */_a) { /* cross-origin hosted auth loaded normally */ }
|
|
5704
5746
|
};
|
|
5705
5747
|
navigationTimer = setTimeout(checkNavigation, NAVIGATION_RECHECK_MS);
|
|
5706
5748
|
// The popup posts its code and then closes ITSELF, so a naive "popup.closed -> reject"
|
|
@@ -5710,10 +5752,8 @@ async function loginWithPopup(opts) {
|
|
|
5710
5752
|
timer = setInterval(() => {
|
|
5711
5753
|
if (popup.closed) {
|
|
5712
5754
|
clearInterval(timer);
|
|
5713
|
-
setTimeout(() => { if (!settled)
|
|
5714
|
-
|
|
5715
|
-
reject(new Error('Login window closed'));
|
|
5716
|
-
} }, 500);
|
|
5755
|
+
setTimeout(() => { if (!settled && !handedOff)
|
|
5756
|
+
finish(new Error('Login window closed')); }, 500);
|
|
5717
5757
|
}
|
|
5718
5758
|
}, 500);
|
|
5719
5759
|
});
|
|
@@ -5727,20 +5767,21 @@ async function loginWithPopup(opts) {
|
|
|
5727
5767
|
// Turnkey-native login path (authMode:"turnkey"), which mints the session server-side
|
|
5728
5768
|
// after Turnkey verifies the email OTP - there is no OIDC code to exchange. Wiring is
|
|
5729
5769
|
// identical to exchangeCode's tail so the realtime worker cannot tell them apart.
|
|
5730
|
-
async function establishInlineSession(data, beforeCommit, beforeStore) {
|
|
5770
|
+
async function establishInlineSession(data, beforeCommit, beforeStore, onCommitting) {
|
|
5731
5771
|
const base = await issuerBase();
|
|
5772
|
+
beforeCommit === null || beforeCommit === void 0 ? void 0 : beforeCommit();
|
|
5732
5773
|
const idToken = tokenField(data, 'id_token', 'idToken');
|
|
5733
5774
|
if (!idToken)
|
|
5734
5775
|
throw new Error('No id_token in the inline session response');
|
|
5735
5776
|
const accessToken = tokenField(data, 'access_token', 'accessToken') || idToken;
|
|
5736
5777
|
const refreshToken = boundedRefreshTokenField(data);
|
|
5737
5778
|
const user = userFromIdToken(idToken);
|
|
5738
|
-
const rollback = await sessionManager().storeSession(String(user.address || ''), accessToken, idToken, refreshToken, base, () => { });
|
|
5779
|
+
const rollback = await sessionManager().storeSession(String(user.address || ''), accessToken, idToken, refreshToken, base, () => { beforeCommit === null || beforeCommit === void 0 ? void 0 : beforeCommit(); });
|
|
5739
5780
|
// Adopt the OIDC provider on EVERY session surface - including core's signing
|
|
5740
5781
|
// pointer (getConfig().authProvider), which this path used to skip, leaving
|
|
5741
5782
|
// onchain writes routed through a previous (e.g. logged-out wallet) provider.
|
|
5742
5783
|
try {
|
|
5743
|
-
await adoptSessionProvider({ provider: oidcProviderSingleton, method: 'email', configKey: 'direct:oidc', user, beforeCommit });
|
|
5784
|
+
await adoptSessionProvider({ provider: oidcProviderSingleton, method: 'email', configKey: 'direct:oidc', user, beforeCommit: () => { beforeCommit === null || beforeCommit === void 0 ? void 0 : beforeCommit(); onCommitting === null || onCommitting === void 0 ? void 0 : onCommitting(); } });
|
|
5744
5785
|
}
|
|
5745
5786
|
catch (error) {
|
|
5746
5787
|
if (typeof rollback === 'function')
|
|
@@ -5764,9 +5805,10 @@ async function inlineAuthEndpoint() {
|
|
|
5764
5805
|
const cfg = await getConfig();
|
|
5765
5806
|
return { base: await issuerBase(), appId: cfg.appId };
|
|
5766
5807
|
}
|
|
5767
|
-
async function exchangeCode(code, pkce) {
|
|
5808
|
+
async function exchangeCode(code, pkce, signal, onCommitting) {
|
|
5768
5809
|
const generation = getInitializationGeneration();
|
|
5769
5810
|
const beforeCommit = () => {
|
|
5811
|
+
throwIfCancelled(signal);
|
|
5770
5812
|
if (generation !== getInitializationGeneration())
|
|
5771
5813
|
throw new Error('Login was superseded by SDK reinitialization. Start sign-in again.');
|
|
5772
5814
|
};
|
|
@@ -5782,7 +5824,7 @@ async function exchangeCode(code, pkce) {
|
|
|
5782
5824
|
let res;
|
|
5783
5825
|
try {
|
|
5784
5826
|
res = await fetch(`${base}/api/auth/oauth2/token`, {
|
|
5785
|
-
method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded' }, body: body.toString(),
|
|
5827
|
+
method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded' }, body: body.toString(), signal,
|
|
5786
5828
|
});
|
|
5787
5829
|
}
|
|
5788
5830
|
catch (err) {
|
|
@@ -5808,7 +5850,7 @@ async function exchangeCode(code, pkce) {
|
|
|
5808
5850
|
// Adopt on EVERY session surface (see establishInlineSession) - hosted
|
|
5809
5851
|
// popup/redirect completions all land here, so this closes their gap too.
|
|
5810
5852
|
try {
|
|
5811
|
-
await adoptSessionProvider({ provider: oidcProviderSingleton, method: 'email', configKey: 'direct:oidc', user, beforeCommit });
|
|
5853
|
+
await adoptSessionProvider({ provider: oidcProviderSingleton, method: 'email', configKey: 'direct:oidc', user, beforeCommit: () => { beforeCommit(); onCommitting === null || onCommitting === void 0 ? void 0 : onCommitting(); } });
|
|
5812
5854
|
}
|
|
5813
5855
|
catch (error) {
|
|
5814
5856
|
if (typeof rollback === 'function')
|
|
@@ -5877,6 +5919,31 @@ function idTokenIsGuest(idToken, expectedAddress) {
|
|
|
5877
5919
|
function storedSessionIsGuest() {
|
|
5878
5920
|
return idTokenIsGuest(getStoredIdToken());
|
|
5879
5921
|
}
|
|
5922
|
+
/** Internal: select a cross-tab restore from bearer claims, never global hints. */
|
|
5923
|
+
function storedSessionAuthMethod(config) {
|
|
5924
|
+
try {
|
|
5925
|
+
const token = getStoredIdToken();
|
|
5926
|
+
if (!token)
|
|
5927
|
+
return null;
|
|
5928
|
+
let payload = token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/');
|
|
5929
|
+
payload += '='.repeat((4 - payload.length % 4) % 4);
|
|
5930
|
+
const claims = JSON.parse(getPlatform().atob(payload));
|
|
5931
|
+
const method = claims.is_anonymous === true ? 'guest'
|
|
5932
|
+
: claims['custom:walletProvider'] === 'turnkey' || claims.email ? 'email'
|
|
5933
|
+
: claims['custom:evmWalletAddress'] ? 'evm-wallet'
|
|
5934
|
+
: claims['custom:walletAddress'] ? 'phantom' : 'email';
|
|
5935
|
+
if (config.authMethod != null && canonicalWalletAuthMethod(config.authMethod) !== method)
|
|
5936
|
+
return null;
|
|
5937
|
+
if (method === 'evm-wallet' && config.authMethod !== 'evm-wallet')
|
|
5938
|
+
return null;
|
|
5939
|
+
if (method === 'phantom' && (isWalletLoginDisabled(config) || isEmailRequired(config)))
|
|
5940
|
+
return null;
|
|
5941
|
+
return method;
|
|
5942
|
+
}
|
|
5943
|
+
catch (_a) {
|
|
5944
|
+
return null;
|
|
5945
|
+
}
|
|
5946
|
+
}
|
|
5880
5947
|
/**
|
|
5881
5948
|
* Pick the provider used for an ordinary `init({ appId })` restore.
|
|
5882
5949
|
*
|
|
@@ -6138,9 +6205,10 @@ function optionalProviderError(method) {
|
|
|
6138
6205
|
`loginWithRedirect(...) for Bounded Auth, signInAnonymously() for guests, ` +
|
|
6139
6206
|
`or install/import an explicit wallet-provider entry once your app opts into "${method}".`);
|
|
6140
6207
|
}
|
|
6141
|
-
async function getAuthProvider(config) {
|
|
6208
|
+
async function getAuthProvider(config, fromStorage = false) {
|
|
6142
6209
|
var _a;
|
|
6143
|
-
const
|
|
6210
|
+
const requestedAuthMethod = config ? (fromStorage ? storedSessionAuthMethod(config) : authMethodForInit(config)) : null;
|
|
6211
|
+
const nextProviderConfigKey = config ? authProviderConfigKey(Object.assign(Object.assign({}, config), { authMethod: requestedAuthMethod })) : null;
|
|
6144
6212
|
if (currentAuthProvider && (!config || currentAuthProviderConfigKey === nextProviderConfigKey)) {
|
|
6145
6213
|
return currentAuthProvider;
|
|
6146
6214
|
}
|
|
@@ -6155,7 +6223,8 @@ async function getAuthProvider(config) {
|
|
|
6155
6223
|
initConfig = config;
|
|
6156
6224
|
// Keep what the app actually wrote for error text; everything else runs on
|
|
6157
6225
|
// the canonical method so exactly one string reaches storage and the issuer.
|
|
6158
|
-
|
|
6226
|
+
if (!requestedAuthMethod)
|
|
6227
|
+
throw new Error('The stored session is incompatible with this app authentication configuration.');
|
|
6159
6228
|
const authMethod = canonicalWalletAuthMethod(requestedAuthMethod);
|
|
6160
6229
|
const rpcUrl = normalizeSolanaRpcUrl(config.rpcUrl);
|
|
6161
6230
|
const configuredNetwork = getConfiguredSolanaNetwork(config);
|
|
@@ -6180,7 +6249,7 @@ async function getAuthProvider(config) {
|
|
|
6180
6249
|
// manager as legacy email sessions. Human login should be started
|
|
6181
6250
|
// with loginWithRedirect(); this provider is kept as the restore and
|
|
6182
6251
|
// logout surface for those sessions.
|
|
6183
|
-
currentAuthProvider = new (await import('./email-auth-provider-
|
|
6252
|
+
currentAuthProvider = new (await import('./email-auth-provider-C7RXLVd9.mjs')).EmailAuthProvider();
|
|
6184
6253
|
break;
|
|
6185
6254
|
case "phantom": {
|
|
6186
6255
|
// First-class Solana WALLET LOGIN (the poof/TaroBase-style "connect
|
|
@@ -6222,7 +6291,7 @@ async function getAuthProvider(config) {
|
|
|
6222
6291
|
// (bounded-login-widget.ts), so registration never counts as
|
|
6223
6292
|
// evidence the user has a wallet.
|
|
6224
6293
|
await ensureSolanaMobileWalletRegistered(config, configuredNetwork);
|
|
6225
|
-
const { InjectedWalletProvider } = await import('./injected-wallet-provider-
|
|
6294
|
+
const { InjectedWalletProvider } = await import('./injected-wallet-provider-0SSONh1d.mjs');
|
|
6226
6295
|
currentAuthProvider = new InjectedWalletProvider(resolveInjectedWalletConfig(config), rpcUrl, configuredNetwork);
|
|
6227
6296
|
break;
|
|
6228
6297
|
}
|
|
@@ -6235,7 +6304,7 @@ async function getAuthProvider(config) {
|
|
|
6235
6304
|
// Selecting authMethod:'evm-wallet' IS the opt-in — pass evmWalletConfig
|
|
6236
6305
|
// to point at a specific wallet or set chainId/domain.
|
|
6237
6306
|
const evmWalletConfig = ((_a = config.evmWalletConfig) !== null && _a !== void 0 ? _a : {});
|
|
6238
|
-
const { InjectedEvmWalletProvider } = await import('./injected-evm-wallet-provider-
|
|
6307
|
+
const { InjectedEvmWalletProvider } = await import('./injected-evm-wallet-provider-BtyG1HOX.mjs');
|
|
6239
6308
|
currentAuthProvider = new InjectedEvmWalletProvider(evmWalletConfig);
|
|
6240
6309
|
break;
|
|
6241
6310
|
}
|
|
@@ -6260,7 +6329,7 @@ async function getAuthProvider(config) {
|
|
|
6260
6329
|
break;
|
|
6261
6330
|
case "guest":
|
|
6262
6331
|
// Anonymous auth: a device-local ed25519 keypair signs the challenge.
|
|
6263
|
-
currentAuthProvider = new (await import('./guest-auth-provider-
|
|
6332
|
+
currentAuthProvider = new (await import('./guest-auth-provider-2J4fnTX5.mjs')).GuestAuthProvider();
|
|
6264
6333
|
break;
|
|
6265
6334
|
}
|
|
6266
6335
|
if (!currentAuthProvider) {
|
|
@@ -6322,7 +6391,7 @@ async function signInAnonymously() {
|
|
|
6322
6391
|
// Lazy-load the guest provider so its ed25519/web3 dependencies stay out of
|
|
6323
6392
|
// the main bundle for data-only apps. Specifier is a static string literal
|
|
6324
6393
|
// so bundle-splitting can see it.
|
|
6325
|
-
const provider = new (await import('./guest-auth-provider-
|
|
6394
|
+
const provider = new (await import('./guest-auth-provider-2J4fnTX5.mjs')).GuestAuthProvider();
|
|
6326
6395
|
setAuthLoading(true); // reflect "signing in…" while the guest keypair session is minted
|
|
6327
6396
|
// adoptSessionProvider awaits only getConfig() (already resolved here) and then
|
|
6328
6397
|
// runs every write - provider/method/config/marker/user - in one synchronous
|
|
@@ -6493,7 +6562,7 @@ function ensureSharedWalletLoginReady() {
|
|
|
6493
6562
|
if (!sharedWalletReady) {
|
|
6494
6563
|
sharedWalletReady = (async () => {
|
|
6495
6564
|
await getConfig();
|
|
6496
|
-
await import('./injected-wallet-provider-
|
|
6565
|
+
await import('./injected-wallet-provider-0SSONh1d.mjs');
|
|
6497
6566
|
})().catch((error) => {
|
|
6498
6567
|
sharedWalletReady = null;
|
|
6499
6568
|
throw error;
|
|
@@ -6596,7 +6665,7 @@ async function loginWithWallet(options) {
|
|
|
6596
6665
|
await ensureSharedWalletLoginReady();
|
|
6597
6666
|
else
|
|
6598
6667
|
await ensureWalletLoginReady();
|
|
6599
|
-
const { InjectedWalletProvider } = await import('./injected-wallet-provider-
|
|
6668
|
+
const { InjectedWalletProvider } = await import('./injected-wallet-provider-0SSONh1d.mjs');
|
|
6600
6669
|
// Keep the RAW wallet provider: the offchain wrapper forwards only a fixed
|
|
6601
6670
|
// set of methods, so cleanup below must speak to the provider that actually
|
|
6602
6671
|
// holds the config rather than to whatever is wrapping it.
|
|
@@ -6868,7 +6937,8 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
6868
6937
|
logout: logout$1,
|
|
6869
6938
|
preloadWalletLogin: preloadWalletLogin,
|
|
6870
6939
|
resolveAuthMode: resolveAuthMode,
|
|
6871
|
-
signInAnonymously: signInAnonymously
|
|
6940
|
+
signInAnonymously: signInAnonymously,
|
|
6941
|
+
storedSessionAuthMethod: storedSessionAuthMethod
|
|
6872
6942
|
});
|
|
6873
6943
|
|
|
6874
6944
|
/**
|
|
@@ -6946,12 +7016,80 @@ let isAuthLoading = false;
|
|
|
6946
7016
|
let authReadyPromise = null;
|
|
6947
7017
|
let initializingConfig = null;
|
|
6948
7018
|
let initializationGeneration = 0;
|
|
7019
|
+
let initializedConfig = null;
|
|
7020
|
+
let storageBridgeRegistered = false;
|
|
7021
|
+
let observedIdToken = null;
|
|
7022
|
+
let observedIssuer = null;
|
|
7023
|
+
// Storage events carry no authority. Re-read the active manager's app/issuer
|
|
7024
|
+
// namespace, then use the ordinary initializer/provider restore and listeners.
|
|
7025
|
+
function registerStorageBridge() {
|
|
7026
|
+
if (storageBridgeRegistered || !getPlatform().hasDOM || typeof window === 'undefined')
|
|
7027
|
+
return;
|
|
7028
|
+
storageBridgeRegistered = true;
|
|
7029
|
+
window.addEventListener('storage', (event) => {
|
|
7030
|
+
if (event.storageArea !== window.localStorage || !initializedConfig)
|
|
7031
|
+
return;
|
|
7032
|
+
void syncStoredSession().catch((error) => console.warn('Bounded session synchronization failed:', error));
|
|
7033
|
+
});
|
|
7034
|
+
}
|
|
7035
|
+
async function syncStoredSession() {
|
|
7036
|
+
const config = initializedConfig;
|
|
7037
|
+
if (!config)
|
|
7038
|
+
return;
|
|
7039
|
+
const token = WebSessionManager.getIdToken();
|
|
7040
|
+
const issuer = WebSessionManager.getIssuer();
|
|
7041
|
+
if (token === observedIdToken && issuer === observedIssuer)
|
|
7042
|
+
return;
|
|
7043
|
+
observedIdToken = token;
|
|
7044
|
+
observedIssuer = issuer;
|
|
7045
|
+
const generation = ++initializationGeneration;
|
|
7046
|
+
// Hide the former principal while the replacement is validated. This also
|
|
7047
|
+
// reconnects live reads through the existing auth-state change path.
|
|
7048
|
+
setCurrentUser(null);
|
|
7049
|
+
if (authReadyPromise)
|
|
7050
|
+
await authReadyPromise.catch(() => { });
|
|
7051
|
+
if (generation !== initializationGeneration || config !== initializedConfig)
|
|
7052
|
+
return;
|
|
7053
|
+
const record = await WebSessionManager.readSessionWithGeneration();
|
|
7054
|
+
if (generation !== initializationGeneration || config !== initializedConfig)
|
|
7055
|
+
return;
|
|
7056
|
+
if (!record)
|
|
7057
|
+
return;
|
|
7058
|
+
const normalize = (url) => (url || '').replace(/\/+$/, '');
|
|
7059
|
+
const resolvedConfig = await getConfig();
|
|
7060
|
+
if (generation !== initializationGeneration || config !== initializedConfig)
|
|
7061
|
+
return;
|
|
7062
|
+
const allowedIssuers = [normalize(resolvedConfig.humanAuthApiUrl || 'https://auth.bounded.sh'), normalize(resolvedConfig.authApiUrl)].filter(Boolean);
|
|
7063
|
+
// A legacy shared blob can belong to another app. Never restore or clear
|
|
7064
|
+
// that app's credential; the current app remains signed out.
|
|
7065
|
+
if ((record.appId && record.appId !== config.appId)
|
|
7066
|
+
|| (record.issuer && !allowedIssuers.includes(normalize(record.issuer))))
|
|
7067
|
+
return;
|
|
7068
|
+
if (!storedSessionAuthMethod(config))
|
|
7069
|
+
return;
|
|
7070
|
+
const restored = startInitialization(config, true);
|
|
7071
|
+
const restoreGeneration = initializationGeneration;
|
|
7072
|
+
try {
|
|
7073
|
+
await restored;
|
|
7074
|
+
}
|
|
7075
|
+
catch (error) {
|
|
7076
|
+
if (restoreGeneration === initializationGeneration && WebSessionManager.getIdToken())
|
|
7077
|
+
throw error;
|
|
7078
|
+
}
|
|
7079
|
+
}
|
|
6949
7080
|
/** Internal guard for a login result arriving after the app reconfigured the SDK. */
|
|
6950
7081
|
function getInitializationGeneration() { return initializationGeneration; }
|
|
6951
7082
|
// This file acts as a middleware for the global state of the SDK
|
|
6952
7083
|
// This mostly involves setting up the AuthProvider and managing the current user
|
|
6953
|
-
async function initialize(requestedConfig) {
|
|
7084
|
+
async function initialize(requestedConfig, fromStorage) {
|
|
6954
7085
|
const newConfig = withDefaultSolanaRpcUrl(requestedConfig);
|
|
7086
|
+
const generation = initializationGeneration;
|
|
7087
|
+
const validateStorage = fromStorage ? WebSessionManager.captureSessionEstablishment() : undefined;
|
|
7088
|
+
const beforeCommit = () => {
|
|
7089
|
+
if (generation !== initializationGeneration)
|
|
7090
|
+
throw new Error('Session restore was superseded.');
|
|
7091
|
+
validateStorage === null || validateStorage === void 0 ? void 0 : validateStorage();
|
|
7092
|
+
};
|
|
6955
7093
|
// Mark auth as loading for the ENTIRE init/restore window so consumers render
|
|
6956
7094
|
// a neutral/loading state instead of the signed-out UI while we rehydrate the
|
|
6957
7095
|
// session — otherwise getCurrentUser() is null + loading is false during the
|
|
@@ -6970,8 +7108,9 @@ async function initialize(requestedConfig) {
|
|
|
6970
7108
|
// onAuthStateChanged never fired, and every consumer UI went on showing a
|
|
6971
7109
|
// connected wallet for a session the server no longer knew about.
|
|
6972
7110
|
registerSessionClearedBridge();
|
|
7111
|
+
registerStorageBridge();
|
|
6973
7112
|
// Get auth provider first
|
|
6974
|
-
authProviderInstance = await getAuthProvider(newConfig);
|
|
7113
|
+
authProviderInstance = await getAuthProvider(newConfig, fromStorage);
|
|
6975
7114
|
// Initialize config with auth provider
|
|
6976
7115
|
await init$2(Object.assign(Object.assign({}, newConfig), { authProvider: authProviderInstance }));
|
|
6977
7116
|
// A return establishes its own provider/session, or hands off a popup.
|
|
@@ -6996,7 +7135,8 @@ async function initialize(requestedConfig) {
|
|
|
6996
7135
|
// Wait for restoreSession to complete
|
|
6997
7136
|
// The appId check is done in SessionManager.getSession which is called by restoreSession
|
|
6998
7137
|
// If there's an appId mismatch, the session will be cleared and restoreSession will return null
|
|
6999
|
-
let user = await authProviderInstance.restoreSession();
|
|
7138
|
+
let user = await authProviderInstance.restoreSession(beforeCommit);
|
|
7139
|
+
beforeCommit();
|
|
7000
7140
|
// If a session exists but was created before auth method tracking (legacy session),
|
|
7001
7141
|
// clear it to avoid mismatches when the app switches auth methods (e.g. email → phantom)
|
|
7002
7142
|
//
|
|
@@ -7004,9 +7144,10 @@ async function initialize(requestedConfig) {
|
|
|
7004
7144
|
// unawaited call would return a Promise (always truthy) — nulling the user
|
|
7005
7145
|
// unconditionally AND letting setCurrentUser run while the old credential
|
|
7006
7146
|
// was still in storage.
|
|
7007
|
-
if (user && await clearIncompatibleSession()) {
|
|
7147
|
+
if (user && !fromStorage && await clearIncompatibleSession()) {
|
|
7008
7148
|
user = null;
|
|
7009
7149
|
}
|
|
7150
|
+
beforeCommit();
|
|
7010
7151
|
setCurrentUser(user);
|
|
7011
7152
|
// Mark init as completed
|
|
7012
7153
|
initCompleted = true;
|
|
@@ -7046,13 +7187,17 @@ function sameConfigValue(a, b, seen = new WeakMap()) {
|
|
|
7046
7187
|
&& sameConfigValue(a[key], b[key], seen));
|
|
7047
7188
|
}
|
|
7048
7189
|
function init$1(newConfig) {
|
|
7190
|
+
return startInitialization(newConfig, false);
|
|
7191
|
+
}
|
|
7192
|
+
function startInitialization(newConfig, fromStorage) {
|
|
7049
7193
|
if (initializingConfig) {
|
|
7050
7194
|
if (sameConfigValue(initializingConfig, newConfig)) {
|
|
7051
7195
|
return authReadyPromise;
|
|
7052
7196
|
}
|
|
7053
7197
|
return Promise.reject(new Error('SDK initialization is in progress. Await init() before changing its configuration.'));
|
|
7054
7198
|
}
|
|
7055
|
-
|
|
7199
|
+
initializedConfig = Object.assign({}, newConfig);
|
|
7200
|
+
initializingConfig = initializedConfig;
|
|
7056
7201
|
initializationGeneration++;
|
|
7057
7202
|
let resolveReady;
|
|
7058
7203
|
let rejectReady;
|
|
@@ -7064,7 +7209,7 @@ function init$1(newConfig) {
|
|
|
7064
7209
|
// auth-loading listener to call waitForAuthReady() synchronously when init()
|
|
7065
7210
|
// announces that session restoration has begun.
|
|
7066
7211
|
authReadyPromise = ready;
|
|
7067
|
-
void initialize(initializingConfig).then(() => { initializingConfig = null; resolveReady(); }, (error) => { initializingConfig = null; rejectReady(error); });
|
|
7212
|
+
void initialize(initializingConfig, fromStorage).then(() => { initializingConfig = null; resolveReady(); }, (error) => { initializingConfig = null; rejectReady(error); });
|
|
7068
7213
|
return ready;
|
|
7069
7214
|
}
|
|
7070
7215
|
/**
|
|
@@ -7137,6 +7282,13 @@ function userPrincipalKey(user) {
|
|
|
7137
7282
|
}
|
|
7138
7283
|
// Update the currentUser and notify listeners
|
|
7139
7284
|
function setCurrentUser(user) {
|
|
7285
|
+
observedIdToken = getCurrentIdToken();
|
|
7286
|
+
try {
|
|
7287
|
+
observedIssuer = getActiveSessionManager().getIssuer();
|
|
7288
|
+
}
|
|
7289
|
+
catch (_a) {
|
|
7290
|
+
observedIssuer = null;
|
|
7291
|
+
}
|
|
7140
7292
|
// Enrich with the universal identity fields (id/email) derived from the
|
|
7141
7293
|
// active session's idToken — central chokepoint so every provider's user
|
|
7142
7294
|
// object gains { id, address, email } without each construction site
|
|
@@ -7682,10 +7834,18 @@ async function startTurnkeyEmailLogin(email) {
|
|
|
7682
7834
|
if (!hasDOM$1()) {
|
|
7683
7835
|
throw new Error('Turnkey-native email login is web-only - on React Native use loginWithRedirect()');
|
|
7684
7836
|
}
|
|
7837
|
+
const generation = getInitializationGeneration();
|
|
7838
|
+
const walletGuard = walletOperationGuard();
|
|
7839
|
+
const assertContext = () => {
|
|
7840
|
+
walletGuard();
|
|
7841
|
+
if (generation !== getInitializationGeneration())
|
|
7842
|
+
throw new Error('Login was superseded by SDK reinitialization. Start sign-in again.');
|
|
7843
|
+
};
|
|
7685
7844
|
const trimmed = email.trim();
|
|
7686
7845
|
if (!trimmed)
|
|
7687
7846
|
throw new Error('Enter your email to continue.');
|
|
7688
7847
|
const { base, appId } = await inlineAuthEndpoint();
|
|
7848
|
+
assertContext();
|
|
7689
7849
|
if (!appId)
|
|
7690
7850
|
throw new Error('appId is not configured (init the SDK with your appId)');
|
|
7691
7851
|
const res = await fetch(`${base}/wallet/turnkey/auth/init`, {
|
|
@@ -7697,6 +7857,7 @@ async function startTurnkeyEmailLogin(email) {
|
|
|
7697
7857
|
if (!res.ok || !data || typeof data.otpId !== 'string' || typeof data.otpEncryptionTargetBundle !== 'string') {
|
|
7698
7858
|
throw new Error(String((data && data.error) || 'Could not send a code. Please try again.'));
|
|
7699
7859
|
}
|
|
7860
|
+
assertContext();
|
|
7700
7861
|
const otpId = data.otpId;
|
|
7701
7862
|
const otpEncryptionTargetBundle = data.otpEncryptionTargetBundle;
|
|
7702
7863
|
// A tenant-origin login always gets a ceremony id; without one the OTP frame refuses to run
|
|
@@ -7712,14 +7873,20 @@ async function startTurnkeyEmailLogin(email) {
|
|
|
7712
7873
|
: undefined;
|
|
7713
7874
|
return {
|
|
7714
7875
|
email: trimmed, frameUrl, signerOrigin,
|
|
7715
|
-
run(iframe,
|
|
7876
|
+
run(iframe, signal) {
|
|
7877
|
+
try {
|
|
7878
|
+
assertContext();
|
|
7879
|
+
}
|
|
7880
|
+
catch (error) {
|
|
7881
|
+
return Promise.reject(error);
|
|
7882
|
+
}
|
|
7716
7883
|
if (!ceremonyId) {
|
|
7717
7884
|
return Promise.reject(new Error('This app is not configured for in-frame wallet login. Please try again.'));
|
|
7718
7885
|
}
|
|
7719
|
-
const run = { iframe, base, signerOrigin, appId, email: trimmed, otpId, otpEncryptionTargetBundle, ceremonyId };
|
|
7886
|
+
const run = { iframe, base, signerOrigin, appId, email: trimmed, otpId, otpEncryptionTargetBundle, ceremonyId, generation };
|
|
7720
7887
|
// BSA-2026-004: the login code is typed only in /wallet/turnkey/otp-frame.
|
|
7721
7888
|
// The scoped signer URL is for post-login signing, not OTP entry.
|
|
7722
|
-
return runOtpFrame(run);
|
|
7889
|
+
return runOtpFrame(run, signal);
|
|
7723
7890
|
},
|
|
7724
7891
|
};
|
|
7725
7892
|
}
|
|
@@ -7728,7 +7895,7 @@ async function startTurnkeyEmailLogin(email) {
|
|
|
7728
7895
|
// frame 'result' {session} -> we establish the inline session and resolve the User.
|
|
7729
7896
|
// When the frame asks for the signing-session authorization ('need-authorization') we mint a
|
|
7730
7897
|
// createWallet action authorization on THIS (registered) origin and post it in - never a key.
|
|
7731
|
-
function runOtpFrame(run) {
|
|
7898
|
+
function runOtpFrame(run, signal) {
|
|
7732
7899
|
const tenantOrigin = window.location.origin;
|
|
7733
7900
|
const url = `${run.base.replace(/\/$/, '')}/wallet/turnkey/otp-frame`
|
|
7734
7901
|
+ `?appId=${encodeURIComponent(run.appId)}`
|
|
@@ -7738,13 +7905,48 @@ function runOtpFrame(run) {
|
|
|
7738
7905
|
return new Promise((resolve, reject) => {
|
|
7739
7906
|
let settled = false;
|
|
7740
7907
|
let started = false;
|
|
7741
|
-
|
|
7908
|
+
let receivingResult = false;
|
|
7909
|
+
let committing = false;
|
|
7910
|
+
const walletGuard = walletLoginGuard(signal);
|
|
7911
|
+
const beforeCommit = () => {
|
|
7912
|
+
if (settled)
|
|
7913
|
+
throw new Error('wallet_login_cancelled');
|
|
7914
|
+
walletGuard();
|
|
7915
|
+
if (run.generation !== getInitializationGeneration())
|
|
7916
|
+
throw new Error('Login was superseded by SDK reinitialization. Start sign-in again.');
|
|
7917
|
+
};
|
|
7918
|
+
const finish = (error, user) => {
|
|
7919
|
+
if (settled)
|
|
7920
|
+
return;
|
|
7921
|
+
settled = true;
|
|
7922
|
+
window.removeEventListener('message', onMsg);
|
|
7923
|
+
window.clearTimeout(timer);
|
|
7924
|
+
signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', onAbort);
|
|
7925
|
+
if (error) {
|
|
7926
|
+
// Destroy the expired frame's code/key realm as well as its parent listener.
|
|
7927
|
+
run.iframe.src = 'about:blank';
|
|
7928
|
+
reject(error);
|
|
7929
|
+
}
|
|
7930
|
+
else
|
|
7931
|
+
resolve(user);
|
|
7932
|
+
};
|
|
7933
|
+
const onAbort = () => { if (!committing)
|
|
7934
|
+
finish(new Error('cancelled')); };
|
|
7742
7935
|
const onMsg = async (event) => {
|
|
7743
7936
|
if (settled)
|
|
7744
7937
|
return;
|
|
7745
7938
|
// Trust ONLY the signer origin and the frame's own window.
|
|
7746
7939
|
if (event.origin !== run.signerOrigin || event.source !== run.iframe.contentWindow)
|
|
7747
7940
|
return;
|
|
7941
|
+
if (!committing) {
|
|
7942
|
+
try {
|
|
7943
|
+
beforeCommit();
|
|
7944
|
+
}
|
|
7945
|
+
catch (error) {
|
|
7946
|
+
finish(error instanceof Error ? error : new Error(String(error)));
|
|
7947
|
+
return;
|
|
7948
|
+
}
|
|
7949
|
+
}
|
|
7748
7950
|
const d = event.data;
|
|
7749
7951
|
if (!d || typeof d !== 'object')
|
|
7750
7952
|
return;
|
|
@@ -7787,40 +7989,56 @@ function runOtpFrame(run) {
|
|
|
7787
7989
|
return;
|
|
7788
7990
|
}
|
|
7789
7991
|
if (d.type === 'bounded:otp:result') {
|
|
7992
|
+
if (receivingResult)
|
|
7993
|
+
return;
|
|
7994
|
+
receivingResult = true;
|
|
7790
7995
|
if (d.ok && d.session && typeof d.session === 'object') {
|
|
7791
7996
|
try {
|
|
7792
|
-
const user = await establishInlineSession(d.session);
|
|
7793
|
-
|
|
7794
|
-
resolve(user);
|
|
7997
|
+
const user = await establishInlineSession(d.session, beforeCommit, undefined, () => { committing = true; });
|
|
7998
|
+
finish(undefined, user);
|
|
7795
7999
|
}
|
|
7796
8000
|
catch (error) {
|
|
7797
|
-
|
|
7798
|
-
reject(error instanceof Error ? error : new Error(String(error)));
|
|
8001
|
+
finish(error instanceof Error ? error : new Error(String(error)));
|
|
7799
8002
|
}
|
|
7800
8003
|
return;
|
|
7801
8004
|
}
|
|
7802
|
-
|
|
7803
|
-
reject(new Error(String((d && d.error) || 'Invalid or expired code.')));
|
|
8005
|
+
finish(new Error(String((d && d.error) || 'Invalid or expired code.')));
|
|
7804
8006
|
return;
|
|
7805
8007
|
}
|
|
7806
8008
|
// 'bounded:otp:registered' is advisory; login does not depend on it.
|
|
7807
8009
|
};
|
|
7808
8010
|
const post = (msg) => {
|
|
7809
8011
|
var _a;
|
|
8012
|
+
if (settled)
|
|
8013
|
+
return;
|
|
8014
|
+
if (!committing) {
|
|
8015
|
+
try {
|
|
8016
|
+
beforeCommit();
|
|
8017
|
+
}
|
|
8018
|
+
catch (_b) {
|
|
8019
|
+
return;
|
|
8020
|
+
}
|
|
8021
|
+
}
|
|
7810
8022
|
try {
|
|
7811
8023
|
(_a = run.iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage(msg, run.signerOrigin);
|
|
7812
8024
|
}
|
|
7813
|
-
catch ( /* frame gone */
|
|
8025
|
+
catch ( /* frame gone */_c) { /* frame gone */ }
|
|
7814
8026
|
};
|
|
7815
8027
|
window.addEventListener('message', onMsg);
|
|
7816
8028
|
// 3 minutes: the human must read the email and type the code. A frame that never reports is a
|
|
7817
8029
|
// failed login the user can retry.
|
|
7818
8030
|
const timer = window.setTimeout(() => {
|
|
7819
|
-
if (
|
|
7820
|
-
|
|
7821
|
-
cleanup();
|
|
7822
|
-
reject(new Error('The sign-in code entry timed out. Please try again.'));
|
|
8031
|
+
if (!committing)
|
|
8032
|
+
finish(new Error('The sign-in code entry timed out. Please try again.'));
|
|
7823
8033
|
}, 3 * 60 * 1000);
|
|
8034
|
+
signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', onAbort, { once: true });
|
|
8035
|
+
try {
|
|
8036
|
+
beforeCommit();
|
|
8037
|
+
}
|
|
8038
|
+
catch (error) {
|
|
8039
|
+
finish(error instanceof Error ? error : new Error(String(error)));
|
|
8040
|
+
return;
|
|
8041
|
+
}
|
|
7824
8042
|
run.iframe.src = url;
|
|
7825
8043
|
});
|
|
7826
8044
|
}
|
|
@@ -8084,7 +8302,8 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8084
8302
|
return authApi.loginWithRedirect(options);
|
|
8085
8303
|
// Invoke immediately inside the click handler to retain popup activation.
|
|
8086
8304
|
return authApi.loginWithPopup(options).catch((error) => {
|
|
8087
|
-
|
|
8305
|
+
var _a;
|
|
8306
|
+
if (!((_a = options.signal) === null || _a === void 0 ? void 0 : _a.aborted) && shouldFallbackToRedirect(error))
|
|
8088
8307
|
return authApi.loginWithRedirect(options);
|
|
8089
8308
|
throw error;
|
|
8090
8309
|
});
|
|
@@ -8222,6 +8441,12 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8222
8441
|
let activeAttempt = 0;
|
|
8223
8442
|
let abortScopedLogin = null;
|
|
8224
8443
|
let abortGesture = null;
|
|
8444
|
+
const startHostedLogin = (options) => {
|
|
8445
|
+
const controller = new AbortController();
|
|
8446
|
+
const abort = () => controller.abort();
|
|
8447
|
+
abortScopedLogin = abort;
|
|
8448
|
+
return hostedLogin(Object.assign(Object.assign({}, options), { signal: controller.signal }));
|
|
8449
|
+
};
|
|
8225
8450
|
/** Reject a gesture promise already waiting on a view that is going away. */
|
|
8226
8451
|
const abortPendingGesture = () => {
|
|
8227
8452
|
const abort = abortGesture;
|
|
@@ -8247,6 +8472,7 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8247
8472
|
if (!attemptIsCurrent(id))
|
|
8248
8473
|
return false;
|
|
8249
8474
|
activeAttempt = 0;
|
|
8475
|
+
abortScopedLogin = null;
|
|
8250
8476
|
return true;
|
|
8251
8477
|
};
|
|
8252
8478
|
/** Take the card back (Back, a lane switch, settling the modal). Deliberately
|
|
@@ -8401,7 +8627,7 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8401
8627
|
loginHint: input.value,
|
|
8402
8628
|
redirectUri: opts.redirectUri,
|
|
8403
8629
|
};
|
|
8404
|
-
|
|
8630
|
+
startHostedLogin(emailOpts)
|
|
8405
8631
|
// A hosted login that RESOLVES minted a real session, so it settles
|
|
8406
8632
|
// the card even if another lane has since taken it - dropping it
|
|
8407
8633
|
// would leave the app signed in behind a widget that says it is not.
|
|
@@ -8451,7 +8677,7 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8451
8677
|
}
|
|
8452
8678
|
setBusy(b, "Opening secure sign-in\u2026");
|
|
8453
8679
|
const socialOpts = { provider: method, redirectUri: opts.redirectUri };
|
|
8454
|
-
|
|
8680
|
+
startHostedLogin(socialOpts)
|
|
8455
8681
|
.then((u) => {
|
|
8456
8682
|
if (u) {
|
|
8457
8683
|
settleAttempt(attempt);
|
|
@@ -8701,14 +8927,16 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8701
8927
|
setErr(BUSY_MSG);
|
|
8702
8928
|
return card;
|
|
8703
8929
|
}
|
|
8704
|
-
back.addEventListener("click", () => {
|
|
8930
|
+
back.addEventListener("click", () => { invalidateAttempts(); swap(renderChoose()); });
|
|
8931
|
+
const controller = new AbortController();
|
|
8932
|
+
abortScopedLogin = () => controller.abort();
|
|
8705
8933
|
handle
|
|
8706
|
-
.run(frame)
|
|
8934
|
+
.run(frame, controller.signal)
|
|
8707
8935
|
.then((u) => { settleAttempt(attempt); succeed(u); })
|
|
8708
8936
|
.catch((err) => {
|
|
8709
8937
|
if (!settleAttempt(attempt))
|
|
8710
8938
|
return;
|
|
8711
|
-
|
|
8939
|
+
swap(renderChoose(errText(err)));
|
|
8712
8940
|
});
|
|
8713
8941
|
return card;
|
|
8714
8942
|
};
|
|
@@ -10523,8 +10751,9 @@ class PrivyExpoProvider {
|
|
|
10523
10751
|
const { signature } = await this.signAndSubmitInternal(transaction, wallet, connection);
|
|
10524
10752
|
return signature;
|
|
10525
10753
|
}
|
|
10526
|
-
async restoreSession() {
|
|
10754
|
+
async restoreSession(beforeCommit) {
|
|
10527
10755
|
const session = await getActiveSessionManager().getSession();
|
|
10756
|
+
beforeCommit === null || beforeCommit === void 0 ? void 0 : beforeCommit();
|
|
10528
10757
|
if (session) {
|
|
10529
10758
|
this.authenticatedAddress = session.address;
|
|
10530
10759
|
return { provider: this, address: session.address };
|
|
@@ -11039,4 +11268,4 @@ function init(config = {}) {
|
|
|
11039
11268
|
}
|
|
11040
11269
|
|
|
11041
11270
|
export { onrampStatus as $, getAuthProvider as A, signInAnonymously as B, loginWithPrivy as C, loginWithWallet as D, ensureWalletLoginReady as E, ensureSharedWalletLoginReady as F, preloadWalletLogin as G, loginWithRedirect as H, completeLoginFromRedirect as I, getLoginReturnError as J, loginWithPopup as K, openBoundedWidget as L, ensureSignedIn as M, useAuth as N, useQuery as O, useBuildRun as P, apps as Q, signSolanaMessageViaTurnkey as R, getOrCreateTurnkeyWallet as S, openTurnkeyKeyExport as T, getTurnkeyWalletSessionState as U, getTurnkeyWalletRecoveryUrl as V, WalletConfigError as W, startTurnkeyEmailLogin as X, getIdToken as Y, onramp as Z, onrampQuote as _, signMessageWithTurnkey as a, setPlatform as a0, OffchainAuthProvider as a1, PrivyExpoProvider as a2, requestEip6963Providers as a3, connectBroadcast as a4, connectServiceSession as a5, builds as a6, BuildsApiError as a7, mediaAgentTools as a8, NON_TERMINAL_STATES as a9, TERMINAL_STATES as aa, RUN_STATES as ab, PARK_REASONS as ac, FAILURE_REASONS as ad, BUILD_REVIEW_CAPABILITY_SCHEMA as ae, BUILD_REVIEW_CAPABILITY_REFRESH_SCHEMA as af, BUILD_DELEGATED_REVIEW_CAPABILITY_SCHEMA as ag, signTransactionWithTurnkey as b, signTransactionV1WithTurnkey as c, signAndSubmitTransactionWithTurnkey as d, bs58 as e, defaultInjectedProvider as f, getPlatform as g, hasTurnkeyWallet as h, firstStandardWalletProvider as i, setAuthLoading as j, bufferExports as k, setStoredAuthMethod as l, confirmAndCheckTransaction as m, normalizeSolanaRpcUrl as n, defaultInjectedEvmProvider as o, init as p, getCurrentUser as q, resolveSolanaRpcUrl as r, setCurrentUser as s, transactionHasSignature as t, onAuthStateChanged as u, onAuthLoadingChanged as v, getAuthLoading as w, waitForAuthReady as x, login as y, logout as z };
|
|
11042
|
-
//# sourceMappingURL=index-
|
|
11271
|
+
//# sourceMappingURL=index-D3kdhCpH.mjs.map
|