@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
|
@@ -56,6 +56,13 @@ function walletOperationGuard() {
|
|
|
56
56
|
throw new Error('wallet_session_changed');
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
|
+
function walletLoginGuard(signal) {
|
|
60
|
+
const generation = ++loginGeneration;
|
|
61
|
+
return () => {
|
|
62
|
+
if ((signal === null || signal === void 0 ? void 0 : signal.aborted) || generation !== loginGeneration)
|
|
63
|
+
throw new Error('wallet_login_cancelled');
|
|
64
|
+
};
|
|
65
|
+
}
|
|
59
66
|
// This realm owns one active SDK session and one retained signer frame.
|
|
60
67
|
let activeWalletState;
|
|
61
68
|
function setWalletSessionState(key, state) { activeWalletState = { key, state }; }
|
|
@@ -277,8 +284,9 @@ class OffchainAuthProvider {
|
|
|
277
284
|
async logout() {
|
|
278
285
|
await this.wrappedProvider.logout();
|
|
279
286
|
}
|
|
280
|
-
async restoreSession() {
|
|
281
|
-
const
|
|
287
|
+
async restoreSession(beforeCommit) {
|
|
288
|
+
const provider = this.wrappedProvider;
|
|
289
|
+
const user = await provider.restoreSession(beforeCommit);
|
|
282
290
|
if (user) {
|
|
283
291
|
return Object.assign(Object.assign({}, user), { provider: this });
|
|
284
292
|
}
|
|
@@ -5532,7 +5540,8 @@ async function loginWithRedirect(opts) {
|
|
|
5532
5540
|
return runNativeLogin(opts);
|
|
5533
5541
|
if (!hasDOM$2())
|
|
5534
5542
|
throw new Error('loginWithRedirect requires a browser or a configured React Native platform');
|
|
5535
|
-
const { url, pkce } = await buildAuthorize(opts);
|
|
5543
|
+
const { url, pkce } = await untilAborted(buildAuthorize(opts), opts.signal);
|
|
5544
|
+
throwIfCancelled(opts.signal);
|
|
5536
5545
|
// Stash the verifier + state so the redirect_uri page can finish the exchange. sessionStorage
|
|
5537
5546
|
// is per-tab and cleared on close — appropriate for a short-lived auth handshake. Keyed by
|
|
5538
5547
|
// this attempt's own state so a second concurrent login cannot overwrite it.
|
|
@@ -5561,9 +5570,29 @@ async function completeLoginFromRedirect() {
|
|
|
5561
5570
|
throw error;
|
|
5562
5571
|
return result.user;
|
|
5563
5572
|
}
|
|
5573
|
+
function throwIfCancelled(signal) {
|
|
5574
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted)
|
|
5575
|
+
throw new Error('cancelled');
|
|
5576
|
+
}
|
|
5577
|
+
async function untilAborted(work, signal) {
|
|
5578
|
+
if (!signal)
|
|
5579
|
+
return work;
|
|
5580
|
+
throwIfCancelled(signal);
|
|
5581
|
+
let onAbort;
|
|
5582
|
+
try {
|
|
5583
|
+
return await Promise.race([work, new Promise((_, reject) => {
|
|
5584
|
+
onAbort = () => reject(new Error('cancelled'));
|
|
5585
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
5586
|
+
})]);
|
|
5587
|
+
}
|
|
5588
|
+
finally {
|
|
5589
|
+
signal.removeEventListener('abort', onAbort);
|
|
5590
|
+
}
|
|
5591
|
+
}
|
|
5564
5592
|
/** Popup variant: open the hosted login in a popup; resolves with the User once the popup's
|
|
5565
5593
|
* redirect_uri page initializes the SDK, which hands the code back automatically. */
|
|
5566
5594
|
async function loginWithPopup(opts) {
|
|
5595
|
+
throwIfCancelled(opts.signal);
|
|
5567
5596
|
if (!hasDOM$2())
|
|
5568
5597
|
throw new Error('loginWithPopup is web-only — on React Native use loginWithRedirect()');
|
|
5569
5598
|
// Open synchronously, before PKCE/config awaits consume the click's user-
|
|
@@ -5581,7 +5610,7 @@ async function loginWithPopup(opts) {
|
|
|
5581
5610
|
throw new Error('Popup blocked — use loginWithRedirect() instead');
|
|
5582
5611
|
let authorization;
|
|
5583
5612
|
try {
|
|
5584
|
-
authorization = await buildAuthorize(opts, 'popup');
|
|
5613
|
+
authorization = await untilAborted(buildAuthorize(opts, 'popup'), opts.signal);
|
|
5585
5614
|
}
|
|
5586
5615
|
catch (error) {
|
|
5587
5616
|
try {
|
|
@@ -5598,6 +5627,7 @@ async function loginWithPopup(opts) {
|
|
|
5598
5627
|
// window with no listener or watchdog attached.
|
|
5599
5628
|
let expectedOrigin;
|
|
5600
5629
|
try {
|
|
5630
|
+
throwIfCancelled(opts.signal);
|
|
5601
5631
|
expectedOrigin = new URL(pkce.redirectUri).origin;
|
|
5602
5632
|
sessionStorage.setItem(pkceKey(pkce.state), JSON.stringify(pkce));
|
|
5603
5633
|
}
|
|
@@ -5629,20 +5659,42 @@ async function loginWithPopup(opts) {
|
|
|
5629
5659
|
setAuthLoading(true); // reflect "signing in…" while the popup is open
|
|
5630
5660
|
try {
|
|
5631
5661
|
return await new Promise((resolve, reject) => {
|
|
5662
|
+
var _a, _b;
|
|
5632
5663
|
let settled = false;
|
|
5664
|
+
let handedOff = false;
|
|
5665
|
+
let committing = false;
|
|
5633
5666
|
let timer;
|
|
5634
5667
|
let navigationTimer;
|
|
5635
5668
|
let completionTimer;
|
|
5636
5669
|
const cleanup = () => {
|
|
5637
|
-
settled = true;
|
|
5638
5670
|
clearInterval(timer);
|
|
5639
5671
|
clearTimeout(navigationTimer);
|
|
5640
5672
|
clearTimeout(completionTimer);
|
|
5641
5673
|
window.removeEventListener('message', onMsg);
|
|
5642
5674
|
removeAttempt(pkce.state);
|
|
5643
5675
|
};
|
|
5676
|
+
const finish = (error, user) => {
|
|
5677
|
+
var _a;
|
|
5678
|
+
if (settled)
|
|
5679
|
+
return;
|
|
5680
|
+
settled = true;
|
|
5681
|
+
cleanup();
|
|
5682
|
+
(_a = opts.signal) === null || _a === void 0 ? void 0 : _a.removeEventListener('abort', onAbort);
|
|
5683
|
+
try {
|
|
5684
|
+
popup.close();
|
|
5685
|
+
}
|
|
5686
|
+
catch ( /* ignore */_b) { /* ignore */ }
|
|
5687
|
+
if (error)
|
|
5688
|
+
reject(error);
|
|
5689
|
+
else
|
|
5690
|
+
resolve(user);
|
|
5691
|
+
};
|
|
5692
|
+
// Provider adoption commits synchronously after its final guard. An auth
|
|
5693
|
+
// listener dismissing the card there cannot cancel an already signed-in user.
|
|
5694
|
+
const onAbort = () => { if (!committing)
|
|
5695
|
+
finish(new Error('cancelled')); };
|
|
5644
5696
|
const onMsg = async (ev) => {
|
|
5645
|
-
if (settled || ev.origin !== expectedOrigin || ev.source !== popup)
|
|
5697
|
+
if (settled || handedOff || ev.origin !== expectedOrigin || ev.source !== popup)
|
|
5646
5698
|
return;
|
|
5647
5699
|
const d = ev.data;
|
|
5648
5700
|
if (!d || d.type !== 'bounded-oidc-code' ||
|
|
@@ -5656,35 +5708,30 @@ async function loginWithPopup(opts) {
|
|
|
5656
5708
|
return;
|
|
5657
5709
|
if (d.appId !== pkce.appId || d.issuer !== pkce.issuer)
|
|
5658
5710
|
return;
|
|
5711
|
+
handedOff = true;
|
|
5659
5712
|
cleanup();
|
|
5660
5713
|
try {
|
|
5714
|
+
throwIfCancelled(opts.signal);
|
|
5661
5715
|
await validateAttempt(pkce, new URL(d.callbackUrl));
|
|
5716
|
+
throwIfCancelled(opts.signal);
|
|
5662
5717
|
popup.postMessage({ type: 'bounded-oidc-accepted', state: pkce.state }, expectedOrigin);
|
|
5663
5718
|
if (d.error)
|
|
5664
5719
|
throw new Error(typeof d.errorDescription === 'string' ? d.errorDescription : `Login failed: ${d.error}`);
|
|
5665
|
-
const user = await exchangeCode(d.code, pkce);
|
|
5666
|
-
|
|
5667
|
-
popup.close();
|
|
5668
|
-
}
|
|
5669
|
-
catch ( /* ignore */_a) { /* ignore */ }
|
|
5670
|
-
resolve(user);
|
|
5720
|
+
const user = await exchangeCode(d.code, pkce, opts.signal, () => { committing = true; });
|
|
5721
|
+
finish(undefined, user);
|
|
5671
5722
|
}
|
|
5672
5723
|
catch (e) {
|
|
5673
|
-
|
|
5674
|
-
popup.close();
|
|
5675
|
-
}
|
|
5676
|
-
catch ( /* ignore */_b) { /* ignore */ }
|
|
5677
|
-
reject(e);
|
|
5724
|
+
finish(e);
|
|
5678
5725
|
}
|
|
5679
5726
|
};
|
|
5727
|
+
(_a = opts.signal) === null || _a === void 0 ? void 0 : _a.addEventListener('abort', onAbort, { once: true });
|
|
5728
|
+
if ((_b = opts.signal) === null || _b === void 0 ? void 0 : _b.aborted) {
|
|
5729
|
+
onAbort();
|
|
5730
|
+
return;
|
|
5731
|
+
}
|
|
5680
5732
|
window.addEventListener('message', onMsg);
|
|
5681
5733
|
completionTimer = setTimeout(() => {
|
|
5682
|
-
|
|
5683
|
-
try {
|
|
5684
|
-
popup.close();
|
|
5685
|
-
}
|
|
5686
|
-
catch ( /* ignore */_a) { /* ignore */ }
|
|
5687
|
-
reject(new Error('Login expired or its popup disconnected. Start sign-in again.'));
|
|
5734
|
+
finish(new Error('Login expired or its popup disconnected. Start sign-in again.'));
|
|
5688
5735
|
}, LOGIN_TIMEOUT_MS);
|
|
5689
5736
|
// Some browser/extension combinations can return a real popup handle but
|
|
5690
5737
|
// strand the window at about:blank instead of navigating to the hosted
|
|
@@ -5705,23 +5752,18 @@ async function loginWithPopup(opts) {
|
|
|
5705
5752
|
const NAVIGATION_RECHECK_MS = 2000;
|
|
5706
5753
|
const navigationStartedAt = Date.now();
|
|
5707
5754
|
const checkNavigation = () => {
|
|
5708
|
-
if (settled || popup.closed)
|
|
5755
|
+
if (settled || handedOff || popup.closed)
|
|
5709
5756
|
return;
|
|
5710
5757
|
try {
|
|
5711
5758
|
if (popup.location.href === 'about:blank') {
|
|
5712
5759
|
if (Date.now() - navigationStartedAt >= NAVIGATION_GRACE_MS) {
|
|
5713
|
-
|
|
5714
|
-
try {
|
|
5715
|
-
popup.close();
|
|
5716
|
-
}
|
|
5717
|
-
catch ( /* ignore */_a) { /* ignore */ }
|
|
5718
|
-
reject(new Error('Popup stalled at about:blank - use loginWithRedirect() instead'));
|
|
5760
|
+
finish(new Error('Popup stalled at about:blank - use loginWithRedirect() instead'));
|
|
5719
5761
|
return;
|
|
5720
5762
|
}
|
|
5721
5763
|
navigationTimer = setTimeout(checkNavigation, NAVIGATION_RECHECK_MS);
|
|
5722
5764
|
}
|
|
5723
5765
|
}
|
|
5724
|
-
catch ( /* cross-origin hosted auth loaded normally */
|
|
5766
|
+
catch ( /* cross-origin hosted auth loaded normally */_a) { /* cross-origin hosted auth loaded normally */ }
|
|
5725
5767
|
};
|
|
5726
5768
|
navigationTimer = setTimeout(checkNavigation, NAVIGATION_RECHECK_MS);
|
|
5727
5769
|
// The popup posts its code and then closes ITSELF, so a naive "popup.closed -> reject"
|
|
@@ -5731,10 +5773,8 @@ async function loginWithPopup(opts) {
|
|
|
5731
5773
|
timer = setInterval(() => {
|
|
5732
5774
|
if (popup.closed) {
|
|
5733
5775
|
clearInterval(timer);
|
|
5734
|
-
setTimeout(() => { if (!settled)
|
|
5735
|
-
|
|
5736
|
-
reject(new Error('Login window closed'));
|
|
5737
|
-
} }, 500);
|
|
5776
|
+
setTimeout(() => { if (!settled && !handedOff)
|
|
5777
|
+
finish(new Error('Login window closed')); }, 500);
|
|
5738
5778
|
}
|
|
5739
5779
|
}, 500);
|
|
5740
5780
|
});
|
|
@@ -5748,20 +5788,21 @@ async function loginWithPopup(opts) {
|
|
|
5748
5788
|
// Turnkey-native login path (authMode:"turnkey"), which mints the session server-side
|
|
5749
5789
|
// after Turnkey verifies the email OTP - there is no OIDC code to exchange. Wiring is
|
|
5750
5790
|
// identical to exchangeCode's tail so the realtime worker cannot tell them apart.
|
|
5751
|
-
async function establishInlineSession(data, beforeCommit, beforeStore) {
|
|
5791
|
+
async function establishInlineSession(data, beforeCommit, beforeStore, onCommitting) {
|
|
5752
5792
|
const base = await issuerBase();
|
|
5793
|
+
beforeCommit === null || beforeCommit === void 0 ? void 0 : beforeCommit();
|
|
5753
5794
|
const idToken = tokenField(data, 'id_token', 'idToken');
|
|
5754
5795
|
if (!idToken)
|
|
5755
5796
|
throw new Error('No id_token in the inline session response');
|
|
5756
5797
|
const accessToken = tokenField(data, 'access_token', 'accessToken') || idToken;
|
|
5757
5798
|
const refreshToken = boundedRefreshTokenField(data);
|
|
5758
5799
|
const user = userFromIdToken(idToken);
|
|
5759
|
-
const rollback = await sessionManager().storeSession(String(user.address || ''), accessToken, idToken, refreshToken, base, () => { });
|
|
5800
|
+
const rollback = await sessionManager().storeSession(String(user.address || ''), accessToken, idToken, refreshToken, base, () => { beforeCommit === null || beforeCommit === void 0 ? void 0 : beforeCommit(); });
|
|
5760
5801
|
// Adopt the OIDC provider on EVERY session surface - including core's signing
|
|
5761
5802
|
// pointer (getConfig().authProvider), which this path used to skip, leaving
|
|
5762
5803
|
// onchain writes routed through a previous (e.g. logged-out wallet) provider.
|
|
5763
5804
|
try {
|
|
5764
|
-
await adoptSessionProvider({ provider: oidcProviderSingleton, method: 'email', configKey: 'direct:oidc', user, beforeCommit });
|
|
5805
|
+
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(); } });
|
|
5765
5806
|
}
|
|
5766
5807
|
catch (error) {
|
|
5767
5808
|
if (typeof rollback === 'function')
|
|
@@ -5785,9 +5826,10 @@ async function inlineAuthEndpoint() {
|
|
|
5785
5826
|
const cfg = await core.getConfig();
|
|
5786
5827
|
return { base: await issuerBase(), appId: cfg.appId };
|
|
5787
5828
|
}
|
|
5788
|
-
async function exchangeCode(code, pkce) {
|
|
5829
|
+
async function exchangeCode(code, pkce, signal, onCommitting) {
|
|
5789
5830
|
const generation = getInitializationGeneration();
|
|
5790
5831
|
const beforeCommit = () => {
|
|
5832
|
+
throwIfCancelled(signal);
|
|
5791
5833
|
if (generation !== getInitializationGeneration())
|
|
5792
5834
|
throw new Error('Login was superseded by SDK reinitialization. Start sign-in again.');
|
|
5793
5835
|
};
|
|
@@ -5803,7 +5845,7 @@ async function exchangeCode(code, pkce) {
|
|
|
5803
5845
|
let res;
|
|
5804
5846
|
try {
|
|
5805
5847
|
res = await fetch(`${base}/api/auth/oauth2/token`, {
|
|
5806
|
-
method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded' }, body: body.toString(),
|
|
5848
|
+
method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded' }, body: body.toString(), signal,
|
|
5807
5849
|
});
|
|
5808
5850
|
}
|
|
5809
5851
|
catch (err) {
|
|
@@ -5829,7 +5871,7 @@ async function exchangeCode(code, pkce) {
|
|
|
5829
5871
|
// Adopt on EVERY session surface (see establishInlineSession) - hosted
|
|
5830
5872
|
// popup/redirect completions all land here, so this closes their gap too.
|
|
5831
5873
|
try {
|
|
5832
|
-
await adoptSessionProvider({ provider: oidcProviderSingleton, method: 'email', configKey: 'direct:oidc', user, beforeCommit });
|
|
5874
|
+
await adoptSessionProvider({ provider: oidcProviderSingleton, method: 'email', configKey: 'direct:oidc', user, beforeCommit: () => { beforeCommit(); onCommitting === null || onCommitting === void 0 ? void 0 : onCommitting(); } });
|
|
5833
5875
|
}
|
|
5834
5876
|
catch (error) {
|
|
5835
5877
|
if (typeof rollback === 'function')
|
|
@@ -5898,6 +5940,31 @@ function idTokenIsGuest(idToken, expectedAddress) {
|
|
|
5898
5940
|
function storedSessionIsGuest() {
|
|
5899
5941
|
return idTokenIsGuest(getStoredIdToken());
|
|
5900
5942
|
}
|
|
5943
|
+
/** Internal: select a cross-tab restore from bearer claims, never global hints. */
|
|
5944
|
+
function storedSessionAuthMethod(config) {
|
|
5945
|
+
try {
|
|
5946
|
+
const token = getStoredIdToken();
|
|
5947
|
+
if (!token)
|
|
5948
|
+
return null;
|
|
5949
|
+
let payload = token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/');
|
|
5950
|
+
payload += '='.repeat((4 - payload.length % 4) % 4);
|
|
5951
|
+
const claims = JSON.parse(getPlatform().atob(payload));
|
|
5952
|
+
const method = claims.is_anonymous === true ? 'guest'
|
|
5953
|
+
: claims['custom:walletProvider'] === 'turnkey' || claims.email ? 'email'
|
|
5954
|
+
: claims['custom:evmWalletAddress'] ? 'evm-wallet'
|
|
5955
|
+
: claims['custom:walletAddress'] ? 'phantom' : 'email';
|
|
5956
|
+
if (config.authMethod != null && canonicalWalletAuthMethod(config.authMethod) !== method)
|
|
5957
|
+
return null;
|
|
5958
|
+
if (method === 'evm-wallet' && config.authMethod !== 'evm-wallet')
|
|
5959
|
+
return null;
|
|
5960
|
+
if (method === 'phantom' && (isWalletLoginDisabled(config) || isEmailRequired(config)))
|
|
5961
|
+
return null;
|
|
5962
|
+
return method;
|
|
5963
|
+
}
|
|
5964
|
+
catch (_a) {
|
|
5965
|
+
return null;
|
|
5966
|
+
}
|
|
5967
|
+
}
|
|
5901
5968
|
/**
|
|
5902
5969
|
* Pick the provider used for an ordinary `init({ appId })` restore.
|
|
5903
5970
|
*
|
|
@@ -6159,9 +6226,10 @@ function optionalProviderError(method) {
|
|
|
6159
6226
|
`loginWithRedirect(...) for Bounded Auth, signInAnonymously() for guests, ` +
|
|
6160
6227
|
`or install/import an explicit wallet-provider entry once your app opts into "${method}".`);
|
|
6161
6228
|
}
|
|
6162
|
-
async function getAuthProvider(config) {
|
|
6229
|
+
async function getAuthProvider(config, fromStorage = false) {
|
|
6163
6230
|
var _a;
|
|
6164
|
-
const
|
|
6231
|
+
const requestedAuthMethod = config ? (fromStorage ? storedSessionAuthMethod(config) : authMethodForInit(config)) : null;
|
|
6232
|
+
const nextProviderConfigKey = config ? authProviderConfigKey(Object.assign(Object.assign({}, config), { authMethod: requestedAuthMethod })) : null;
|
|
6165
6233
|
if (currentAuthProvider && (!config || currentAuthProviderConfigKey === nextProviderConfigKey)) {
|
|
6166
6234
|
return currentAuthProvider;
|
|
6167
6235
|
}
|
|
@@ -6176,7 +6244,8 @@ async function getAuthProvider(config) {
|
|
|
6176
6244
|
initConfig = config;
|
|
6177
6245
|
// Keep what the app actually wrote for error text; everything else runs on
|
|
6178
6246
|
// the canonical method so exactly one string reaches storage and the issuer.
|
|
6179
|
-
|
|
6247
|
+
if (!requestedAuthMethod)
|
|
6248
|
+
throw new Error('The stored session is incompatible with this app authentication configuration.');
|
|
6180
6249
|
const authMethod = canonicalWalletAuthMethod(requestedAuthMethod);
|
|
6181
6250
|
const rpcUrl = normalizeSolanaRpcUrl(config.rpcUrl);
|
|
6182
6251
|
const configuredNetwork = getConfiguredSolanaNetwork(config);
|
|
@@ -6201,7 +6270,7 @@ async function getAuthProvider(config) {
|
|
|
6201
6270
|
// manager as legacy email sessions. Human login should be started
|
|
6202
6271
|
// with loginWithRedirect(); this provider is kept as the restore and
|
|
6203
6272
|
// logout surface for those sessions.
|
|
6204
|
-
currentAuthProvider = new (await Promise.resolve().then(function () { return require('./email-auth-provider-
|
|
6273
|
+
currentAuthProvider = new (await Promise.resolve().then(function () { return require('./email-auth-provider-53sA5_i2.js'); })).EmailAuthProvider();
|
|
6205
6274
|
break;
|
|
6206
6275
|
case "phantom": {
|
|
6207
6276
|
// First-class Solana WALLET LOGIN (the poof/TaroBase-style "connect
|
|
@@ -6243,7 +6312,7 @@ async function getAuthProvider(config) {
|
|
|
6243
6312
|
// (bounded-login-widget.ts), so registration never counts as
|
|
6244
6313
|
// evidence the user has a wallet.
|
|
6245
6314
|
await ensureSolanaMobileWalletRegistered(config, configuredNetwork);
|
|
6246
|
-
const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-
|
|
6315
|
+
const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-BEYwsn6M.js'); });
|
|
6247
6316
|
currentAuthProvider = new InjectedWalletProvider(resolveInjectedWalletConfig(config), rpcUrl, configuredNetwork);
|
|
6248
6317
|
break;
|
|
6249
6318
|
}
|
|
@@ -6256,7 +6325,7 @@ async function getAuthProvider(config) {
|
|
|
6256
6325
|
// Selecting authMethod:'evm-wallet' IS the opt-in — pass evmWalletConfig
|
|
6257
6326
|
// to point at a specific wallet or set chainId/domain.
|
|
6258
6327
|
const evmWalletConfig = ((_a = config.evmWalletConfig) !== null && _a !== void 0 ? _a : {});
|
|
6259
|
-
const { InjectedEvmWalletProvider } = await Promise.resolve().then(function () { return require('./injected-evm-wallet-provider-
|
|
6328
|
+
const { InjectedEvmWalletProvider } = await Promise.resolve().then(function () { return require('./injected-evm-wallet-provider-IlkuKffc.js'); });
|
|
6260
6329
|
currentAuthProvider = new InjectedEvmWalletProvider(evmWalletConfig);
|
|
6261
6330
|
break;
|
|
6262
6331
|
}
|
|
@@ -6281,7 +6350,7 @@ async function getAuthProvider(config) {
|
|
|
6281
6350
|
break;
|
|
6282
6351
|
case "guest":
|
|
6283
6352
|
// Anonymous auth: a device-local ed25519 keypair signs the challenge.
|
|
6284
|
-
currentAuthProvider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-
|
|
6353
|
+
currentAuthProvider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-00KkSNpE.js'); })).GuestAuthProvider();
|
|
6285
6354
|
break;
|
|
6286
6355
|
}
|
|
6287
6356
|
if (!currentAuthProvider) {
|
|
@@ -6343,7 +6412,7 @@ async function signInAnonymously() {
|
|
|
6343
6412
|
// Lazy-load the guest provider so its ed25519/web3 dependencies stay out of
|
|
6344
6413
|
// the main bundle for data-only apps. Specifier is a static string literal
|
|
6345
6414
|
// so bundle-splitting can see it.
|
|
6346
|
-
const provider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-
|
|
6415
|
+
const provider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-00KkSNpE.js'); })).GuestAuthProvider();
|
|
6347
6416
|
setAuthLoading(true); // reflect "signing in…" while the guest keypair session is minted
|
|
6348
6417
|
// adoptSessionProvider awaits only getConfig() (already resolved here) and then
|
|
6349
6418
|
// runs every write - provider/method/config/marker/user - in one synchronous
|
|
@@ -6514,7 +6583,7 @@ function ensureSharedWalletLoginReady() {
|
|
|
6514
6583
|
if (!sharedWalletReady) {
|
|
6515
6584
|
sharedWalletReady = (async () => {
|
|
6516
6585
|
await core.getConfig();
|
|
6517
|
-
await Promise.resolve().then(function () { return require('./injected-wallet-provider-
|
|
6586
|
+
await Promise.resolve().then(function () { return require('./injected-wallet-provider-BEYwsn6M.js'); });
|
|
6518
6587
|
})().catch((error) => {
|
|
6519
6588
|
sharedWalletReady = null;
|
|
6520
6589
|
throw error;
|
|
@@ -6617,7 +6686,7 @@ async function loginWithWallet(options) {
|
|
|
6617
6686
|
await ensureSharedWalletLoginReady();
|
|
6618
6687
|
else
|
|
6619
6688
|
await ensureWalletLoginReady();
|
|
6620
|
-
const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-
|
|
6689
|
+
const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-BEYwsn6M.js'); });
|
|
6621
6690
|
// Keep the RAW wallet provider: the offchain wrapper forwards only a fixed
|
|
6622
6691
|
// set of methods, so cleanup below must speak to the provider that actually
|
|
6623
6692
|
// holds the config rather than to whatever is wrapping it.
|
|
@@ -6889,7 +6958,8 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
6889
6958
|
logout: logout$1,
|
|
6890
6959
|
preloadWalletLogin: preloadWalletLogin,
|
|
6891
6960
|
resolveAuthMode: resolveAuthMode,
|
|
6892
|
-
signInAnonymously: signInAnonymously
|
|
6961
|
+
signInAnonymously: signInAnonymously,
|
|
6962
|
+
storedSessionAuthMethod: storedSessionAuthMethod
|
|
6893
6963
|
});
|
|
6894
6964
|
|
|
6895
6965
|
/**
|
|
@@ -6967,12 +7037,80 @@ let isAuthLoading = false;
|
|
|
6967
7037
|
let authReadyPromise = null;
|
|
6968
7038
|
let initializingConfig = null;
|
|
6969
7039
|
let initializationGeneration = 0;
|
|
7040
|
+
let initializedConfig = null;
|
|
7041
|
+
let storageBridgeRegistered = false;
|
|
7042
|
+
let observedIdToken = null;
|
|
7043
|
+
let observedIssuer = null;
|
|
7044
|
+
// Storage events carry no authority. Re-read the active manager's app/issuer
|
|
7045
|
+
// namespace, then use the ordinary initializer/provider restore and listeners.
|
|
7046
|
+
function registerStorageBridge() {
|
|
7047
|
+
if (storageBridgeRegistered || !getPlatform().hasDOM || typeof window === 'undefined')
|
|
7048
|
+
return;
|
|
7049
|
+
storageBridgeRegistered = true;
|
|
7050
|
+
window.addEventListener('storage', (event) => {
|
|
7051
|
+
if (event.storageArea !== window.localStorage || !initializedConfig)
|
|
7052
|
+
return;
|
|
7053
|
+
void syncStoredSession().catch((error) => console.warn('Bounded session synchronization failed:', error));
|
|
7054
|
+
});
|
|
7055
|
+
}
|
|
7056
|
+
async function syncStoredSession() {
|
|
7057
|
+
const config = initializedConfig;
|
|
7058
|
+
if (!config)
|
|
7059
|
+
return;
|
|
7060
|
+
const token = core.WebSessionManager.getIdToken();
|
|
7061
|
+
const issuer = core.WebSessionManager.getIssuer();
|
|
7062
|
+
if (token === observedIdToken && issuer === observedIssuer)
|
|
7063
|
+
return;
|
|
7064
|
+
observedIdToken = token;
|
|
7065
|
+
observedIssuer = issuer;
|
|
7066
|
+
const generation = ++initializationGeneration;
|
|
7067
|
+
// Hide the former principal while the replacement is validated. This also
|
|
7068
|
+
// reconnects live reads through the existing auth-state change path.
|
|
7069
|
+
setCurrentUser(null);
|
|
7070
|
+
if (authReadyPromise)
|
|
7071
|
+
await authReadyPromise.catch(() => { });
|
|
7072
|
+
if (generation !== initializationGeneration || config !== initializedConfig)
|
|
7073
|
+
return;
|
|
7074
|
+
const record = await core.WebSessionManager.readSessionWithGeneration();
|
|
7075
|
+
if (generation !== initializationGeneration || config !== initializedConfig)
|
|
7076
|
+
return;
|
|
7077
|
+
if (!record)
|
|
7078
|
+
return;
|
|
7079
|
+
const normalize = (url) => (url || '').replace(/\/+$/, '');
|
|
7080
|
+
const resolvedConfig = await core.getConfig();
|
|
7081
|
+
if (generation !== initializationGeneration || config !== initializedConfig)
|
|
7082
|
+
return;
|
|
7083
|
+
const allowedIssuers = [normalize(resolvedConfig.humanAuthApiUrl || 'https://auth.bounded.sh'), normalize(resolvedConfig.authApiUrl)].filter(Boolean);
|
|
7084
|
+
// A legacy shared blob can belong to another app. Never restore or clear
|
|
7085
|
+
// that app's credential; the current app remains signed out.
|
|
7086
|
+
if ((record.appId && record.appId !== config.appId)
|
|
7087
|
+
|| (record.issuer && !allowedIssuers.includes(normalize(record.issuer))))
|
|
7088
|
+
return;
|
|
7089
|
+
if (!storedSessionAuthMethod(config))
|
|
7090
|
+
return;
|
|
7091
|
+
const restored = startInitialization(config, true);
|
|
7092
|
+
const restoreGeneration = initializationGeneration;
|
|
7093
|
+
try {
|
|
7094
|
+
await restored;
|
|
7095
|
+
}
|
|
7096
|
+
catch (error) {
|
|
7097
|
+
if (restoreGeneration === initializationGeneration && core.WebSessionManager.getIdToken())
|
|
7098
|
+
throw error;
|
|
7099
|
+
}
|
|
7100
|
+
}
|
|
6970
7101
|
/** Internal guard for a login result arriving after the app reconfigured the SDK. */
|
|
6971
7102
|
function getInitializationGeneration() { return initializationGeneration; }
|
|
6972
7103
|
// This file acts as a middleware for the global state of the SDK
|
|
6973
7104
|
// This mostly involves setting up the AuthProvider and managing the current user
|
|
6974
|
-
async function initialize(requestedConfig) {
|
|
7105
|
+
async function initialize(requestedConfig, fromStorage) {
|
|
6975
7106
|
const newConfig = withDefaultSolanaRpcUrl(requestedConfig);
|
|
7107
|
+
const generation = initializationGeneration;
|
|
7108
|
+
const validateStorage = fromStorage ? core.WebSessionManager.captureSessionEstablishment() : undefined;
|
|
7109
|
+
const beforeCommit = () => {
|
|
7110
|
+
if (generation !== initializationGeneration)
|
|
7111
|
+
throw new Error('Session restore was superseded.');
|
|
7112
|
+
validateStorage === null || validateStorage === void 0 ? void 0 : validateStorage();
|
|
7113
|
+
};
|
|
6976
7114
|
// Mark auth as loading for the ENTIRE init/restore window so consumers render
|
|
6977
7115
|
// a neutral/loading state instead of the signed-out UI while we rehydrate the
|
|
6978
7116
|
// session — otherwise getCurrentUser() is null + loading is false during the
|
|
@@ -6991,8 +7129,9 @@ async function initialize(requestedConfig) {
|
|
|
6991
7129
|
// onAuthStateChanged never fired, and every consumer UI went on showing a
|
|
6992
7130
|
// connected wallet for a session the server no longer knew about.
|
|
6993
7131
|
registerSessionClearedBridge();
|
|
7132
|
+
registerStorageBridge();
|
|
6994
7133
|
// Get auth provider first
|
|
6995
|
-
authProviderInstance = await getAuthProvider(newConfig);
|
|
7134
|
+
authProviderInstance = await getAuthProvider(newConfig, fromStorage);
|
|
6996
7135
|
// Initialize config with auth provider
|
|
6997
7136
|
await core.init(Object.assign(Object.assign({}, newConfig), { authProvider: authProviderInstance }));
|
|
6998
7137
|
// A return establishes its own provider/session, or hands off a popup.
|
|
@@ -7017,7 +7156,8 @@ async function initialize(requestedConfig) {
|
|
|
7017
7156
|
// Wait for restoreSession to complete
|
|
7018
7157
|
// The appId check is done in SessionManager.getSession which is called by restoreSession
|
|
7019
7158
|
// If there's an appId mismatch, the session will be cleared and restoreSession will return null
|
|
7020
|
-
let user = await authProviderInstance.restoreSession();
|
|
7159
|
+
let user = await authProviderInstance.restoreSession(beforeCommit);
|
|
7160
|
+
beforeCommit();
|
|
7021
7161
|
// If a session exists but was created before auth method tracking (legacy session),
|
|
7022
7162
|
// clear it to avoid mismatches when the app switches auth methods (e.g. email → phantom)
|
|
7023
7163
|
//
|
|
@@ -7025,9 +7165,10 @@ async function initialize(requestedConfig) {
|
|
|
7025
7165
|
// unawaited call would return a Promise (always truthy) — nulling the user
|
|
7026
7166
|
// unconditionally AND letting setCurrentUser run while the old credential
|
|
7027
7167
|
// was still in storage.
|
|
7028
|
-
if (user && await clearIncompatibleSession()) {
|
|
7168
|
+
if (user && !fromStorage && await clearIncompatibleSession()) {
|
|
7029
7169
|
user = null;
|
|
7030
7170
|
}
|
|
7171
|
+
beforeCommit();
|
|
7031
7172
|
setCurrentUser(user);
|
|
7032
7173
|
// Mark init as completed
|
|
7033
7174
|
initCompleted = true;
|
|
@@ -7067,13 +7208,17 @@ function sameConfigValue(a, b, seen = new WeakMap()) {
|
|
|
7067
7208
|
&& sameConfigValue(a[key], b[key], seen));
|
|
7068
7209
|
}
|
|
7069
7210
|
function init$1(newConfig) {
|
|
7211
|
+
return startInitialization(newConfig, false);
|
|
7212
|
+
}
|
|
7213
|
+
function startInitialization(newConfig, fromStorage) {
|
|
7070
7214
|
if (initializingConfig) {
|
|
7071
7215
|
if (sameConfigValue(initializingConfig, newConfig)) {
|
|
7072
7216
|
return authReadyPromise;
|
|
7073
7217
|
}
|
|
7074
7218
|
return Promise.reject(new Error('SDK initialization is in progress. Await init() before changing its configuration.'));
|
|
7075
7219
|
}
|
|
7076
|
-
|
|
7220
|
+
initializedConfig = Object.assign({}, newConfig);
|
|
7221
|
+
initializingConfig = initializedConfig;
|
|
7077
7222
|
initializationGeneration++;
|
|
7078
7223
|
let resolveReady;
|
|
7079
7224
|
let rejectReady;
|
|
@@ -7085,7 +7230,7 @@ function init$1(newConfig) {
|
|
|
7085
7230
|
// auth-loading listener to call waitForAuthReady() synchronously when init()
|
|
7086
7231
|
// announces that session restoration has begun.
|
|
7087
7232
|
authReadyPromise = ready;
|
|
7088
|
-
void initialize(initializingConfig).then(() => { initializingConfig = null; resolveReady(); }, (error) => { initializingConfig = null; rejectReady(error); });
|
|
7233
|
+
void initialize(initializingConfig, fromStorage).then(() => { initializingConfig = null; resolveReady(); }, (error) => { initializingConfig = null; rejectReady(error); });
|
|
7089
7234
|
return ready;
|
|
7090
7235
|
}
|
|
7091
7236
|
/**
|
|
@@ -7158,6 +7303,13 @@ function userPrincipalKey(user) {
|
|
|
7158
7303
|
}
|
|
7159
7304
|
// Update the currentUser and notify listeners
|
|
7160
7305
|
function setCurrentUser(user) {
|
|
7306
|
+
observedIdToken = getCurrentIdToken();
|
|
7307
|
+
try {
|
|
7308
|
+
observedIssuer = core.getActiveSessionManager().getIssuer();
|
|
7309
|
+
}
|
|
7310
|
+
catch (_a) {
|
|
7311
|
+
observedIssuer = null;
|
|
7312
|
+
}
|
|
7161
7313
|
// Enrich with the universal identity fields (id/email) derived from the
|
|
7162
7314
|
// active session's idToken — central chokepoint so every provider's user
|
|
7163
7315
|
// object gains { id, address, email } without each construction site
|
|
@@ -7703,10 +7855,18 @@ async function startTurnkeyEmailLogin(email) {
|
|
|
7703
7855
|
if (!hasDOM$1()) {
|
|
7704
7856
|
throw new Error('Turnkey-native email login is web-only - on React Native use loginWithRedirect()');
|
|
7705
7857
|
}
|
|
7858
|
+
const generation = getInitializationGeneration();
|
|
7859
|
+
const walletGuard = walletOperationGuard();
|
|
7860
|
+
const assertContext = () => {
|
|
7861
|
+
walletGuard();
|
|
7862
|
+
if (generation !== getInitializationGeneration())
|
|
7863
|
+
throw new Error('Login was superseded by SDK reinitialization. Start sign-in again.');
|
|
7864
|
+
};
|
|
7706
7865
|
const trimmed = email.trim();
|
|
7707
7866
|
if (!trimmed)
|
|
7708
7867
|
throw new Error('Enter your email to continue.');
|
|
7709
7868
|
const { base, appId } = await inlineAuthEndpoint();
|
|
7869
|
+
assertContext();
|
|
7710
7870
|
if (!appId)
|
|
7711
7871
|
throw new Error('appId is not configured (init the SDK with your appId)');
|
|
7712
7872
|
const res = await fetch(`${base}/wallet/turnkey/auth/init`, {
|
|
@@ -7718,6 +7878,7 @@ async function startTurnkeyEmailLogin(email) {
|
|
|
7718
7878
|
if (!res.ok || !data || typeof data.otpId !== 'string' || typeof data.otpEncryptionTargetBundle !== 'string') {
|
|
7719
7879
|
throw new Error(String((data && data.error) || 'Could not send a code. Please try again.'));
|
|
7720
7880
|
}
|
|
7881
|
+
assertContext();
|
|
7721
7882
|
const otpId = data.otpId;
|
|
7722
7883
|
const otpEncryptionTargetBundle = data.otpEncryptionTargetBundle;
|
|
7723
7884
|
// A tenant-origin login always gets a ceremony id; without one the OTP frame refuses to run
|
|
@@ -7733,14 +7894,20 @@ async function startTurnkeyEmailLogin(email) {
|
|
|
7733
7894
|
: undefined;
|
|
7734
7895
|
return {
|
|
7735
7896
|
email: trimmed, frameUrl, signerOrigin,
|
|
7736
|
-
run(iframe,
|
|
7897
|
+
run(iframe, signal) {
|
|
7898
|
+
try {
|
|
7899
|
+
assertContext();
|
|
7900
|
+
}
|
|
7901
|
+
catch (error) {
|
|
7902
|
+
return Promise.reject(error);
|
|
7903
|
+
}
|
|
7737
7904
|
if (!ceremonyId) {
|
|
7738
7905
|
return Promise.reject(new Error('This app is not configured for in-frame wallet login. Please try again.'));
|
|
7739
7906
|
}
|
|
7740
|
-
const run = { iframe, base, signerOrigin, appId, email: trimmed, otpId, otpEncryptionTargetBundle, ceremonyId };
|
|
7907
|
+
const run = { iframe, base, signerOrigin, appId, email: trimmed, otpId, otpEncryptionTargetBundle, ceremonyId, generation };
|
|
7741
7908
|
// BSA-2026-004: the login code is typed only in /wallet/turnkey/otp-frame.
|
|
7742
7909
|
// The scoped signer URL is for post-login signing, not OTP entry.
|
|
7743
|
-
return runOtpFrame(run);
|
|
7910
|
+
return runOtpFrame(run, signal);
|
|
7744
7911
|
},
|
|
7745
7912
|
};
|
|
7746
7913
|
}
|
|
@@ -7749,7 +7916,7 @@ async function startTurnkeyEmailLogin(email) {
|
|
|
7749
7916
|
// frame 'result' {session} -> we establish the inline session and resolve the User.
|
|
7750
7917
|
// When the frame asks for the signing-session authorization ('need-authorization') we mint a
|
|
7751
7918
|
// createWallet action authorization on THIS (registered) origin and post it in - never a key.
|
|
7752
|
-
function runOtpFrame(run) {
|
|
7919
|
+
function runOtpFrame(run, signal) {
|
|
7753
7920
|
const tenantOrigin = window.location.origin;
|
|
7754
7921
|
const url = `${run.base.replace(/\/$/, '')}/wallet/turnkey/otp-frame`
|
|
7755
7922
|
+ `?appId=${encodeURIComponent(run.appId)}`
|
|
@@ -7759,13 +7926,48 @@ function runOtpFrame(run) {
|
|
|
7759
7926
|
return new Promise((resolve, reject) => {
|
|
7760
7927
|
let settled = false;
|
|
7761
7928
|
let started = false;
|
|
7762
|
-
|
|
7929
|
+
let receivingResult = false;
|
|
7930
|
+
let committing = false;
|
|
7931
|
+
const walletGuard = walletLoginGuard(signal);
|
|
7932
|
+
const beforeCommit = () => {
|
|
7933
|
+
if (settled)
|
|
7934
|
+
throw new Error('wallet_login_cancelled');
|
|
7935
|
+
walletGuard();
|
|
7936
|
+
if (run.generation !== getInitializationGeneration())
|
|
7937
|
+
throw new Error('Login was superseded by SDK reinitialization. Start sign-in again.');
|
|
7938
|
+
};
|
|
7939
|
+
const finish = (error, user) => {
|
|
7940
|
+
if (settled)
|
|
7941
|
+
return;
|
|
7942
|
+
settled = true;
|
|
7943
|
+
window.removeEventListener('message', onMsg);
|
|
7944
|
+
window.clearTimeout(timer);
|
|
7945
|
+
signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', onAbort);
|
|
7946
|
+
if (error) {
|
|
7947
|
+
// Destroy the expired frame's code/key realm as well as its parent listener.
|
|
7948
|
+
run.iframe.src = 'about:blank';
|
|
7949
|
+
reject(error);
|
|
7950
|
+
}
|
|
7951
|
+
else
|
|
7952
|
+
resolve(user);
|
|
7953
|
+
};
|
|
7954
|
+
const onAbort = () => { if (!committing)
|
|
7955
|
+
finish(new Error('cancelled')); };
|
|
7763
7956
|
const onMsg = async (event) => {
|
|
7764
7957
|
if (settled)
|
|
7765
7958
|
return;
|
|
7766
7959
|
// Trust ONLY the signer origin and the frame's own window.
|
|
7767
7960
|
if (event.origin !== run.signerOrigin || event.source !== run.iframe.contentWindow)
|
|
7768
7961
|
return;
|
|
7962
|
+
if (!committing) {
|
|
7963
|
+
try {
|
|
7964
|
+
beforeCommit();
|
|
7965
|
+
}
|
|
7966
|
+
catch (error) {
|
|
7967
|
+
finish(error instanceof Error ? error : new Error(String(error)));
|
|
7968
|
+
return;
|
|
7969
|
+
}
|
|
7970
|
+
}
|
|
7769
7971
|
const d = event.data;
|
|
7770
7972
|
if (!d || typeof d !== 'object')
|
|
7771
7973
|
return;
|
|
@@ -7808,40 +8010,56 @@ function runOtpFrame(run) {
|
|
|
7808
8010
|
return;
|
|
7809
8011
|
}
|
|
7810
8012
|
if (d.type === 'bounded:otp:result') {
|
|
8013
|
+
if (receivingResult)
|
|
8014
|
+
return;
|
|
8015
|
+
receivingResult = true;
|
|
7811
8016
|
if (d.ok && d.session && typeof d.session === 'object') {
|
|
7812
8017
|
try {
|
|
7813
|
-
const user = await establishInlineSession(d.session);
|
|
7814
|
-
|
|
7815
|
-
resolve(user);
|
|
8018
|
+
const user = await establishInlineSession(d.session, beforeCommit, undefined, () => { committing = true; });
|
|
8019
|
+
finish(undefined, user);
|
|
7816
8020
|
}
|
|
7817
8021
|
catch (error) {
|
|
7818
|
-
|
|
7819
|
-
reject(error instanceof Error ? error : new Error(String(error)));
|
|
8022
|
+
finish(error instanceof Error ? error : new Error(String(error)));
|
|
7820
8023
|
}
|
|
7821
8024
|
return;
|
|
7822
8025
|
}
|
|
7823
|
-
|
|
7824
|
-
reject(new Error(String((d && d.error) || 'Invalid or expired code.')));
|
|
8026
|
+
finish(new Error(String((d && d.error) || 'Invalid or expired code.')));
|
|
7825
8027
|
return;
|
|
7826
8028
|
}
|
|
7827
8029
|
// 'bounded:otp:registered' is advisory; login does not depend on it.
|
|
7828
8030
|
};
|
|
7829
8031
|
const post = (msg) => {
|
|
7830
8032
|
var _a;
|
|
8033
|
+
if (settled)
|
|
8034
|
+
return;
|
|
8035
|
+
if (!committing) {
|
|
8036
|
+
try {
|
|
8037
|
+
beforeCommit();
|
|
8038
|
+
}
|
|
8039
|
+
catch (_b) {
|
|
8040
|
+
return;
|
|
8041
|
+
}
|
|
8042
|
+
}
|
|
7831
8043
|
try {
|
|
7832
8044
|
(_a = run.iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage(msg, run.signerOrigin);
|
|
7833
8045
|
}
|
|
7834
|
-
catch ( /* frame gone */
|
|
8046
|
+
catch ( /* frame gone */_c) { /* frame gone */ }
|
|
7835
8047
|
};
|
|
7836
8048
|
window.addEventListener('message', onMsg);
|
|
7837
8049
|
// 3 minutes: the human must read the email and type the code. A frame that never reports is a
|
|
7838
8050
|
// failed login the user can retry.
|
|
7839
8051
|
const timer = window.setTimeout(() => {
|
|
7840
|
-
if (
|
|
7841
|
-
|
|
7842
|
-
cleanup();
|
|
7843
|
-
reject(new Error('The sign-in code entry timed out. Please try again.'));
|
|
8052
|
+
if (!committing)
|
|
8053
|
+
finish(new Error('The sign-in code entry timed out. Please try again.'));
|
|
7844
8054
|
}, 3 * 60 * 1000);
|
|
8055
|
+
signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', onAbort, { once: true });
|
|
8056
|
+
try {
|
|
8057
|
+
beforeCommit();
|
|
8058
|
+
}
|
|
8059
|
+
catch (error) {
|
|
8060
|
+
finish(error instanceof Error ? error : new Error(String(error)));
|
|
8061
|
+
return;
|
|
8062
|
+
}
|
|
7845
8063
|
run.iframe.src = url;
|
|
7846
8064
|
});
|
|
7847
8065
|
}
|
|
@@ -8105,7 +8323,8 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8105
8323
|
return authApi.loginWithRedirect(options);
|
|
8106
8324
|
// Invoke immediately inside the click handler to retain popup activation.
|
|
8107
8325
|
return authApi.loginWithPopup(options).catch((error) => {
|
|
8108
|
-
|
|
8326
|
+
var _a;
|
|
8327
|
+
if (!((_a = options.signal) === null || _a === void 0 ? void 0 : _a.aborted) && shouldFallbackToRedirect(error))
|
|
8109
8328
|
return authApi.loginWithRedirect(options);
|
|
8110
8329
|
throw error;
|
|
8111
8330
|
});
|
|
@@ -8243,6 +8462,12 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8243
8462
|
let activeAttempt = 0;
|
|
8244
8463
|
let abortScopedLogin = null;
|
|
8245
8464
|
let abortGesture = null;
|
|
8465
|
+
const startHostedLogin = (options) => {
|
|
8466
|
+
const controller = new AbortController();
|
|
8467
|
+
const abort = () => controller.abort();
|
|
8468
|
+
abortScopedLogin = abort;
|
|
8469
|
+
return hostedLogin(Object.assign(Object.assign({}, options), { signal: controller.signal }));
|
|
8470
|
+
};
|
|
8246
8471
|
/** Reject a gesture promise already waiting on a view that is going away. */
|
|
8247
8472
|
const abortPendingGesture = () => {
|
|
8248
8473
|
const abort = abortGesture;
|
|
@@ -8268,6 +8493,7 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8268
8493
|
if (!attemptIsCurrent(id))
|
|
8269
8494
|
return false;
|
|
8270
8495
|
activeAttempt = 0;
|
|
8496
|
+
abortScopedLogin = null;
|
|
8271
8497
|
return true;
|
|
8272
8498
|
};
|
|
8273
8499
|
/** Take the card back (Back, a lane switch, settling the modal). Deliberately
|
|
@@ -8422,7 +8648,7 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8422
8648
|
loginHint: input.value,
|
|
8423
8649
|
redirectUri: opts.redirectUri,
|
|
8424
8650
|
};
|
|
8425
|
-
|
|
8651
|
+
startHostedLogin(emailOpts)
|
|
8426
8652
|
// A hosted login that RESOLVES minted a real session, so it settles
|
|
8427
8653
|
// the card even if another lane has since taken it - dropping it
|
|
8428
8654
|
// would leave the app signed in behind a widget that says it is not.
|
|
@@ -8472,7 +8698,7 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8472
8698
|
}
|
|
8473
8699
|
setBusy(b, "Opening secure sign-in\u2026");
|
|
8474
8700
|
const socialOpts = { provider: method, redirectUri: opts.redirectUri };
|
|
8475
|
-
|
|
8701
|
+
startHostedLogin(socialOpts)
|
|
8476
8702
|
.then((u) => {
|
|
8477
8703
|
if (u) {
|
|
8478
8704
|
settleAttempt(attempt);
|
|
@@ -8722,14 +8948,16 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8722
8948
|
setErr(BUSY_MSG);
|
|
8723
8949
|
return card;
|
|
8724
8950
|
}
|
|
8725
|
-
back.addEventListener("click", () => {
|
|
8951
|
+
back.addEventListener("click", () => { invalidateAttempts(); swap(renderChoose()); });
|
|
8952
|
+
const controller = new AbortController();
|
|
8953
|
+
abortScopedLogin = () => controller.abort();
|
|
8726
8954
|
handle
|
|
8727
|
-
.run(frame)
|
|
8955
|
+
.run(frame, controller.signal)
|
|
8728
8956
|
.then((u) => { settleAttempt(attempt); succeed(u); })
|
|
8729
8957
|
.catch((err) => {
|
|
8730
8958
|
if (!settleAttempt(attempt))
|
|
8731
8959
|
return;
|
|
8732
|
-
|
|
8960
|
+
swap(renderChoose(errText(err)));
|
|
8733
8961
|
});
|
|
8734
8962
|
return card;
|
|
8735
8963
|
};
|
|
@@ -10544,8 +10772,9 @@ class PrivyExpoProvider {
|
|
|
10544
10772
|
const { signature } = await this.signAndSubmitInternal(transaction, wallet, connection);
|
|
10545
10773
|
return signature;
|
|
10546
10774
|
}
|
|
10547
|
-
async restoreSession() {
|
|
10775
|
+
async restoreSession(beforeCommit) {
|
|
10548
10776
|
const session = await core.getActiveSessionManager().getSession();
|
|
10777
|
+
beforeCommit === null || beforeCommit === void 0 ? void 0 : beforeCommit();
|
|
10549
10778
|
if (session) {
|
|
10550
10779
|
this.authenticatedAddress = session.address;
|
|
10551
10780
|
return { provider: this, address: session.address };
|
|
@@ -11130,4 +11359,4 @@ exports.useAuth = useAuth;
|
|
|
11130
11359
|
exports.useBuildRun = useBuildRun;
|
|
11131
11360
|
exports.useQuery = useQuery;
|
|
11132
11361
|
exports.waitForAuthReady = waitForAuthReady;
|
|
11133
|
-
//# sourceMappingURL=index-
|
|
11362
|
+
//# sourceMappingURL=index-DJeEMevo.js.map
|