@bounded-sh/client 0.0.112-ux-audit.1 → 0.0.112
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/bounded-widget-modal.d.ts +24 -2
- package/dist/auth/oidc-auth.d.ts +1 -1
- package/dist/{email-auth-provider-eyi3Wpnx.mjs → email-auth-provider-BV1Iea4A.mjs} +2 -2
- package/dist/{email-auth-provider-BfCH7K6N.mjs.map → email-auth-provider-BV1Iea4A.mjs.map} +1 -1
- package/dist/{email-auth-provider-CG5cxOj0.js → email-auth-provider-CyFsnSzx.js} +2 -2
- package/dist/{email-auth-provider-CG5cxOj0.js.map → email-auth-provider-CyFsnSzx.js.map} +1 -1
- package/dist/{email-auth-provider-BfCH7K6N.mjs → email-auth-provider-D0_iXVYk.mjs} +2 -2
- package/dist/{email-auth-provider-eyi3Wpnx.mjs.map → email-auth-provider-D0_iXVYk.mjs.map} +1 -1
- package/dist/{email-auth-provider-DTrCfOJd.js → email-auth-provider-OVzQ63dn.js} +2 -2
- package/dist/{email-auth-provider-DTrCfOJd.js.map → email-auth-provider-OVzQ63dn.js.map} +1 -1
- package/dist/{guest-auth-provider-Tndt6tzJ.js → guest-auth-provider-0WlOutqU.js} +2 -2
- package/dist/{guest-auth-provider-Tndt6tzJ.js.map → guest-auth-provider-0WlOutqU.js.map} +1 -1
- package/dist/{guest-auth-provider-DjOFjtnk.mjs → guest-auth-provider-AP80a700.mjs} +2 -2
- package/dist/{guest-auth-provider-BsW56oJg.mjs.map → guest-auth-provider-AP80a700.mjs.map} +1 -1
- package/dist/{guest-auth-provider-Dtl1J-2F.js → guest-auth-provider-B4WIWOjV.js} +2 -2
- package/dist/{guest-auth-provider-Dtl1J-2F.js.map → guest-auth-provider-B4WIWOjV.js.map} +1 -1
- package/dist/{guest-auth-provider-BsW56oJg.mjs → guest-auth-provider-Cqx1zH23.mjs} +2 -2
- package/dist/{guest-auth-provider-DjOFjtnk.mjs.map → guest-auth-provider-Cqx1zH23.mjs.map} +1 -1
- package/dist/{index-Brdwqgqs.js → index-BmNNZlTl.js} +226 -67
- package/dist/index-BmNNZlTl.js.map +1 -0
- package/dist/{index-CRxls8Qc.mjs → index-D76-cZcD.mjs} +226 -67
- package/dist/index-D76-cZcD.mjs.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{index.native-ingNhWPw.js → index.native-C5glqiTU.js} +59 -14
- package/dist/index.native-C5glqiTU.js.map +1 -0
- package/dist/{index.native-CAH_ks0s.mjs → index.native-DyR93n8K.mjs} +59 -14
- package/dist/index.native-DyR93n8K.mjs.map +1 -0
- package/dist/index.native.js +1 -1
- package/dist/index.native.mjs +1 -1
- package/dist/{injected-evm-wallet-provider-Cao1U0NZ.js → injected-evm-wallet-provider-4ICYUEU4.js} +2 -2
- package/dist/{injected-evm-wallet-provider-Cao1U0NZ.js.map → injected-evm-wallet-provider-4ICYUEU4.js.map} +1 -1
- package/dist/{injected-evm-wallet-provider-CwOGXCDt.js → injected-evm-wallet-provider-C8YItSiB.js} +2 -2
- package/dist/{injected-evm-wallet-provider-CwOGXCDt.js.map → injected-evm-wallet-provider-C8YItSiB.js.map} +1 -1
- package/dist/{injected-evm-wallet-provider-DXjwPjLW.mjs → injected-evm-wallet-provider-CS4R8c51.mjs} +2 -2
- package/dist/{injected-evm-wallet-provider-DXjwPjLW.mjs.map → injected-evm-wallet-provider-CS4R8c51.mjs.map} +1 -1
- package/dist/{injected-evm-wallet-provider-BjkCeRBL.mjs → injected-evm-wallet-provider-WxUbyMZL.mjs} +2 -2
- package/dist/{injected-evm-wallet-provider-BjkCeRBL.mjs.map → injected-evm-wallet-provider-WxUbyMZL.mjs.map} +1 -1
- package/dist/{injected-wallet-provider-CfYNIIHd.mjs → injected-wallet-provider-D1ygndjX.mjs} +2 -2
- package/dist/{injected-wallet-provider-CfYNIIHd.mjs.map → injected-wallet-provider-D1ygndjX.mjs.map} +1 -1
- package/dist/{injected-wallet-provider-LTnqoaYD.js → injected-wallet-provider-D8vIsUHf.js} +2 -2
- package/dist/{injected-wallet-provider-LTnqoaYD.js.map → injected-wallet-provider-D8vIsUHf.js.map} +1 -1
- package/dist/{injected-wallet-provider-BG6gGNch.mjs → injected-wallet-provider-UuGrzdNW.mjs} +2 -2
- package/dist/{injected-wallet-provider-BG6gGNch.mjs.map → injected-wallet-provider-UuGrzdNW.mjs.map} +1 -1
- package/dist/{injected-wallet-provider-DSlHfgMU.js → injected-wallet-provider-nwd3ialR.js} +2 -2
- package/dist/{injected-wallet-provider-DSlHfgMU.js.map → injected-wallet-provider-nwd3ialR.js.map} +1 -1
- package/package.json +2 -2
- package/dist/index-Brdwqgqs.js.map +0 -1
- package/dist/index-CRxls8Qc.mjs.map +0 -1
- package/dist/index.native-CAH_ks0s.mjs.map +0 -1
- package/dist/index.native-ingNhWPw.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 }; }
|
|
@@ -3890,9 +3897,13 @@ async function ensureSolanaMobileWalletRegistered(config, network) {
|
|
|
3890
3897
|
}
|
|
3891
3898
|
catch (_e) {
|
|
3892
3899
|
throw new WalletConfigError(`Bounded: Solana Mobile wallet support needs the optional peer dependency ` +
|
|
3893
|
-
`'@solana-mobile/wallet-standard-mobile', which is not installed.
|
|
3894
|
-
`
|
|
3895
|
-
`
|
|
3900
|
+
`'@solana-mobile/wallet-standard-mobile', which is not installed. Until it is, ` +
|
|
3901
|
+
`Android users (Seeker, Saga, any phone browser) get NO wallet to connect: ` +
|
|
3902
|
+
`installed wallet apps are never injected into a page there, the mobile adapter ` +
|
|
3903
|
+
`is the only route. Fix: npm install @solana-mobile/wallet-standard-mobile ` +
|
|
3904
|
+
`(a web app also needs legacy-peer-deps=true in its .npmrc, because the adapter's ` +
|
|
3905
|
+
`protocol package declares react-native as a peer). Or leave the Solana Mobile ` +
|
|
3906
|
+
`wallet out of this app's wallet configuration on purpose.`);
|
|
3896
3907
|
}
|
|
3897
3908
|
const { registerMwa, createDefaultChainSelector, SolanaMobileWalletAdapterWalletName, SolanaMobileWalletAdapterRemoteWalletName, } = mwa;
|
|
3898
3909
|
const before = new Set(getWallets().get());
|
|
@@ -3979,7 +3990,7 @@ const OVERLAY_CSS = `
|
|
|
3979
3990
|
:host{all:initial}
|
|
3980
3991
|
*{box-sizing:border-box}
|
|
3981
3992
|
.bw-ov{position:fixed;inset:0;z-index:2147483647;display:none;
|
|
3982
|
-
font-family:"Schibsted Grotesk","Helvetica Neue",Arial,sans-serif}
|
|
3993
|
+
font-family:"Bounded Schibsted Grotesk","Schibsted Grotesk","Helvetica Neue",Arial,sans-serif}
|
|
3983
3994
|
.bw-ov.mounted{display:block}
|
|
3984
3995
|
.bw-back{position:fixed;inset:0;background:rgba(4,4,5,.62);opacity:0;
|
|
3985
3996
|
transition:opacity .24s ease;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px)}
|
|
@@ -4012,6 +4023,29 @@ const OVERLAY_CSS = `
|
|
|
4012
4023
|
}
|
|
4013
4024
|
@media(prefers-reduced-motion:reduce){.bw-back,.bw-panel{transition:opacity .12s linear!important}}
|
|
4014
4025
|
`;
|
|
4026
|
+
/**
|
|
4027
|
+
* Style the shadow tree with `css` as constructed stylesheets, and say whether it could. A host
|
|
4028
|
+
* CSP whose style-src lacks 'unsafe-inline' refuses an inline <style> even inside a shadow root,
|
|
4029
|
+
* which left the widget unstyled (the Bounded router compiles exactly `style-src 'self'` for an
|
|
4030
|
+
* app that declares browser boundaries and names no style sources); CSP does not govern
|
|
4031
|
+
* constructed sheets. A browser without them (they shipped with adoptedStyleSheets everywhere)
|
|
4032
|
+
* gets <style> elements instead (styleTag).
|
|
4033
|
+
*/
|
|
4034
|
+
function adoptStyles(shadow, css) {
|
|
4035
|
+
if (!("adoptedStyleSheets" in shadow))
|
|
4036
|
+
return false;
|
|
4037
|
+
shadow.adoptedStyleSheets = css.map((text) => {
|
|
4038
|
+
const sheet = new CSSStyleSheet();
|
|
4039
|
+
sheet.replaceSync(text);
|
|
4040
|
+
return sheet;
|
|
4041
|
+
});
|
|
4042
|
+
return true;
|
|
4043
|
+
}
|
|
4044
|
+
function styleTag(css) {
|
|
4045
|
+
const style = document.createElement("style");
|
|
4046
|
+
style.textContent = css;
|
|
4047
|
+
return style;
|
|
4048
|
+
}
|
|
4015
4049
|
let modal = null;
|
|
4016
4050
|
function getModal() {
|
|
4017
4051
|
if (modal)
|
|
@@ -4019,9 +4053,8 @@ function getModal() {
|
|
|
4019
4053
|
const root = document.createElement("div");
|
|
4020
4054
|
root.setAttribute("data-bounded-widget", "");
|
|
4021
4055
|
const shadow = root.attachShadow({ mode: "open" });
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
shadow.appendChild(style);
|
|
4056
|
+
if (!adoptStyles(shadow, [OVERLAY_CSS]))
|
|
4057
|
+
shadow.appendChild(styleTag(OVERLAY_CSS));
|
|
4025
4058
|
const overlay = document.createElement("div");
|
|
4026
4059
|
overlay.className = "bw-ov";
|
|
4027
4060
|
const back = document.createElement("div");
|
|
@@ -4156,12 +4189,15 @@ function fitPanelToContent(m) {
|
|
|
4156
4189
|
m.fitObserver = ro;
|
|
4157
4190
|
}
|
|
4158
4191
|
}
|
|
4159
|
-
/** Switch the modal into NATIVE-content mode: detach any iframe, mount `node
|
|
4160
|
-
function mountContent(m, node) {
|
|
4192
|
+
/** Switch the modal into NATIVE-content mode: detach any iframe, mount `node`, styled by `css` until the next mount. */
|
|
4193
|
+
function mountContent(m, node, css) {
|
|
4161
4194
|
var _a;
|
|
4162
4195
|
detachIframe(m);
|
|
4163
4196
|
(_a = m.fitObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
4164
4197
|
m.fitObserver = null;
|
|
4198
|
+
const shadow = m.root.shadowRoot;
|
|
4199
|
+
if (!(shadow && adoptStyles(shadow, [OVERLAY_CSS, css] )) && css)
|
|
4200
|
+
node.prepend(styleTag(css));
|
|
4165
4201
|
m.content.replaceChildren(node);
|
|
4166
4202
|
m.content.style.display = "block";
|
|
4167
4203
|
}
|
|
@@ -4223,27 +4259,39 @@ function detachIframe(m) {
|
|
|
4223
4259
|
m.iframeContext = "";
|
|
4224
4260
|
m.onIframeMessage = null;
|
|
4225
4261
|
}
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4262
|
+
/**
|
|
4263
|
+
* The Bounded editorial typefaces the hosted auth page uses (Newsreader display, Schibsted
|
|
4264
|
+
* Grotesk body), registered once at the document level so they apply inside the shadow root.
|
|
4265
|
+
*
|
|
4266
|
+
* The Bounded router serves them same-origin at /__bounded/fonts/*.woff2 on every site it
|
|
4267
|
+
* serves (bounded-router scripts/build-widget-styles.cjs), and they load through the FontFace
|
|
4268
|
+
* API: no stylesheet, so a host CSP's style-src never applies, and the only fetch is same-origin,
|
|
4269
|
+
* which font-src 'self' admits. Google Fonts CSS injected here was refused by strict hosts such
|
|
4270
|
+
* as the OpenApps venue (style-src 'self'), with a CSP error on every page. A page the router
|
|
4271
|
+
* does not serve has none of its /__bounded/ scripts: nothing is fetched there, and the widget's
|
|
4272
|
+
* font stacks fall back to the page's own faces or system ones. The Bounded-prefixed family
|
|
4273
|
+
* names never restyle the host page's own text.
|
|
4274
|
+
*/
|
|
4275
|
+
const WIDGET_FONT_FACES = [
|
|
4276
|
+
{ family: "Bounded Newsreader", url: "/__bounded/fonts/newsreader.woff2", weight: "200 800" },
|
|
4277
|
+
{ family: "Bounded Schibsted Grotesk", url: "/__bounded/fonts/schibsted.woff2", weight: "400 900" },
|
|
4278
|
+
];
|
|
4230
4279
|
function ensureFonts() {
|
|
4231
|
-
if (!hasDOM$5())
|
|
4280
|
+
if (!hasDOM$5() || typeof FontFace === "undefined" || !document.fonts)
|
|
4232
4281
|
return;
|
|
4233
|
-
if (document.querySelector('
|
|
4282
|
+
if (!document.querySelector('script[src^="/__bounded/"]'))
|
|
4234
4283
|
return;
|
|
4235
|
-
const
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
document.head.append(pre1, pre2, link);
|
|
4284
|
+
const registered = new Set();
|
|
4285
|
+
document.fonts.forEach((face) => registered.add(face.family.replace(/^["']|["']$/g, "")));
|
|
4286
|
+
for (const { family, url, weight } of WIDGET_FONT_FACES) {
|
|
4287
|
+
if (registered.has(family))
|
|
4288
|
+
continue;
|
|
4289
|
+
// Against the page's origin, not its base URL: a <base href> elsewhere must not move the fetch off this origin.
|
|
4290
|
+
const face = new FontFace(family, `url("${location.origin}${url}") format("woff2")`, { weight, display: "swap" });
|
|
4291
|
+
document.fonts.add(face);
|
|
4292
|
+
// A face that cannot load is taken back out; the font stack falls back to the next face.
|
|
4293
|
+
face.load().catch(() => { document.fonts.delete(face); });
|
|
4294
|
+
}
|
|
4247
4295
|
}
|
|
4248
4296
|
|
|
4249
4297
|
// turnkey-wallet-widget.ts - runs one Turnkey signer exchange inside the shared
|
|
@@ -5781,20 +5829,21 @@ async function loginWithPopup(opts) {
|
|
|
5781
5829
|
// Turnkey-native login path (authMode:"turnkey"), which mints the session server-side
|
|
5782
5830
|
// after Turnkey verifies the email OTP - there is no OIDC code to exchange. Wiring is
|
|
5783
5831
|
// identical to exchangeCode's tail so the realtime worker cannot tell them apart.
|
|
5784
|
-
async function establishInlineSession(data, beforeCommit, beforeStore) {
|
|
5832
|
+
async function establishInlineSession(data, beforeCommit, beforeStore, onCommitting) {
|
|
5785
5833
|
const base = await issuerBase();
|
|
5834
|
+
beforeCommit === null || beforeCommit === void 0 ? void 0 : beforeCommit();
|
|
5786
5835
|
const idToken = tokenField(data, 'id_token', 'idToken');
|
|
5787
5836
|
if (!idToken)
|
|
5788
5837
|
throw new Error('No id_token in the inline session response');
|
|
5789
5838
|
const accessToken = tokenField(data, 'access_token', 'accessToken') || idToken;
|
|
5790
5839
|
const refreshToken = boundedRefreshTokenField(data);
|
|
5791
5840
|
const user = userFromIdToken(idToken);
|
|
5792
|
-
const rollback = await sessionManager().storeSession(String(user.address || ''), accessToken, idToken, refreshToken, base, () => { });
|
|
5841
|
+
const rollback = await sessionManager().storeSession(String(user.address || ''), accessToken, idToken, refreshToken, base, () => { beforeCommit === null || beforeCommit === void 0 ? void 0 : beforeCommit(); });
|
|
5793
5842
|
// Adopt the OIDC provider on EVERY session surface - including core's signing
|
|
5794
5843
|
// pointer (getConfig().authProvider), which this path used to skip, leaving
|
|
5795
5844
|
// onchain writes routed through a previous (e.g. logged-out wallet) provider.
|
|
5796
5845
|
try {
|
|
5797
|
-
await adoptSessionProvider({ provider: oidcProviderSingleton, method: 'email', configKey: 'direct:oidc', user, beforeCommit });
|
|
5846
|
+
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(); } });
|
|
5798
5847
|
}
|
|
5799
5848
|
catch (error) {
|
|
5800
5849
|
if (typeof rollback === 'function')
|
|
@@ -6262,7 +6311,7 @@ async function getAuthProvider(config, fromStorage = false) {
|
|
|
6262
6311
|
// manager as legacy email sessions. Human login should be started
|
|
6263
6312
|
// with loginWithRedirect(); this provider is kept as the restore and
|
|
6264
6313
|
// logout surface for those sessions.
|
|
6265
|
-
currentAuthProvider = new (await Promise.resolve().then(function () { return require('./email-auth-provider-
|
|
6314
|
+
currentAuthProvider = new (await Promise.resolve().then(function () { return require('./email-auth-provider-CyFsnSzx.js'); })).EmailAuthProvider();
|
|
6266
6315
|
break;
|
|
6267
6316
|
case "phantom": {
|
|
6268
6317
|
// First-class Solana WALLET LOGIN (the poof/TaroBase-style "connect
|
|
@@ -6304,7 +6353,7 @@ async function getAuthProvider(config, fromStorage = false) {
|
|
|
6304
6353
|
// (bounded-login-widget.ts), so registration never counts as
|
|
6305
6354
|
// evidence the user has a wallet.
|
|
6306
6355
|
await ensureSolanaMobileWalletRegistered(config, configuredNetwork);
|
|
6307
|
-
const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-
|
|
6356
|
+
const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-D8vIsUHf.js'); });
|
|
6308
6357
|
currentAuthProvider = new InjectedWalletProvider(resolveInjectedWalletConfig(config), rpcUrl, configuredNetwork);
|
|
6309
6358
|
break;
|
|
6310
6359
|
}
|
|
@@ -6317,7 +6366,7 @@ async function getAuthProvider(config, fromStorage = false) {
|
|
|
6317
6366
|
// Selecting authMethod:'evm-wallet' IS the opt-in — pass evmWalletConfig
|
|
6318
6367
|
// to point at a specific wallet or set chainId/domain.
|
|
6319
6368
|
const evmWalletConfig = ((_a = config.evmWalletConfig) !== null && _a !== void 0 ? _a : {});
|
|
6320
|
-
const { InjectedEvmWalletProvider } = await Promise.resolve().then(function () { return require('./injected-evm-wallet-provider-
|
|
6369
|
+
const { InjectedEvmWalletProvider } = await Promise.resolve().then(function () { return require('./injected-evm-wallet-provider-C8YItSiB.js'); });
|
|
6321
6370
|
currentAuthProvider = new InjectedEvmWalletProvider(evmWalletConfig);
|
|
6322
6371
|
break;
|
|
6323
6372
|
}
|
|
@@ -6342,7 +6391,7 @@ async function getAuthProvider(config, fromStorage = false) {
|
|
|
6342
6391
|
break;
|
|
6343
6392
|
case "guest":
|
|
6344
6393
|
// Anonymous auth: a device-local ed25519 keypair signs the challenge.
|
|
6345
|
-
currentAuthProvider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-
|
|
6394
|
+
currentAuthProvider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-B4WIWOjV.js'); })).GuestAuthProvider();
|
|
6346
6395
|
break;
|
|
6347
6396
|
}
|
|
6348
6397
|
if (!currentAuthProvider) {
|
|
@@ -6404,7 +6453,7 @@ async function signInAnonymously() {
|
|
|
6404
6453
|
// Lazy-load the guest provider so its ed25519/web3 dependencies stay out of
|
|
6405
6454
|
// the main bundle for data-only apps. Specifier is a static string literal
|
|
6406
6455
|
// so bundle-splitting can see it.
|
|
6407
|
-
const provider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-
|
|
6456
|
+
const provider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-B4WIWOjV.js'); })).GuestAuthProvider();
|
|
6408
6457
|
setAuthLoading(true); // reflect "signing in…" while the guest keypair session is minted
|
|
6409
6458
|
// adoptSessionProvider awaits only getConfig() (already resolved here) and then
|
|
6410
6459
|
// runs every write - provider/method/config/marker/user - in one synchronous
|
|
@@ -6575,7 +6624,7 @@ function ensureSharedWalletLoginReady() {
|
|
|
6575
6624
|
if (!sharedWalletReady) {
|
|
6576
6625
|
sharedWalletReady = (async () => {
|
|
6577
6626
|
await core.getConfig();
|
|
6578
|
-
await Promise.resolve().then(function () { return require('./injected-wallet-provider-
|
|
6627
|
+
await Promise.resolve().then(function () { return require('./injected-wallet-provider-D8vIsUHf.js'); });
|
|
6579
6628
|
})().catch((error) => {
|
|
6580
6629
|
sharedWalletReady = null;
|
|
6581
6630
|
throw error;
|
|
@@ -6678,7 +6727,7 @@ async function loginWithWallet(options) {
|
|
|
6678
6727
|
await ensureSharedWalletLoginReady();
|
|
6679
6728
|
else
|
|
6680
6729
|
await ensureWalletLoginReady();
|
|
6681
|
-
const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-
|
|
6730
|
+
const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-D8vIsUHf.js'); });
|
|
6682
6731
|
// Keep the RAW wallet provider: the offchain wrapper forwards only a fixed
|
|
6683
6732
|
// set of methods, so cleanup below must speak to the provider that actually
|
|
6684
6733
|
// holds the config rather than to whatever is wrapping it.
|
|
@@ -7045,6 +7094,13 @@ function registerStorageBridge() {
|
|
|
7045
7094
|
void syncStoredSession().catch((error) => console.warn('Bounded session synchronization failed:', error));
|
|
7046
7095
|
});
|
|
7047
7096
|
}
|
|
7097
|
+
function sameSessionIdentity(next, previous) {
|
|
7098
|
+
if (!next || !previous)
|
|
7099
|
+
return false;
|
|
7100
|
+
const a = core.deriveUserIdentityFromIdToken(next);
|
|
7101
|
+
const b = core.deriveUserIdentityFromIdToken(previous);
|
|
7102
|
+
return !!a.id && a.id === b.id && a.address === b.address && a.email === b.email && a.evmAddress === b.evmAddress;
|
|
7103
|
+
}
|
|
7048
7104
|
async function syncStoredSession() {
|
|
7049
7105
|
const config = initializedConfig;
|
|
7050
7106
|
if (!config)
|
|
@@ -7053,6 +7109,18 @@ async function syncStoredSession() {
|
|
|
7053
7109
|
const issuer = core.WebSessionManager.getIssuer();
|
|
7054
7110
|
if (token === observedIdToken && issuer === observedIssuer)
|
|
7055
7111
|
return;
|
|
7112
|
+
// Another tab refreshed this same session (tokens rotate every few minutes):
|
|
7113
|
+
// who is signed in did not change, so keep the user and its live reads, whose
|
|
7114
|
+
// sockets take the new token on their own, instead of hiding and restoring it.
|
|
7115
|
+
if (currentUser && issuer === observedIssuer && sameSessionIdentity(token, observedIdToken)) {
|
|
7116
|
+
const record = await core.WebSessionManager.readSessionWithGeneration();
|
|
7117
|
+
if (config !== initializedConfig || core.WebSessionManager.getIdToken() !== token)
|
|
7118
|
+
return;
|
|
7119
|
+
if ((record === null || record === void 0 ? void 0 : record.idToken) === token && (!record.appId || record.appId === config.appId)) {
|
|
7120
|
+
observedIdToken = token;
|
|
7121
|
+
return;
|
|
7122
|
+
}
|
|
7123
|
+
}
|
|
7056
7124
|
observedIdToken = token;
|
|
7057
7125
|
observedIssuer = issuer;
|
|
7058
7126
|
const generation = ++initializationGeneration;
|
|
@@ -7847,10 +7915,18 @@ async function startTurnkeyEmailLogin(email) {
|
|
|
7847
7915
|
if (!hasDOM$1()) {
|
|
7848
7916
|
throw new Error('Turnkey-native email login is web-only - on React Native use loginWithRedirect()');
|
|
7849
7917
|
}
|
|
7918
|
+
const generation = getInitializationGeneration();
|
|
7919
|
+
const walletGuard = walletOperationGuard();
|
|
7920
|
+
const assertContext = () => {
|
|
7921
|
+
walletGuard();
|
|
7922
|
+
if (generation !== getInitializationGeneration())
|
|
7923
|
+
throw new Error('Login was superseded by SDK reinitialization. Start sign-in again.');
|
|
7924
|
+
};
|
|
7850
7925
|
const trimmed = email.trim();
|
|
7851
7926
|
if (!trimmed)
|
|
7852
7927
|
throw new Error('Enter your email to continue.');
|
|
7853
7928
|
const { base, appId } = await inlineAuthEndpoint();
|
|
7929
|
+
assertContext();
|
|
7854
7930
|
if (!appId)
|
|
7855
7931
|
throw new Error('appId is not configured (init the SDK with your appId)');
|
|
7856
7932
|
const res = await fetch(`${base}/wallet/turnkey/auth/init`, {
|
|
@@ -7862,6 +7938,7 @@ async function startTurnkeyEmailLogin(email) {
|
|
|
7862
7938
|
if (!res.ok || !data || typeof data.otpId !== 'string' || typeof data.otpEncryptionTargetBundle !== 'string') {
|
|
7863
7939
|
throw new Error(String((data && data.error) || 'Could not send a code. Please try again.'));
|
|
7864
7940
|
}
|
|
7941
|
+
assertContext();
|
|
7865
7942
|
const otpId = data.otpId;
|
|
7866
7943
|
const otpEncryptionTargetBundle = data.otpEncryptionTargetBundle;
|
|
7867
7944
|
// A tenant-origin login always gets a ceremony id; without one the OTP frame refuses to run
|
|
@@ -7877,14 +7954,20 @@ async function startTurnkeyEmailLogin(email) {
|
|
|
7877
7954
|
: undefined;
|
|
7878
7955
|
return {
|
|
7879
7956
|
email: trimmed, frameUrl, signerOrigin,
|
|
7880
|
-
run(iframe,
|
|
7957
|
+
run(iframe, signal) {
|
|
7958
|
+
try {
|
|
7959
|
+
assertContext();
|
|
7960
|
+
}
|
|
7961
|
+
catch (error) {
|
|
7962
|
+
return Promise.reject(error);
|
|
7963
|
+
}
|
|
7881
7964
|
if (!ceremonyId) {
|
|
7882
7965
|
return Promise.reject(new Error('This app is not configured for in-frame wallet login. Please try again.'));
|
|
7883
7966
|
}
|
|
7884
|
-
const run = { iframe, base, signerOrigin, appId, email: trimmed, otpId, otpEncryptionTargetBundle, ceremonyId };
|
|
7967
|
+
const run = { iframe, base, signerOrigin, appId, email: trimmed, otpId, otpEncryptionTargetBundle, ceremonyId, generation };
|
|
7885
7968
|
// BSA-2026-004: the login code is typed only in /wallet/turnkey/otp-frame.
|
|
7886
7969
|
// The scoped signer URL is for post-login signing, not OTP entry.
|
|
7887
|
-
return runOtpFrame(run);
|
|
7970
|
+
return runOtpFrame(run, signal);
|
|
7888
7971
|
},
|
|
7889
7972
|
};
|
|
7890
7973
|
}
|
|
@@ -7893,7 +7976,7 @@ async function startTurnkeyEmailLogin(email) {
|
|
|
7893
7976
|
// frame 'result' {session} -> we establish the inline session and resolve the User.
|
|
7894
7977
|
// When the frame asks for the signing-session authorization ('need-authorization') we mint a
|
|
7895
7978
|
// createWallet action authorization on THIS (registered) origin and post it in - never a key.
|
|
7896
|
-
function runOtpFrame(run) {
|
|
7979
|
+
function runOtpFrame(run, signal) {
|
|
7897
7980
|
const tenantOrigin = window.location.origin;
|
|
7898
7981
|
const url = `${run.base.replace(/\/$/, '')}/wallet/turnkey/otp-frame`
|
|
7899
7982
|
+ `?appId=${encodeURIComponent(run.appId)}`
|
|
@@ -7903,13 +7986,48 @@ function runOtpFrame(run) {
|
|
|
7903
7986
|
return new Promise((resolve, reject) => {
|
|
7904
7987
|
let settled = false;
|
|
7905
7988
|
let started = false;
|
|
7906
|
-
|
|
7989
|
+
let receivingResult = false;
|
|
7990
|
+
let committing = false;
|
|
7991
|
+
const walletGuard = walletLoginGuard(signal);
|
|
7992
|
+
const beforeCommit = () => {
|
|
7993
|
+
if (settled)
|
|
7994
|
+
throw new Error('wallet_login_cancelled');
|
|
7995
|
+
walletGuard();
|
|
7996
|
+
if (run.generation !== getInitializationGeneration())
|
|
7997
|
+
throw new Error('Login was superseded by SDK reinitialization. Start sign-in again.');
|
|
7998
|
+
};
|
|
7999
|
+
const finish = (error, user) => {
|
|
8000
|
+
if (settled)
|
|
8001
|
+
return;
|
|
8002
|
+
settled = true;
|
|
8003
|
+
window.removeEventListener('message', onMsg);
|
|
8004
|
+
window.clearTimeout(timer);
|
|
8005
|
+
signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', onAbort);
|
|
8006
|
+
if (error) {
|
|
8007
|
+
// Destroy the expired frame's code/key realm as well as its parent listener.
|
|
8008
|
+
run.iframe.src = 'about:blank';
|
|
8009
|
+
reject(error);
|
|
8010
|
+
}
|
|
8011
|
+
else
|
|
8012
|
+
resolve(user);
|
|
8013
|
+
};
|
|
8014
|
+
const onAbort = () => { if (!committing)
|
|
8015
|
+
finish(new Error('cancelled')); };
|
|
7907
8016
|
const onMsg = async (event) => {
|
|
7908
8017
|
if (settled)
|
|
7909
8018
|
return;
|
|
7910
8019
|
// Trust ONLY the signer origin and the frame's own window.
|
|
7911
8020
|
if (event.origin !== run.signerOrigin || event.source !== run.iframe.contentWindow)
|
|
7912
8021
|
return;
|
|
8022
|
+
if (!committing) {
|
|
8023
|
+
try {
|
|
8024
|
+
beforeCommit();
|
|
8025
|
+
}
|
|
8026
|
+
catch (error) {
|
|
8027
|
+
finish(error instanceof Error ? error : new Error(String(error)));
|
|
8028
|
+
return;
|
|
8029
|
+
}
|
|
8030
|
+
}
|
|
7913
8031
|
const d = event.data;
|
|
7914
8032
|
if (!d || typeof d !== 'object')
|
|
7915
8033
|
return;
|
|
@@ -7952,40 +8070,56 @@ function runOtpFrame(run) {
|
|
|
7952
8070
|
return;
|
|
7953
8071
|
}
|
|
7954
8072
|
if (d.type === 'bounded:otp:result') {
|
|
8073
|
+
if (receivingResult)
|
|
8074
|
+
return;
|
|
8075
|
+
receivingResult = true;
|
|
7955
8076
|
if (d.ok && d.session && typeof d.session === 'object') {
|
|
7956
8077
|
try {
|
|
7957
|
-
const user = await establishInlineSession(d.session);
|
|
7958
|
-
|
|
7959
|
-
resolve(user);
|
|
8078
|
+
const user = await establishInlineSession(d.session, beforeCommit, undefined, () => { committing = true; });
|
|
8079
|
+
finish(undefined, user);
|
|
7960
8080
|
}
|
|
7961
8081
|
catch (error) {
|
|
7962
|
-
|
|
7963
|
-
reject(error instanceof Error ? error : new Error(String(error)));
|
|
8082
|
+
finish(error instanceof Error ? error : new Error(String(error)));
|
|
7964
8083
|
}
|
|
7965
8084
|
return;
|
|
7966
8085
|
}
|
|
7967
|
-
|
|
7968
|
-
reject(new Error(String((d && d.error) || 'Invalid or expired code.')));
|
|
8086
|
+
finish(new Error(String((d && d.error) || 'Invalid or expired code.')));
|
|
7969
8087
|
return;
|
|
7970
8088
|
}
|
|
7971
8089
|
// 'bounded:otp:registered' is advisory; login does not depend on it.
|
|
7972
8090
|
};
|
|
7973
8091
|
const post = (msg) => {
|
|
7974
8092
|
var _a;
|
|
8093
|
+
if (settled)
|
|
8094
|
+
return;
|
|
8095
|
+
if (!committing) {
|
|
8096
|
+
try {
|
|
8097
|
+
beforeCommit();
|
|
8098
|
+
}
|
|
8099
|
+
catch (_b) {
|
|
8100
|
+
return;
|
|
8101
|
+
}
|
|
8102
|
+
}
|
|
7975
8103
|
try {
|
|
7976
8104
|
(_a = run.iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage(msg, run.signerOrigin);
|
|
7977
8105
|
}
|
|
7978
|
-
catch ( /* frame gone */
|
|
8106
|
+
catch ( /* frame gone */_c) { /* frame gone */ }
|
|
7979
8107
|
};
|
|
7980
8108
|
window.addEventListener('message', onMsg);
|
|
7981
8109
|
// 3 minutes: the human must read the email and type the code. A frame that never reports is a
|
|
7982
8110
|
// failed login the user can retry.
|
|
7983
8111
|
const timer = window.setTimeout(() => {
|
|
7984
|
-
if (
|
|
7985
|
-
|
|
7986
|
-
cleanup();
|
|
7987
|
-
reject(new Error('The sign-in code entry timed out. Please try again.'));
|
|
8112
|
+
if (!committing)
|
|
8113
|
+
finish(new Error('The sign-in code entry timed out. Please try again.'));
|
|
7988
8114
|
}, 3 * 60 * 1000);
|
|
8115
|
+
signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', onAbort, { once: true });
|
|
8116
|
+
try {
|
|
8117
|
+
beforeCommit();
|
|
8118
|
+
}
|
|
8119
|
+
catch (error) {
|
|
8120
|
+
finish(error instanceof Error ? error : new Error(String(error)));
|
|
8121
|
+
return;
|
|
8122
|
+
}
|
|
7989
8123
|
run.iframe.src = url;
|
|
7990
8124
|
});
|
|
7991
8125
|
}
|
|
@@ -8014,8 +8148,8 @@ const CARD_CSS = `
|
|
|
8014
8148
|
--line:rgba(232,230,222,.08);--line-strong:rgba(232,230,222,.16);
|
|
8015
8149
|
--text:#e8e6de;--dim:#9b9991;--faint:#85837c;
|
|
8016
8150
|
--green:#58c98f;--green-bg:rgba(88,201,143,.09);--green-line:rgba(88,201,143,.28);--red:#ec8488;
|
|
8017
|
-
--disp:"Newsreader","Iowan Old Style",Georgia,serif;
|
|
8018
|
-
--body:"Schibsted Grotesk","Helvetica Neue",Arial,sans-serif;
|
|
8151
|
+
--disp:"Bounded Newsreader","Newsreader","Iowan Old Style",Georgia,serif;
|
|
8152
|
+
--body:"Bounded Schibsted Grotesk","Schibsted Grotesk","Helvetica Neue",Arial,sans-serif;
|
|
8019
8153
|
position:relative;padding:34px 32px 20px;color:var(--text);font-family:var(--body);
|
|
8020
8154
|
-webkit-font-smoothing:antialiased}
|
|
8021
8155
|
.x{position:absolute;top:20px;right:24px;border:0;background:transparent;color:var(--faint);
|
|
@@ -8136,6 +8270,17 @@ function discoverWallets(configuredNetwork) {
|
|
|
8136
8270
|
// beats a click that does nothing, which is what "one at a time" looks like from
|
|
8137
8271
|
// the outside.
|
|
8138
8272
|
const BUSY_MSG = "A sign-in is already in progress - finish or cancel it first.";
|
|
8273
|
+
// Shown instead of an empty card when no lane can be offered (wallet-only app,
|
|
8274
|
+
// no wallet in this browser). A phone browser never sees installed wallet apps
|
|
8275
|
+
// as injected providers, so the honest advice there is a different browser,
|
|
8276
|
+
// not "install a wallet".
|
|
8277
|
+
function noLaneCopy(mobile) {
|
|
8278
|
+
return mobile
|
|
8279
|
+
? "No wallet is available in this browser. Open this page in your wallet app's " +
|
|
8280
|
+
"browser, or on a desktop browser with a wallet extension, then try again."
|
|
8281
|
+
: "No wallet was found in this browser. Install a Solana wallet extension such as " +
|
|
8282
|
+
"Phantom or Solflare, reload the page, then try again.";
|
|
8283
|
+
}
|
|
8139
8284
|
const METHOD_LABEL = {
|
|
8140
8285
|
google: "Continue with Google",
|
|
8141
8286
|
apple: "Continue with Apple",
|
|
@@ -8477,12 +8622,9 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8477
8622
|
cancelPendingOpens();
|
|
8478
8623
|
};
|
|
8479
8624
|
m.onBackdrop = cancel;
|
|
8480
|
-
const style = el("style");
|
|
8481
|
-
style.textContent = CARD_CSS;
|
|
8482
8625
|
let emailDraft = "";
|
|
8483
8626
|
const renderChoose = (initialError) => {
|
|
8484
8627
|
const card = el("div", "c");
|
|
8485
|
-
card.appendChild(style.cloneNode(true));
|
|
8486
8628
|
const x = el("button", "x", "Close");
|
|
8487
8629
|
x.type = "button";
|
|
8488
8630
|
x.setAttribute("aria-label", "Close");
|
|
@@ -8699,6 +8841,24 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8699
8841
|
});
|
|
8700
8842
|
};
|
|
8701
8843
|
}
|
|
8844
|
+
// A card with no lane at all. It happens when an app asks for wallet-only
|
|
8845
|
+
// (`methods: []`, `wallet: true`) and this browser has no wallet to offer:
|
|
8846
|
+
// no injected wallet, and no Solana Mobile wallet (off-Android, or the app
|
|
8847
|
+
// never installed the adapter). A blank card between the title and the
|
|
8848
|
+
// footer was the shipped behaviour, and it reads as "the site is broken"
|
|
8849
|
+
// to the person and tells the developer nothing. Say what is missing on
|
|
8850
|
+
// screen, and name the usual cause once in the console, where the
|
|
8851
|
+
// developer's own preview run will show it.
|
|
8852
|
+
if (!hasEmail && social.length === 0 && !walletEnabled) {
|
|
8853
|
+
card.appendChild(el("p", "sub", noLaneCopy(detectMobile())));
|
|
8854
|
+
console.warn("[Bounded] openBoundedWidget has no sign-in lane to show: the app asked for " +
|
|
8855
|
+
"no email or social method and no wallet is available in this browser. " +
|
|
8856
|
+
(offerMobile
|
|
8857
|
+
? "On Android the Solana Mobile wallet is offered only when the app installs " +
|
|
8858
|
+
"'@solana-mobile/wallet-standard-mobile' (see the warning above if registration failed); "
|
|
8859
|
+
: "") +
|
|
8860
|
+
"Add a method, or make sure wallet login is enabled and the mobile adapter is installed.");
|
|
8861
|
+
}
|
|
8702
8862
|
card.appendChild(status);
|
|
8703
8863
|
const foot = el("div", "foot");
|
|
8704
8864
|
const poweredBy = el("a", undefined, "Powered by Bounded");
|
|
@@ -8745,7 +8905,6 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8745
8905
|
const renderSignInGesture = (choice, done) => {
|
|
8746
8906
|
var _a;
|
|
8747
8907
|
const card = el("div", "c");
|
|
8748
|
-
card.appendChild(style.cloneNode(true));
|
|
8749
8908
|
const x = el("button", "x", "Close");
|
|
8750
8909
|
x.type = "button";
|
|
8751
8910
|
x.setAttribute("aria-label", "Close");
|
|
@@ -8766,7 +8925,6 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8766
8925
|
};
|
|
8767
8926
|
const renderWallets = (initialError) => {
|
|
8768
8927
|
const card = el("div", "c");
|
|
8769
|
-
card.appendChild(style.cloneNode(true));
|
|
8770
8928
|
const back = el("button", "back", "\u2190 Back");
|
|
8771
8929
|
back.type = "button";
|
|
8772
8930
|
// Leaving the wallet list supersedes any attempt still preparing, so it
|
|
@@ -8846,7 +9004,6 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8846
9004
|
// experience still feels native; the code input, sealing, and verify all live behind the frame.
|
|
8847
9005
|
const renderOtpFrame = (handle) => {
|
|
8848
9006
|
const card = el("div", "c");
|
|
8849
|
-
card.appendChild(style.cloneNode(true));
|
|
8850
9007
|
const back = el("button", "back", "\u2190 Back");
|
|
8851
9008
|
back.type = "button";
|
|
8852
9009
|
card.appendChild(back);
|
|
@@ -8874,14 +9031,16 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8874
9031
|
setErr(BUSY_MSG);
|
|
8875
9032
|
return card;
|
|
8876
9033
|
}
|
|
8877
|
-
back.addEventListener("click", () => {
|
|
9034
|
+
back.addEventListener("click", () => { invalidateAttempts(); swap(renderChoose()); });
|
|
9035
|
+
const controller = new AbortController();
|
|
9036
|
+
abortScopedLogin = () => controller.abort();
|
|
8878
9037
|
handle
|
|
8879
|
-
.run(frame)
|
|
9038
|
+
.run(frame, controller.signal)
|
|
8880
9039
|
.then((u) => { settleAttempt(attempt); succeed(u); })
|
|
8881
9040
|
.catch((err) => {
|
|
8882
9041
|
if (!settleAttempt(attempt))
|
|
8883
9042
|
return;
|
|
8884
|
-
|
|
9043
|
+
swap(renderChoose(errText(err)));
|
|
8885
9044
|
});
|
|
8886
9045
|
return card;
|
|
8887
9046
|
};
|
|
@@ -8891,7 +9050,7 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8891
9050
|
// land after a newer open has taken over the DOM.
|
|
8892
9051
|
if (!owner.owns())
|
|
8893
9052
|
return;
|
|
8894
|
-
mountContent(m, node);
|
|
9053
|
+
mountContent(m, node, CARD_CSS);
|
|
8895
9054
|
requestAnimationFrame(() => {
|
|
8896
9055
|
if (owner.owns())
|
|
8897
9056
|
fitPanelToContent(m);
|
|
@@ -11283,4 +11442,4 @@ exports.useAuth = useAuth;
|
|
|
11283
11442
|
exports.useBuildRun = useBuildRun;
|
|
11284
11443
|
exports.useQuery = useQuery;
|
|
11285
11444
|
exports.waitForAuthReady = waitForAuthReady;
|
|
11286
|
-
//# sourceMappingURL=index-
|
|
11445
|
+
//# sourceMappingURL=index-BmNNZlTl.js.map
|