@bounded-sh/client 0.0.96 → 0.0.98
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/turnkey-auth.d.ts +9 -7
- package/dist/bounded-widget-modal-C0Z7gmxH.mjs +31 -0
- package/dist/bounded-widget-modal-C0Z7gmxH.mjs.map +1 -0
- package/dist/bounded-widget-modal-s0PL86Y-.js +33 -0
- package/dist/bounded-widget-modal-s0PL86Y-.js.map +1 -0
- package/dist/{email-auth-provider-B1wYw68c.js → email-auth-provider-BhYzRN0r.js} +2 -2
- package/dist/{email-auth-provider-B1wYw68c.js.map → email-auth-provider-BhYzRN0r.js.map} +1 -1
- package/dist/{email-auth-provider-BgxLdrbB.mjs → email-auth-provider-CiPAD3vz.mjs} +2 -2
- package/dist/{email-auth-provider-Dhu15el8.mjs.map → email-auth-provider-CiPAD3vz.mjs.map} +1 -1
- package/dist/{email-auth-provider-Dhu15el8.mjs → email-auth-provider-DF7Urh8i.mjs} +2 -2
- package/dist/{email-auth-provider-BgxLdrbB.mjs.map → email-auth-provider-DF7Urh8i.mjs.map} +1 -1
- package/dist/{email-auth-provider-CiMNpEWJ.js → email-auth-provider-DxB_pJKO.js} +2 -2
- package/dist/{email-auth-provider-CiMNpEWJ.js.map → email-auth-provider-DxB_pJKO.js.map} +1 -1
- package/dist/{guest-auth-provider-BrMhyIse.js → guest-auth-provider-B9C3Iub_.js} +2 -2
- package/dist/{guest-auth-provider-BrMhyIse.js.map → guest-auth-provider-B9C3Iub_.js.map} +1 -1
- package/dist/{guest-auth-provider-BGBcSwsM.js → guest-auth-provider-BiM35KHb.js} +2 -2
- package/dist/{guest-auth-provider-BGBcSwsM.js.map → guest-auth-provider-BiM35KHb.js.map} +1 -1
- package/dist/{guest-auth-provider-U-zsTm0z.mjs → guest-auth-provider-DVw-tITC.mjs} +2 -2
- package/dist/{guest-auth-provider-U-zsTm0z.mjs.map → guest-auth-provider-DVw-tITC.mjs.map} +1 -1
- package/dist/{guest-auth-provider-BXJ2xm3C.mjs → guest-auth-provider-Dtsq4QaY.mjs} +2 -2
- package/dist/{guest-auth-provider-BXJ2xm3C.mjs.map → guest-auth-provider-Dtsq4QaY.mjs.map} +1 -1
- package/dist/{index-DWUx-v0z.js → index-CYdYsf8s.js} +514 -662
- package/dist/index-CYdYsf8s.js.map +1 -0
- package/dist/{index-B5Luqobz.mjs → index-Cflemdaf.mjs} +514 -662
- package/dist/index-Cflemdaf.mjs.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{index.native-DVMCCbwq.js → index.native-BZOWS_sR.js} +16 -332
- package/dist/index.native-BZOWS_sR.js.map +1 -0
- package/dist/{index.native-CAkdhYaP.mjs → index.native-gVbAsohv.mjs} +16 -332
- package/dist/index.native-gVbAsohv.mjs.map +1 -0
- package/dist/index.native.js +1 -1
- package/dist/index.native.mjs +1 -1
- package/dist/{injected-evm-wallet-provider-DvoG_pvE.js → injected-evm-wallet-provider-Bv8VLuB1.js} +2 -2
- package/dist/{injected-evm-wallet-provider-DvoG_pvE.js.map → injected-evm-wallet-provider-Bv8VLuB1.js.map} +1 -1
- package/dist/{injected-evm-wallet-provider-CgUCo_6H.js → injected-evm-wallet-provider-C3MwUTRd.js} +2 -2
- package/dist/{injected-evm-wallet-provider-CgUCo_6H.js.map → injected-evm-wallet-provider-C3MwUTRd.js.map} +1 -1
- package/dist/{injected-evm-wallet-provider-Da6kghfZ.mjs → injected-evm-wallet-provider-CMqUqqxN.mjs} +2 -2
- package/dist/{injected-evm-wallet-provider-Da6kghfZ.mjs.map → injected-evm-wallet-provider-CMqUqqxN.mjs.map} +1 -1
- package/dist/{injected-evm-wallet-provider-BmWa3lHu.mjs → injected-evm-wallet-provider-K0j697jt.mjs} +2 -2
- package/dist/{injected-evm-wallet-provider-BmWa3lHu.mjs.map → injected-evm-wallet-provider-K0j697jt.mjs.map} +1 -1
- package/dist/{injected-wallet-provider-B7xVks8k.js → injected-wallet-provider-BDt4CN0b.js} +2 -2
- package/dist/{injected-wallet-provider-B7xVks8k.js.map → injected-wallet-provider-BDt4CN0b.js.map} +1 -1
- package/dist/{injected-wallet-provider-DBWcA9tW.js → injected-wallet-provider-CG3oKdp_.js} +2 -2
- package/dist/{injected-wallet-provider-DBWcA9tW.js.map → injected-wallet-provider-CG3oKdp_.js.map} +1 -1
- package/dist/{injected-wallet-provider-TvPTmUdy.mjs → injected-wallet-provider-DH8yLpyf.mjs} +2 -2
- package/dist/{injected-wallet-provider-TvPTmUdy.mjs.map → injected-wallet-provider-DH8yLpyf.mjs.map} +1 -1
- package/dist/{injected-wallet-provider-CJFZ9O7q.mjs → injected-wallet-provider-Dlo96aV9.mjs} +2 -2
- package/dist/{injected-wallet-provider-CJFZ9O7q.mjs.map → injected-wallet-provider-Dlo96aV9.mjs.map} +1 -1
- package/package.json +2 -2
- package/dist/index-B5Luqobz.mjs.map +0 -1
- package/dist/index-DWUx-v0z.js.map +0 -1
- package/dist/index.native-CAkdhYaP.mjs.map +0 -1
- package/dist/index.native-DVMCCbwq.js.map +0 -1
|
@@ -4178,402 +4178,6 @@ async function ensureSolanaMobileWalletRegistered(config, network) {
|
|
|
4178
4178
|
|
|
4179
4179
|
var bufferExports = requireBuffer();
|
|
4180
4180
|
|
|
4181
|
-
// bounded-widget-modal.ts - the shared in-app WIDGET shell for Bounded's login
|
|
4182
|
-
// and signing surfaces. One Shadow-DOM overlay + panel that matches the Bounded
|
|
4183
|
-
// widget (Seal) look and MOTION: a backdrop fade, a panel rise on desktop, a
|
|
4184
|
-
// bottom-sheet on mobile, a height tween as content swaps, and a clean close.
|
|
4185
|
-
//
|
|
4186
|
-
// It hosts EITHER:
|
|
4187
|
-
// - NATIVE content (the login card the SDK renders itself), or
|
|
4188
|
-
// - an IFRAME (the Bounded-owned signer page, which must run on the single
|
|
4189
|
-
// signer origin because the wallet's 24h signing session lives in that
|
|
4190
|
-
// origin's storage, out of every app's reach).
|
|
4191
|
-
//
|
|
4192
|
-
// The modal is a warm singleton: it stays mounted (hidden) between uses so a
|
|
4193
|
-
// second open - or a signature right after login - is instant and, when it is
|
|
4194
|
-
// already open, a clean in-place view swap rather than a reopen.
|
|
4195
|
-
function hasDOM$5() {
|
|
4196
|
-
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
4197
|
-
}
|
|
4198
|
-
const OVERLAY_CSS = `
|
|
4199
|
-
:host{all:initial}
|
|
4200
|
-
*{box-sizing:border-box}
|
|
4201
|
-
.bw-ov{position:fixed;inset:0;z-index:2147483647;display:none;
|
|
4202
|
-
font-family:"Schibsted Grotesk","Helvetica Neue",Arial,sans-serif}
|
|
4203
|
-
.bw-ov.mounted{display:block}
|
|
4204
|
-
.bw-back{position:fixed;inset:0;background:rgba(4,4,5,.62);opacity:0;
|
|
4205
|
-
transition:opacity .24s ease;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px)}
|
|
4206
|
-
.bw-wrap{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;padding:20px}
|
|
4207
|
-
.bw-panel{position:relative;width:420px;max-width:calc(100vw - 28px);height:280px;
|
|
4208
|
-
border-radius:14px;overflow:hidden;background:#0e0f11;border:1px solid rgba(232,230,222,.08);
|
|
4209
|
-
box-shadow:0 1px 0 rgba(232,230,222,.03) inset,0 40px 90px -45px rgba(0,0,0,.85);
|
|
4210
|
-
opacity:0;transform:translateY(14px) scale(.98);will-change:transform,opacity,height;
|
|
4211
|
-
transition:opacity .28s cubic-bezier(.2,.8,.2,1),transform .28s cubic-bezier(.2,.8,.2,1),
|
|
4212
|
-
height .3s cubic-bezier(.2,.8,.2,1)}
|
|
4213
|
-
.bw-ov.show .bw-back{opacity:1}
|
|
4214
|
-
.bw-ov.show .bw-panel{opacity:1;transform:none}
|
|
4215
|
-
.bw-ov.closing .bw-back{opacity:0}
|
|
4216
|
-
.bw-ov.closing .bw-panel{opacity:0;transform:translateY(12px) scale(.99)}
|
|
4217
|
-
.bw-content{position:absolute;inset:0;overflow:hidden}
|
|
4218
|
-
.bw-frame{display:block;width:100%;height:100%;border:0;background:transparent;color-scheme:dark}
|
|
4219
|
-
/* editorial corner crop-marks, matching the reference frame */
|
|
4220
|
-
.bw-mk{position:absolute;width:13px;height:13px;pointer-events:none;z-index:2;
|
|
4221
|
-
border-color:rgba(232,230,222,.22);border-style:solid;border-width:0}
|
|
4222
|
-
.bw-mk.tl{top:11px;left:11px;border-top-width:1px;border-left-width:1px}
|
|
4223
|
-
.bw-mk.tr{top:11px;right:11px;border-top-width:1px;border-right-width:1px}
|
|
4224
|
-
.bw-mk.bl{bottom:11px;left:11px;border-bottom-width:1px;border-left-width:1px}
|
|
4225
|
-
.bw-mk.br{bottom:11px;right:11px;border-bottom-width:1px;border-right-width:1px}
|
|
4226
|
-
@media(max-width:560px){
|
|
4227
|
-
.bw-wrap{align-items:flex-end;padding:0}
|
|
4228
|
-
.bw-panel{width:100%;max-width:100%;border-radius:18px 18px 0 0;border-bottom:0}
|
|
4229
|
-
.bw-content{overflow-y:auto}
|
|
4230
|
-
.bw-ov.show .bw-panel{transform:none}
|
|
4231
|
-
.bw-ov:not(.show) .bw-panel,.bw-ov.closing .bw-panel{transform:translateY(18%)}
|
|
4232
|
-
}
|
|
4233
|
-
@media(prefers-reduced-motion:reduce){.bw-back,.bw-panel{transition:opacity .12s linear!important}}
|
|
4234
|
-
`;
|
|
4235
|
-
let modal = null;
|
|
4236
|
-
function getModal() {
|
|
4237
|
-
if (modal)
|
|
4238
|
-
return modal;
|
|
4239
|
-
const root = document.createElement("div");
|
|
4240
|
-
root.setAttribute("data-bounded-widget", "");
|
|
4241
|
-
const shadow = root.attachShadow({ mode: "open" });
|
|
4242
|
-
const style = document.createElement("style");
|
|
4243
|
-
style.textContent = OVERLAY_CSS;
|
|
4244
|
-
shadow.appendChild(style);
|
|
4245
|
-
const overlay = document.createElement("div");
|
|
4246
|
-
overlay.className = "bw-ov";
|
|
4247
|
-
const back = document.createElement("div");
|
|
4248
|
-
back.className = "bw-back";
|
|
4249
|
-
const wrap = document.createElement("div");
|
|
4250
|
-
wrap.className = "bw-wrap";
|
|
4251
|
-
const panel = document.createElement("div");
|
|
4252
|
-
panel.className = "bw-panel";
|
|
4253
|
-
const content = document.createElement("div");
|
|
4254
|
-
content.className = "bw-content";
|
|
4255
|
-
panel.appendChild(content);
|
|
4256
|
-
for (const corner of ["tl", "tr", "bl", "br"]) {
|
|
4257
|
-
const mk = document.createElement("span");
|
|
4258
|
-
mk.className = "bw-mk " + corner;
|
|
4259
|
-
panel.appendChild(mk);
|
|
4260
|
-
}
|
|
4261
|
-
wrap.appendChild(panel);
|
|
4262
|
-
overlay.appendChild(back);
|
|
4263
|
-
overlay.appendChild(wrap);
|
|
4264
|
-
shadow.appendChild(overlay);
|
|
4265
|
-
(document.body || document.documentElement).appendChild(root);
|
|
4266
|
-
const m = {
|
|
4267
|
-
root,
|
|
4268
|
-
overlay,
|
|
4269
|
-
panel,
|
|
4270
|
-
content,
|
|
4271
|
-
iframe: null,
|
|
4272
|
-
iframeOrigin: "",
|
|
4273
|
-
iframeReady: false,
|
|
4274
|
-
onBackdrop: null,
|
|
4275
|
-
onIframeMessage: null,
|
|
4276
|
-
chain: Promise.resolve(),
|
|
4277
|
-
fitObserver: null,
|
|
4278
|
-
generation: 0,
|
|
4279
|
-
onSupersede: null,
|
|
4280
|
-
};
|
|
4281
|
-
// The dismiss handler lives on `.bw-wrap`: it is the full-viewport flex layer
|
|
4282
|
-
// that sits ABOVE `.bw-back`, so it (not the backdrop element) receives clicks
|
|
4283
|
-
// outside the panel. Fire only when the click lands on the wrap itself, never
|
|
4284
|
-
// when it bubbles up from the panel or its content.
|
|
4285
|
-
wrap.addEventListener("click", (event) => {
|
|
4286
|
-
if (event.target === wrap && m.onBackdrop)
|
|
4287
|
-
m.onBackdrop();
|
|
4288
|
-
});
|
|
4289
|
-
window.addEventListener("message", (event) => {
|
|
4290
|
-
if (!m.iframe)
|
|
4291
|
-
return;
|
|
4292
|
-
if (event.origin !== m.iframeOrigin)
|
|
4293
|
-
return;
|
|
4294
|
-
if (event.source !== m.iframe.contentWindow)
|
|
4295
|
-
return;
|
|
4296
|
-
const d = event.data;
|
|
4297
|
-
if (!d || typeof d !== "object")
|
|
4298
|
-
return;
|
|
4299
|
-
if (m.onIframeMessage)
|
|
4300
|
-
m.onIframeMessage(d);
|
|
4301
|
-
});
|
|
4302
|
-
modal = m;
|
|
4303
|
-
return m;
|
|
4304
|
-
}
|
|
4305
|
-
function showModal(m) {
|
|
4306
|
-
m.overlay.classList.remove("closing");
|
|
4307
|
-
m.overlay.classList.add("mounted");
|
|
4308
|
-
// Force a reflow so the .show transition runs from the hidden state every open.
|
|
4309
|
-
void m.panel.offsetWidth;
|
|
4310
|
-
m.overlay.classList.add("show");
|
|
4311
|
-
}
|
|
4312
|
-
function hideModal(m, after) {
|
|
4313
|
-
m.overlay.classList.remove("show");
|
|
4314
|
-
m.overlay.classList.add("closing");
|
|
4315
|
-
// Capture the generation at hide time. If a newer open re-shows the modal within
|
|
4316
|
-
// the close tween, this stale timer must NOT strip `.mounted`/`.closing` off the
|
|
4317
|
-
// freshly reopened widget - only tear down when we are still the same open.
|
|
4318
|
-
const gen = m.generation;
|
|
4319
|
-
window.setTimeout(() => {
|
|
4320
|
-
if (m.generation === gen)
|
|
4321
|
-
m.overlay.classList.remove("mounted", "closing");
|
|
4322
|
-
}, 260);
|
|
4323
|
-
}
|
|
4324
|
-
function setPanelHeight(m, px) {
|
|
4325
|
-
const h = Math.max(140, Math.min(680, Math.round(px)));
|
|
4326
|
-
m.panel.style.height = h + "px";
|
|
4327
|
-
}
|
|
4328
|
-
// True outer height of the mounted card: the max of its padding-box scroll height
|
|
4329
|
-
// (catches overflowing descendants) and its border-box height plus own vertical
|
|
4330
|
-
// margins (catches border + margins, which scrollHeight omits). Ceiled so a
|
|
4331
|
-
// sub-pixel row is never clipped under `overflow:hidden`.
|
|
4332
|
-
function measureOuterHeight(target) {
|
|
4333
|
-
var _a;
|
|
4334
|
-
const cs = (_a = target.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.getComputedStyle(target);
|
|
4335
|
-
const marginY = cs ? parseFloat(cs.marginTop) + parseFloat(cs.marginBottom) : 0;
|
|
4336
|
-
const borderBox = target.offsetHeight + (Number.isFinite(marginY) ? marginY : 0);
|
|
4337
|
-
const rect = target.getBoundingClientRect().height;
|
|
4338
|
-
return Math.ceil(Math.max(target.scrollHeight, borderBox, rect));
|
|
4339
|
-
}
|
|
4340
|
-
/**
|
|
4341
|
-
* Measure the currently mounted native content and tween the panel to fit it.
|
|
4342
|
-
* Re-fits automatically when the card's intrinsic height changes - notably after
|
|
4343
|
-
* the Newsreader/Schibsted web fonts swap in (which grows line boxes a few px
|
|
4344
|
-
* after first paint) and on inline view swaps (email -> OTP code -> success).
|
|
4345
|
-
*/
|
|
4346
|
-
function fitPanelToContent(m) {
|
|
4347
|
-
var _a, _b;
|
|
4348
|
-
const first = m.content.firstElementChild;
|
|
4349
|
-
const target = first || m.content;
|
|
4350
|
-
const apply = () => {
|
|
4351
|
-
// Only fit while this exact node is still the mounted card.
|
|
4352
|
-
if (m.content.firstElementChild !== first && first)
|
|
4353
|
-
return;
|
|
4354
|
-
const h = measureOuterHeight(target);
|
|
4355
|
-
if (h > 0)
|
|
4356
|
-
setPanelHeight(m, h);
|
|
4357
|
-
};
|
|
4358
|
-
apply();
|
|
4359
|
-
const view = target.ownerDocument.defaultView;
|
|
4360
|
-
// Re-fit after fonts load (one-shot) and once the ResizeObserver-less browsers
|
|
4361
|
-
// have painted, so the height never lags a late reflow.
|
|
4362
|
-
(_a = view === null || view === void 0 ? void 0 : view.requestAnimationFrame) === null || _a === void 0 ? void 0 : _a.call(view, apply);
|
|
4363
|
-
const fonts = target.ownerDocument.fonts;
|
|
4364
|
-
if (fonts === null || fonts === void 0 ? void 0 : fonts.ready)
|
|
4365
|
-
fonts.ready.then(apply).catch(() => { });
|
|
4366
|
-
(_b = m.fitObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
|
|
4367
|
-
m.fitObserver = null;
|
|
4368
|
-
if (first && typeof (view === null || view === void 0 ? void 0 : view.ResizeObserver) === "function") {
|
|
4369
|
-
const ro = new view.ResizeObserver(() => apply());
|
|
4370
|
-
ro.observe(first);
|
|
4371
|
-
m.fitObserver = ro;
|
|
4372
|
-
}
|
|
4373
|
-
}
|
|
4374
|
-
/** Switch the modal into NATIVE-content mode: detach any iframe, mount `node`. */
|
|
4375
|
-
function mountContent(m, node) {
|
|
4376
|
-
var _a;
|
|
4377
|
-
detachIframe(m);
|
|
4378
|
-
(_a = m.fitObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
4379
|
-
m.fitObserver = null;
|
|
4380
|
-
m.content.replaceChildren(node);
|
|
4381
|
-
m.content.style.display = "block";
|
|
4382
|
-
}
|
|
4383
|
-
/** Get (or lazily create) the warm iframe for signer/hosted-page mode. */
|
|
4384
|
-
function ensureIframe(m, url, origin) {
|
|
4385
|
-
var _a;
|
|
4386
|
-
if (m.iframe && m.iframeOrigin === origin && m.iframe.src === url)
|
|
4387
|
-
return m.iframe;
|
|
4388
|
-
detachIframe(m);
|
|
4389
|
-
(_a = m.fitObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
4390
|
-
m.fitObserver = null;
|
|
4391
|
-
m.content.style.display = "none";
|
|
4392
|
-
const iframe = document.createElement("iframe");
|
|
4393
|
-
iframe.className = "bw-frame";
|
|
4394
|
-
iframe.setAttribute("title", "Bounded");
|
|
4395
|
-
iframe.setAttribute("allow", "clipboard-write");
|
|
4396
|
-
iframe.src = url;
|
|
4397
|
-
m.iframeOrigin = origin;
|
|
4398
|
-
m.iframeReady = false;
|
|
4399
|
-
m.panel.appendChild(iframe);
|
|
4400
|
-
m.iframe = iframe;
|
|
4401
|
-
return iframe;
|
|
4402
|
-
}
|
|
4403
|
-
/**
|
|
4404
|
-
* Destroy the warm signer iframe if one is currently mounted for `origin`, and report
|
|
4405
|
-
* whether there was one. Logout needs this: a signing session can live in that document's
|
|
4406
|
-
* MEMORY (the signer keeps an in-memory mirror when the browser blocks its storage), and a
|
|
4407
|
-
* throwaway iframe opened by the sweep can only ever clear the shared store, never another
|
|
4408
|
-
* document's memory. Removing the iframe discards its browsing context, which takes the
|
|
4409
|
-
* mirror with it.
|
|
4410
|
-
*
|
|
4411
|
-
* Deliberately does NOT call getModal(): that would BUILD a modal just to tear it down, on
|
|
4412
|
-
* every logout of every app, most of which never mounted one.
|
|
4413
|
-
*/
|
|
4414
|
-
function detachWarmSignerIframe(origin) {
|
|
4415
|
-
if (!modal || !modal.iframe || modal.iframeOrigin !== origin)
|
|
4416
|
-
return false;
|
|
4417
|
-
detachIframe(modal);
|
|
4418
|
-
return true;
|
|
4419
|
-
}
|
|
4420
|
-
function detachIframe(m) {
|
|
4421
|
-
if (m.iframe) {
|
|
4422
|
-
try {
|
|
4423
|
-
m.iframe.remove();
|
|
4424
|
-
}
|
|
4425
|
-
catch (_a) {
|
|
4426
|
-
/* ignore */
|
|
4427
|
-
}
|
|
4428
|
-
}
|
|
4429
|
-
m.iframe = null;
|
|
4430
|
-
m.iframeReady = false;
|
|
4431
|
-
m.iframeOrigin = "";
|
|
4432
|
-
m.onIframeMessage = null;
|
|
4433
|
-
}
|
|
4434
|
-
// Load the Bounded editorial typefaces (Newsreader display + Schibsted Grotesk body +
|
|
4435
|
-
// JetBrains Mono) once at the document level so they apply inside the shadow root. A
|
|
4436
|
-
// no-op if already present or off-DOM. Fonts loaded here match the hosted auth page.
|
|
4437
|
-
const FONTS_HREF = "https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght@6..72,400;6..72,500&family=Schibsted+Grotesk:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap";
|
|
4438
|
-
function ensureFonts() {
|
|
4439
|
-
if (!hasDOM$5())
|
|
4440
|
-
return;
|
|
4441
|
-
if (document.querySelector('link[data-bounded-fonts="1"]'))
|
|
4442
|
-
return;
|
|
4443
|
-
const pre1 = document.createElement("link");
|
|
4444
|
-
pre1.rel = "preconnect";
|
|
4445
|
-
pre1.href = "https://fonts.googleapis.com";
|
|
4446
|
-
const pre2 = document.createElement("link");
|
|
4447
|
-
pre2.rel = "preconnect";
|
|
4448
|
-
pre2.href = "https://fonts.gstatic.com";
|
|
4449
|
-
pre2.crossOrigin = "anonymous";
|
|
4450
|
-
const link = document.createElement("link");
|
|
4451
|
-
link.rel = "stylesheet";
|
|
4452
|
-
link.href = FONTS_HREF;
|
|
4453
|
-
link.setAttribute("data-bounded-fonts", "1");
|
|
4454
|
-
document.head.append(pre1, pre2, link);
|
|
4455
|
-
}
|
|
4456
|
-
|
|
4457
|
-
var boundedWidgetModal = /*#__PURE__*/Object.freeze({
|
|
4458
|
-
__proto__: null,
|
|
4459
|
-
detachIframe: detachIframe,
|
|
4460
|
-
detachWarmSignerIframe: detachWarmSignerIframe,
|
|
4461
|
-
ensureFonts: ensureFonts,
|
|
4462
|
-
ensureIframe: ensureIframe,
|
|
4463
|
-
fitPanelToContent: fitPanelToContent,
|
|
4464
|
-
getModal: getModal,
|
|
4465
|
-
hasDOM: hasDOM$5,
|
|
4466
|
-
hideModal: hideModal,
|
|
4467
|
-
mountContent: mountContent,
|
|
4468
|
-
setPanelHeight: setPanelHeight,
|
|
4469
|
-
showModal: showModal
|
|
4470
|
-
});
|
|
4471
|
-
|
|
4472
|
-
// turnkey-wallet-widget.ts - runs one Turnkey signer exchange inside the shared
|
|
4473
|
-
// in-app WIDGET (bounded-widget-modal.ts). The Bounded-owned signer page is loaded
|
|
4474
|
-
// in a warm iframe behind the modal so signing feels native: an in-app approve
|
|
4475
|
-
// card (with inline code entry when the 24h signing session must first be
|
|
4476
|
-
// established), never a jarring popup.
|
|
4477
|
-
//
|
|
4478
|
-
// WHY AN IFRAME: the wallet's signing session lives in the single Bounded signer
|
|
4479
|
-
// origin's storage, out of every app's reach, so signing MUST run on that origin;
|
|
4480
|
-
// the iframe brings it in-app.
|
|
4481
|
-
//
|
|
4482
|
-
// Restricted embedders: if the frame never loads, the SAME request reruns through
|
|
4483
|
-
// `popupFallback` (a real window). Callers pass a popup implementation and never
|
|
4484
|
-
// see the difference.
|
|
4485
|
-
/**
|
|
4486
|
-
* Run one signer exchange through the in-app widget. Resolves when `onResult`
|
|
4487
|
-
* accepts a result; falls back to `popupFallback` if the frame cannot be mounted
|
|
4488
|
-
* or never loads.
|
|
4489
|
-
*/
|
|
4490
|
-
async function runWidget(url, signerOrigin, ex, popupFallback) {
|
|
4491
|
-
if (!hasDOM$5())
|
|
4492
|
-
return popupFallback();
|
|
4493
|
-
const m = getModal();
|
|
4494
|
-
const requestId = String(ex.request.requestId);
|
|
4495
|
-
// Serialize: the approve card is modal, and one warm frame handles one request at a time.
|
|
4496
|
-
const run = m.chain.then(() => new Promise((resolve, reject) => {
|
|
4497
|
-
let settled = false;
|
|
4498
|
-
let usedFallback = false;
|
|
4499
|
-
const iframe = ensureIframe(m, url, signerOrigin);
|
|
4500
|
-
const send = () => {
|
|
4501
|
-
if (!iframe.contentWindow)
|
|
4502
|
-
return;
|
|
4503
|
-
try {
|
|
4504
|
-
iframe.contentWindow.postMessage(ex.request, signerOrigin);
|
|
4505
|
-
}
|
|
4506
|
-
catch (_a) {
|
|
4507
|
-
/* frame gone */
|
|
4508
|
-
}
|
|
4509
|
-
};
|
|
4510
|
-
let loadTimer = 0;
|
|
4511
|
-
let ceilingTimer = 0;
|
|
4512
|
-
const finish = (fn) => {
|
|
4513
|
-
if (settled)
|
|
4514
|
-
return;
|
|
4515
|
-
settled = true;
|
|
4516
|
-
m.onIframeMessage = null;
|
|
4517
|
-
m.onBackdrop = null;
|
|
4518
|
-
window.clearTimeout(loadTimer);
|
|
4519
|
-
window.clearTimeout(ceilingTimer);
|
|
4520
|
-
fn();
|
|
4521
|
-
};
|
|
4522
|
-
const goFallback = () => {
|
|
4523
|
-
if (usedFallback || settled)
|
|
4524
|
-
return;
|
|
4525
|
-
usedFallback = true;
|
|
4526
|
-
hideModal(m);
|
|
4527
|
-
finish(() => popupFallback().then(resolve, reject));
|
|
4528
|
-
};
|
|
4529
|
-
m.onBackdrop = () => {
|
|
4530
|
-
hideModal(m);
|
|
4531
|
-
finish(() => reject(new Error("cancelled")));
|
|
4532
|
-
};
|
|
4533
|
-
m.onIframeMessage = (d) => {
|
|
4534
|
-
if (d.type === "bounded:turnkey:ready") {
|
|
4535
|
-
m.iframeReady = true;
|
|
4536
|
-
send();
|
|
4537
|
-
return;
|
|
4538
|
-
}
|
|
4539
|
-
if (d.type === "bounded:turnkey:resize" && typeof d.height === "number") {
|
|
4540
|
-
setPanelHeight(m, d.height);
|
|
4541
|
-
return;
|
|
4542
|
-
}
|
|
4543
|
-
if (d.type === "bounded:turnkey:result" && d.requestId === requestId) {
|
|
4544
|
-
const outcome = ex.onResult(d);
|
|
4545
|
-
if ("error" in outcome) {
|
|
4546
|
-
hideModal(m);
|
|
4547
|
-
finish(() => reject(new Error(outcome.error)));
|
|
4548
|
-
return;
|
|
4549
|
-
}
|
|
4550
|
-
if (outcome.done) {
|
|
4551
|
-
hideModal(m);
|
|
4552
|
-
finish(() => resolve(outcome.value));
|
|
4553
|
-
}
|
|
4554
|
-
}
|
|
4555
|
-
};
|
|
4556
|
-
showModal(m);
|
|
4557
|
-
if (m.iframeReady)
|
|
4558
|
-
send();
|
|
4559
|
-
// If the frame never loads, degrade to the popup (best-effort - a post-load
|
|
4560
|
-
// popup may be blocked without a gesture, in which case the fallback rejects).
|
|
4561
|
-
loadTimer = window.setTimeout(() => {
|
|
4562
|
-
if (!m.iframeReady && !settled)
|
|
4563
|
-
goFallback();
|
|
4564
|
-
}, 8000);
|
|
4565
|
-
// Absolute ceiling so a stuck flow cannot hang forever.
|
|
4566
|
-
ceilingTimer = window.setTimeout(() => {
|
|
4567
|
-
if (!settled) {
|
|
4568
|
-
hideModal(m);
|
|
4569
|
-
finish(() => reject(new Error("Wallet approval timed out.")));
|
|
4570
|
-
}
|
|
4571
|
-
}, 5 * 60 * 1000);
|
|
4572
|
-
}));
|
|
4573
|
-
m.chain = run.then(() => undefined, () => undefined);
|
|
4574
|
-
return run;
|
|
4575
|
-
}
|
|
4576
|
-
|
|
4577
4181
|
// turnkey-signer-frame.ts - a HIDDEN, offscreen iframe of the Bounded signer page
|
|
4578
4182
|
// for UI-less signer exchanges: sealing a login code (bounded:turnkey:encryptOtp),
|
|
4579
4183
|
// establishing the 24h signing session right after login
|
|
@@ -4584,7 +4188,7 @@ async function runWidget(url, signerOrigin, ex, popupFallback) {
|
|
|
4584
4188
|
// exchanges (seal a code, then establish the session with the keypair the SEAL
|
|
4585
4189
|
// left in that exact page instance) talk to the same page. Origin + source +
|
|
4586
4190
|
// requestId are all pinned; dispose() tears everything down.
|
|
4587
|
-
function hasDOM$
|
|
4191
|
+
function hasDOM$5() {
|
|
4588
4192
|
return typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
4589
4193
|
}
|
|
4590
4194
|
async function signerPage() {
|
|
@@ -4594,7 +4198,7 @@ async function signerPage() {
|
|
|
4594
4198
|
}
|
|
4595
4199
|
/** Mount the hidden signer frame. Callers MUST dispose() when done. */
|
|
4596
4200
|
async function openHiddenSignerFrame() {
|
|
4597
|
-
if (!hasDOM$
|
|
4201
|
+
if (!hasDOM$5())
|
|
4598
4202
|
throw new Error('The Bounded signer frame is only available in the browser.');
|
|
4599
4203
|
const { url, origin } = await signerPage();
|
|
4600
4204
|
const frame = document.createElement('iframe');
|
|
@@ -4799,17 +4403,17 @@ function buildTurnkeyActionRequest(opts) {
|
|
|
4799
4403
|
// storage, out of every app's reach, so ALL Bounded apps (any subdomain / custom
|
|
4800
4404
|
// domain) sign through this one origin - giving every user one wallet that roams
|
|
4801
4405
|
// across every app.
|
|
4802
|
-
function hasDOM$
|
|
4406
|
+
function hasDOM$4() {
|
|
4803
4407
|
return typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
4804
4408
|
}
|
|
4805
|
-
//
|
|
4806
|
-
//
|
|
4807
|
-
//
|
|
4808
|
-
// click
|
|
4809
|
-
//
|
|
4409
|
+
// BSA-2026-006: dispatch every signing / get-or-create exchange through a TOP-LEVEL
|
|
4410
|
+
// POPUP the caller opened from the user gesture - NEVER a framed widget. An authorized
|
|
4411
|
+
// tenant that embedded the signer could overlay its predictable Approve control and steal
|
|
4412
|
+
// one concealed click into a fund-moving signature; a top-level window it cannot reach or
|
|
4413
|
+
// visually redress closes that. A blocked popup surfaces `popup_blocked` (runPopup) and we
|
|
4414
|
+
// never silently fall back to an iframe.
|
|
4810
4415
|
async function deliver(url, origin, ex) {
|
|
4811
|
-
|
|
4812
|
-
return runWidget(url, origin, { request: ex.request, onResult: ex.onResult }, popup);
|
|
4416
|
+
return runPopup(url, origin, ex);
|
|
4813
4417
|
}
|
|
4814
4418
|
async function turnkeySignerPage() {
|
|
4815
4419
|
const cfg = await getConfig();
|
|
@@ -4860,7 +4464,7 @@ function activeTurnkeyAddress() {
|
|
|
4860
4464
|
? address
|
|
4861
4465
|
: null;
|
|
4862
4466
|
}
|
|
4863
|
-
let requestSeq
|
|
4467
|
+
let requestSeq = 0;
|
|
4864
4468
|
// Shared popup driver: open the signer page, do the ready/postMessage handshake, and
|
|
4865
4469
|
// resolve when `onResult` accepts a result message. Origin + source are pinned.
|
|
4866
4470
|
async function runPopup(url, signerOrigin, ex) {
|
|
@@ -4870,7 +4474,7 @@ async function runPopup(url, signerOrigin, ex) {
|
|
|
4870
4474
|
const top = window.screenY + Math.max(0, (window.outerHeight - h) / 2);
|
|
4871
4475
|
const popup = window.open(url, 'bounded-turnkey-signer', `width=${w},height=${h},left=${left},top=${top}`);
|
|
4872
4476
|
if (!popup) {
|
|
4873
|
-
throw new Error('
|
|
4477
|
+
throw new Error('popup_blocked - the wallet approval window was blocked. Call this from a user gesture (e.g. a click handler) so it can open; we never fall back to an in-page frame.');
|
|
4874
4478
|
}
|
|
4875
4479
|
return await new Promise((resolve, reject) => {
|
|
4876
4480
|
let settled = false;
|
|
@@ -5014,7 +4618,7 @@ async function fetchActionAuthorization(action) {
|
|
|
5014
4618
|
* it just costs its owner nothing and a stranger nothing.
|
|
5015
4619
|
*/
|
|
5016
4620
|
async function clearTurnkeySigningSession() {
|
|
5017
|
-
if (!hasDOM$
|
|
4621
|
+
if (!hasDOM$4())
|
|
5018
4622
|
return;
|
|
5019
4623
|
// The session can live in TWO places, and the sweep has to reach both:
|
|
5020
4624
|
// 1. the signer origin's store, shared by every signer frame in this app's partition -
|
|
@@ -5034,7 +4638,7 @@ async function clearTurnkeySigningSession() {
|
|
|
5034
4638
|
let frame = null;
|
|
5035
4639
|
try {
|
|
5036
4640
|
frame = await openHiddenSignerFrame();
|
|
5037
|
-
await frame.request({ type: 'bounded:turnkey:clearSigningSession', requestId: `tkclear_${Date.now()}_${++requestSeq
|
|
4641
|
+
await frame.request({ type: 'bounded:turnkey:clearSigningSession', requestId: `tkclear_${Date.now()}_${++requestSeq}` }, 4000);
|
|
5038
4642
|
}
|
|
5039
4643
|
catch (_b) {
|
|
5040
4644
|
/* best-effort: never block or fail logout on the sweep */
|
|
@@ -5055,10 +4659,10 @@ function hasTurnkeyWallet() {
|
|
|
5055
4659
|
* Use this to learn the fee-payer address BEFORE building a transaction to sign.
|
|
5056
4660
|
*/
|
|
5057
4661
|
async function getOrCreateTurnkeyWallet() {
|
|
5058
|
-
if (!hasDOM$
|
|
4662
|
+
if (!hasDOM$4())
|
|
5059
4663
|
throw new Error('Turnkey embedded wallets are only available in the browser (popup-based).');
|
|
5060
4664
|
const { url, origin } = await turnkeySignerPage();
|
|
5061
|
-
const requestId = `tkcreate_${Date.now()}_${++requestSeq
|
|
4665
|
+
const requestId = `tkcreate_${Date.now()}_${++requestSeq}`;
|
|
5062
4666
|
const authorization = await fetchActionAuthorization('createWallet');
|
|
5063
4667
|
return await deliver(url, origin, {
|
|
5064
4668
|
request: buildTurnkeyActionRequest({ requestId, action: 'createWallet', authorization }),
|
|
@@ -5080,7 +4684,7 @@ async function getOrCreateTurnkeyWallet() {
|
|
|
5080
4684
|
* that tab - it never transits Bounded.
|
|
5081
4685
|
*/
|
|
5082
4686
|
async function openTurnkeyKeyExport() {
|
|
5083
|
-
if (!hasDOM$
|
|
4687
|
+
if (!hasDOM$4())
|
|
5084
4688
|
throw new Error('Turnkey key export is only available in the browser.');
|
|
5085
4689
|
if (!hasTurnkeyWallet())
|
|
5086
4690
|
throw new Error('This session has no Turnkey wallet to export.');
|
|
@@ -5128,11 +4732,11 @@ async function openTurnkeyKeyExport() {
|
|
|
5128
4732
|
* completes the signature.
|
|
5129
4733
|
*/
|
|
5130
4734
|
async function signSolanaMessageViaTurnkey(message) {
|
|
5131
|
-
if (!hasDOM$
|
|
4735
|
+
if (!hasDOM$4()) {
|
|
5132
4736
|
throw new Error('Turnkey embedded-wallet signing is only available in the browser (popup-based).');
|
|
5133
4737
|
}
|
|
5134
4738
|
const { url, origin } = await turnkeySignerPage();
|
|
5135
|
-
const requestId = `tksign_${Date.now()}_${++requestSeq
|
|
4739
|
+
const requestId = `tksign_${Date.now()}_${++requestSeq}`;
|
|
5136
4740
|
const messageHex = toHex(message);
|
|
5137
4741
|
// AS-02: obtain the issuer-signed capability for THESE exact bytes first; the signer will
|
|
5138
4742
|
// refuse (capability_required) without it. Fetched per signature (each is single-payload).
|
|
@@ -5286,7 +4890,7 @@ const ISSUER_SESSION_KIND_KEY = 'bounded_issuer_session_kind';
|
|
|
5286
4890
|
// not by `typeof window` (truthy on RN). OIDC redirect/popup is web-only, but the
|
|
5287
4891
|
// session it mints is read back through this same selector everywhere.
|
|
5288
4892
|
const sessionManager = getActiveSessionManager;
|
|
5289
|
-
function hasDOM$
|
|
4893
|
+
function hasDOM$3() {
|
|
5290
4894
|
return typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
5291
4895
|
}
|
|
5292
4896
|
function decodeJwt(token) {
|
|
@@ -5437,7 +5041,7 @@ async function buildAuthorize(opts) {
|
|
|
5437
5041
|
throw new Error('appId is not configured (init the SDK with your appId)');
|
|
5438
5042
|
// Web: default to the current page so callers don't have to pass redirectUri. Native has no
|
|
5439
5043
|
// window — it MUST pass an https universal link (the system auth session needs a real URL).
|
|
5440
|
-
const redirectUri = opts.redirectUri || (hasDOM$
|
|
5044
|
+
const redirectUri = opts.redirectUri || (hasDOM$3() ? window.location.origin + window.location.pathname : undefined);
|
|
5441
5045
|
if (!redirectUri)
|
|
5442
5046
|
throw new Error('redirectUri is required on React Native — pass the https universal link the app owner registered.');
|
|
5443
5047
|
const { verifier, challenge } = await makePkce();
|
|
@@ -5545,7 +5149,7 @@ async function runNativeLogin(opts) {
|
|
|
5545
5149
|
async function loginWithRedirect(opts) {
|
|
5546
5150
|
if (isNative())
|
|
5547
5151
|
return runNativeLogin(opts);
|
|
5548
|
-
if (!hasDOM$
|
|
5152
|
+
if (!hasDOM$3())
|
|
5549
5153
|
throw new Error('loginWithRedirect requires a browser or a configured React Native platform');
|
|
5550
5154
|
const { url, pkce } = await buildAuthorize(opts);
|
|
5551
5155
|
// Stash the verifier + state so the redirect_uri page can finish the exchange. sessionStorage
|
|
@@ -5562,7 +5166,7 @@ async function loginWithRedirect(opts) {
|
|
|
5562
5166
|
* loginWithRedirect() (which resolves with the User), so there is no separate redirect
|
|
5563
5167
|
* page to finish from. Calling it on RN is harmless. */
|
|
5564
5168
|
async function completeLoginFromRedirect() {
|
|
5565
|
-
if (!hasDOM$
|
|
5169
|
+
if (!hasDOM$3())
|
|
5566
5170
|
return null;
|
|
5567
5171
|
const url = new URL(window.location.href);
|
|
5568
5172
|
const code = url.searchParams.get('code');
|
|
@@ -5610,7 +5214,7 @@ async function completeLoginFromRedirect() {
|
|
|
5610
5214
|
* redirect_uri page posts the code back. The redirect_uri page just calls the usual
|
|
5611
5215
|
* completeLoginFromRedirect() (which auto-detects the popup) — no separate call needed. */
|
|
5612
5216
|
async function loginWithPopup(opts) {
|
|
5613
|
-
if (!hasDOM$
|
|
5217
|
+
if (!hasDOM$3())
|
|
5614
5218
|
throw new Error('loginWithPopup is web-only — on React Native use loginWithRedirect()');
|
|
5615
5219
|
// Open synchronously, before PKCE/config awaits consume the click's user-
|
|
5616
5220
|
// activation window. Opening only after buildAuthorize() intermittently
|
|
@@ -5770,7 +5374,7 @@ async function loginWithPopup(opts) {
|
|
|
5770
5374
|
/** Call this on the redirect_uri page when login was opened via loginWithPopup(): posts the
|
|
5771
5375
|
* code back to the opener and closes. (For the redirect variant use completeLoginFromRedirect.) */
|
|
5772
5376
|
function completeLoginInPopup(openerOrigin) {
|
|
5773
|
-
if (!hasDOM$
|
|
5377
|
+
if (!hasDOM$3() || !window.opener)
|
|
5774
5378
|
return;
|
|
5775
5379
|
const url = new URL(window.location.href);
|
|
5776
5380
|
const code = url.searchParams.get('code');
|
|
@@ -6224,7 +5828,7 @@ async function getAuthProvider(config) {
|
|
|
6224
5828
|
// manager as legacy email sessions. Human login should be started
|
|
6225
5829
|
// with loginWithRedirect(); this provider is kept as the restore and
|
|
6226
5830
|
// logout surface for those sessions.
|
|
6227
|
-
currentAuthProvider = new (await import('./email-auth-provider-
|
|
5831
|
+
currentAuthProvider = new (await import('./email-auth-provider-DF7Urh8i.mjs')).EmailAuthProvider();
|
|
6228
5832
|
break;
|
|
6229
5833
|
case "phantom": {
|
|
6230
5834
|
// First-class Solana WALLET LOGIN (the poof/TaroBase-style "connect
|
|
@@ -6266,7 +5870,7 @@ async function getAuthProvider(config) {
|
|
|
6266
5870
|
// (bounded-login-widget.ts), so registration never counts as
|
|
6267
5871
|
// evidence the user has a wallet.
|
|
6268
5872
|
await ensureSolanaMobileWalletRegistered(config, configuredNetwork);
|
|
6269
|
-
const { InjectedWalletProvider } = await import('./injected-wallet-provider-
|
|
5873
|
+
const { InjectedWalletProvider } = await import('./injected-wallet-provider-Dlo96aV9.mjs');
|
|
6270
5874
|
currentAuthProvider = new InjectedWalletProvider(resolveInjectedWalletConfig(config), rpcUrl, configuredNetwork);
|
|
6271
5875
|
break;
|
|
6272
5876
|
}
|
|
@@ -6279,7 +5883,7 @@ async function getAuthProvider(config) {
|
|
|
6279
5883
|
// Selecting authMethod:'evm-wallet' IS the opt-in — pass evmWalletConfig
|
|
6280
5884
|
// to point at a specific wallet or set chainId/domain.
|
|
6281
5885
|
const evmWalletConfig = ((_a = config.evmWalletConfig) !== null && _a !== void 0 ? _a : {});
|
|
6282
|
-
const { InjectedEvmWalletProvider } = await import('./injected-evm-wallet-provider-
|
|
5886
|
+
const { InjectedEvmWalletProvider } = await import('./injected-evm-wallet-provider-CMqUqqxN.mjs');
|
|
6283
5887
|
currentAuthProvider = new InjectedEvmWalletProvider(evmWalletConfig);
|
|
6284
5888
|
break;
|
|
6285
5889
|
}
|
|
@@ -6304,7 +5908,7 @@ async function getAuthProvider(config) {
|
|
|
6304
5908
|
break;
|
|
6305
5909
|
case "guest":
|
|
6306
5910
|
// Anonymous auth: a device-local ed25519 keypair signs the challenge.
|
|
6307
|
-
currentAuthProvider = new (await import('./guest-auth-provider-
|
|
5911
|
+
currentAuthProvider = new (await import('./guest-auth-provider-DVw-tITC.mjs')).GuestAuthProvider();
|
|
6308
5912
|
break;
|
|
6309
5913
|
}
|
|
6310
5914
|
if (!currentAuthProvider) {
|
|
@@ -6366,7 +5970,7 @@ async function signInAnonymously() {
|
|
|
6366
5970
|
// Lazy-load the guest provider so its ed25519/web3 dependencies stay out of
|
|
6367
5971
|
// the main bundle for data-only apps. Specifier is a static string literal
|
|
6368
5972
|
// so bundle-splitting can see it.
|
|
6369
|
-
const provider = new (await import('./guest-auth-provider-
|
|
5973
|
+
const provider = new (await import('./guest-auth-provider-DVw-tITC.mjs')).GuestAuthProvider();
|
|
6370
5974
|
setAuthLoading(true); // reflect "signing in…" while the guest keypair session is minted
|
|
6371
5975
|
// adoptSessionProvider awaits only getConfig() (already resolved here) and then
|
|
6372
5976
|
// runs every write - provider/method/config/marker/user - in one synchronous
|
|
@@ -6537,7 +6141,7 @@ function ensureSharedWalletLoginReady() {
|
|
|
6537
6141
|
if (!sharedWalletReady) {
|
|
6538
6142
|
sharedWalletReady = (async () => {
|
|
6539
6143
|
await getConfig();
|
|
6540
|
-
await import('./injected-wallet-provider-
|
|
6144
|
+
await import('./injected-wallet-provider-Dlo96aV9.mjs');
|
|
6541
6145
|
})().catch((error) => {
|
|
6542
6146
|
sharedWalletReady = null;
|
|
6543
6147
|
throw error;
|
|
@@ -6640,7 +6244,7 @@ async function loginWithWallet(options) {
|
|
|
6640
6244
|
await ensureSharedWalletLoginReady();
|
|
6641
6245
|
else
|
|
6642
6246
|
await ensureWalletLoginReady();
|
|
6643
|
-
const { InjectedWalletProvider } = await import('./injected-wallet-provider-
|
|
6247
|
+
const { InjectedWalletProvider } = await import('./injected-wallet-provider-Dlo96aV9.mjs');
|
|
6644
6248
|
// Keep the RAW wallet provider: the offchain wrapper forwards only a fixed
|
|
6645
6249
|
// set of methods, so cleanup below must speak to the provider that actually
|
|
6646
6250
|
// holds the config rather than to whatever is wrapping it.
|
|
@@ -7091,80 +6695,350 @@ function setAuthLoading(loading) {
|
|
|
7091
6695
|
function getAuthLoading() {
|
|
7092
6696
|
return isAuthLoading;
|
|
7093
6697
|
}
|
|
7094
|
-
async function login(options) {
|
|
7095
|
-
if (!authProviderInstance) {
|
|
7096
|
-
throw new Error('SDK not initialized. Please call init() first.');
|
|
6698
|
+
async function login(options) {
|
|
6699
|
+
if (!authProviderInstance) {
|
|
6700
|
+
throw new Error('SDK not initialized. Please call init() first.');
|
|
6701
|
+
}
|
|
6702
|
+
const loggedInUser = await login$1(options);
|
|
6703
|
+
setCurrentUser(loggedInUser);
|
|
6704
|
+
return currentUser;
|
|
6705
|
+
}
|
|
6706
|
+
async function logout(options) {
|
|
6707
|
+
if (!authProviderInstance) {
|
|
6708
|
+
throw new Error('SDK not initialized. Please call init() first.');
|
|
6709
|
+
}
|
|
6710
|
+
await logout$1(options);
|
|
6711
|
+
setCurrentUser(null);
|
|
6712
|
+
}
|
|
6713
|
+
var hasRunFirstTime = false;
|
|
6714
|
+
function userPrincipalKey(user) {
|
|
6715
|
+
var _a, _b, _c;
|
|
6716
|
+
if (!user)
|
|
6717
|
+
return null;
|
|
6718
|
+
return (_c = (_b = (_a = user.id) !== null && _a !== void 0 ? _a : user.address) !== null && _b !== void 0 ? _b : user.email) !== null && _c !== void 0 ? _c : null;
|
|
6719
|
+
}
|
|
6720
|
+
// Update the currentUser and notify listeners
|
|
6721
|
+
function setCurrentUser(user) {
|
|
6722
|
+
// Enrich with the universal identity fields (id/email) derived from the
|
|
6723
|
+
// active session's idToken — central chokepoint so every provider's user
|
|
6724
|
+
// object gains { id, address, email } without each construction site
|
|
6725
|
+
// having to set them.
|
|
6726
|
+
user = withUserIdentity(user);
|
|
6727
|
+
const lastUser = currentUser;
|
|
6728
|
+
const wasInitializedBefore = hasRunFirstTime;
|
|
6729
|
+
const lastPrincipal = userPrincipalKey(currentUser);
|
|
6730
|
+
const nextPrincipal = userPrincipalKey(user);
|
|
6731
|
+
const shouldRunListeners = !hasRunFirstTime || lastPrincipal !== nextPrincipal;
|
|
6732
|
+
hasRunFirstTime = true;
|
|
6733
|
+
currentUser = user;
|
|
6734
|
+
if (shouldRunListeners) {
|
|
6735
|
+
// Isolate each listener: a consumer callback that throws (during logout in
|
|
6736
|
+
// particular) must not abort the notification loop OR skip the socket reopen
|
|
6737
|
+
// below. Before this, a single throwing listener propagated out of
|
|
6738
|
+
// setCurrentUser, so the realtime socket kept streaming as the signed-out
|
|
6739
|
+
// user and the other listeners were never told the principal changed.
|
|
6740
|
+
authStateListeners.forEach((callback) => {
|
|
6741
|
+
try {
|
|
6742
|
+
callback(user);
|
|
6743
|
+
}
|
|
6744
|
+
catch (error) {
|
|
6745
|
+
console.error('Error in onAuthStateChanged listener:', error);
|
|
6746
|
+
}
|
|
6747
|
+
});
|
|
6748
|
+
// Reconnect WebSocket connections with new auth when user changes.
|
|
6749
|
+
// Skip on the first setCurrentUser call during init() — there are no
|
|
6750
|
+
// existing connections to reconnect at that point.
|
|
6751
|
+
if (wasInitializedBefore && userPrincipalKey(lastUser) !== nextPrincipal) {
|
|
6752
|
+
reconnectWithNewAuth().catch((error) => {
|
|
6753
|
+
console.error('Error reconnecting WebSocket after auth change:', error);
|
|
6754
|
+
});
|
|
6755
|
+
}
|
|
6756
|
+
}
|
|
6757
|
+
// Return this commit's normalized snapshot. A listener can start another
|
|
6758
|
+
// login, so the mutable currentUser may already belong to a newer session.
|
|
6759
|
+
return user;
|
|
6760
|
+
}
|
|
6761
|
+
function getCurrentUser() {
|
|
6762
|
+
return currentUser;
|
|
6763
|
+
}
|
|
6764
|
+
/** @internal Snapshot/restore surface for transactional auth-provider switches. */
|
|
6765
|
+
function getAuthProviderInstance() {
|
|
6766
|
+
return authProviderInstance;
|
|
6767
|
+
}
|
|
6768
|
+
function setAuthProviderInstance(provider) {
|
|
6769
|
+
authProviderInstance = provider;
|
|
6770
|
+
}
|
|
6771
|
+
|
|
6772
|
+
// bounded-widget-modal.ts - the shared in-app WIDGET shell for Bounded's login
|
|
6773
|
+
// and signing surfaces. One Shadow-DOM overlay + panel that matches the Bounded
|
|
6774
|
+
// widget (Seal) look and MOTION: a backdrop fade, a panel rise on desktop, a
|
|
6775
|
+
// bottom-sheet on mobile, a height tween as content swaps, and a clean close.
|
|
6776
|
+
//
|
|
6777
|
+
// It hosts EITHER:
|
|
6778
|
+
// - NATIVE content (the login card the SDK renders itself), or
|
|
6779
|
+
// - an IFRAME (the Bounded-owned signer page, which must run on the single
|
|
6780
|
+
// signer origin because the wallet's 24h signing session lives in that
|
|
6781
|
+
// origin's storage, out of every app's reach).
|
|
6782
|
+
//
|
|
6783
|
+
// The modal is a warm singleton: it stays mounted (hidden) between uses so a
|
|
6784
|
+
// second open - or a signature right after login - is instant and, when it is
|
|
6785
|
+
// already open, a clean in-place view swap rather than a reopen.
|
|
6786
|
+
function hasDOM$2() {
|
|
6787
|
+
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
6788
|
+
}
|
|
6789
|
+
const OVERLAY_CSS = `
|
|
6790
|
+
:host{all:initial}
|
|
6791
|
+
*{box-sizing:border-box}
|
|
6792
|
+
.bw-ov{position:fixed;inset:0;z-index:2147483647;display:none;
|
|
6793
|
+
font-family:"Schibsted Grotesk","Helvetica Neue",Arial,sans-serif}
|
|
6794
|
+
.bw-ov.mounted{display:block}
|
|
6795
|
+
.bw-back{position:fixed;inset:0;background:rgba(4,4,5,.62);opacity:0;
|
|
6796
|
+
transition:opacity .24s ease;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px)}
|
|
6797
|
+
.bw-wrap{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;padding:20px}
|
|
6798
|
+
.bw-panel{position:relative;width:420px;max-width:calc(100vw - 28px);height:280px;
|
|
6799
|
+
border-radius:14px;overflow:hidden;background:#0e0f11;border:1px solid rgba(232,230,222,.08);
|
|
6800
|
+
box-shadow:0 1px 0 rgba(232,230,222,.03) inset,0 40px 90px -45px rgba(0,0,0,.85);
|
|
6801
|
+
opacity:0;transform:translateY(14px) scale(.98);will-change:transform,opacity,height;
|
|
6802
|
+
transition:opacity .28s cubic-bezier(.2,.8,.2,1),transform .28s cubic-bezier(.2,.8,.2,1),
|
|
6803
|
+
height .3s cubic-bezier(.2,.8,.2,1)}
|
|
6804
|
+
.bw-ov.show .bw-back{opacity:1}
|
|
6805
|
+
.bw-ov.show .bw-panel{opacity:1;transform:none}
|
|
6806
|
+
.bw-ov.closing .bw-back{opacity:0}
|
|
6807
|
+
.bw-ov.closing .bw-panel{opacity:0;transform:translateY(12px) scale(.99)}
|
|
6808
|
+
.bw-content{position:absolute;inset:0;overflow:hidden}
|
|
6809
|
+
.bw-frame{display:block;width:100%;height:100%;border:0;background:transparent;color-scheme:dark}
|
|
6810
|
+
/* editorial corner crop-marks, matching the reference frame */
|
|
6811
|
+
.bw-mk{position:absolute;width:13px;height:13px;pointer-events:none;z-index:2;
|
|
6812
|
+
border-color:rgba(232,230,222,.22);border-style:solid;border-width:0}
|
|
6813
|
+
.bw-mk.tl{top:11px;left:11px;border-top-width:1px;border-left-width:1px}
|
|
6814
|
+
.bw-mk.tr{top:11px;right:11px;border-top-width:1px;border-right-width:1px}
|
|
6815
|
+
.bw-mk.bl{bottom:11px;left:11px;border-bottom-width:1px;border-left-width:1px}
|
|
6816
|
+
.bw-mk.br{bottom:11px;right:11px;border-bottom-width:1px;border-right-width:1px}
|
|
6817
|
+
@media(max-width:560px){
|
|
6818
|
+
.bw-wrap{align-items:flex-end;padding:0}
|
|
6819
|
+
.bw-panel{width:100%;max-width:100%;border-radius:18px 18px 0 0;border-bottom:0}
|
|
6820
|
+
.bw-content{overflow-y:auto}
|
|
6821
|
+
.bw-ov.show .bw-panel{transform:none}
|
|
6822
|
+
.bw-ov:not(.show) .bw-panel,.bw-ov.closing .bw-panel{transform:translateY(18%)}
|
|
6823
|
+
}
|
|
6824
|
+
@media(prefers-reduced-motion:reduce){.bw-back,.bw-panel{transition:opacity .12s linear!important}}
|
|
6825
|
+
`;
|
|
6826
|
+
let modal = null;
|
|
6827
|
+
function getModal() {
|
|
6828
|
+
if (modal)
|
|
6829
|
+
return modal;
|
|
6830
|
+
const root = document.createElement("div");
|
|
6831
|
+
root.setAttribute("data-bounded-widget", "");
|
|
6832
|
+
const shadow = root.attachShadow({ mode: "open" });
|
|
6833
|
+
const style = document.createElement("style");
|
|
6834
|
+
style.textContent = OVERLAY_CSS;
|
|
6835
|
+
shadow.appendChild(style);
|
|
6836
|
+
const overlay = document.createElement("div");
|
|
6837
|
+
overlay.className = "bw-ov";
|
|
6838
|
+
const back = document.createElement("div");
|
|
6839
|
+
back.className = "bw-back";
|
|
6840
|
+
const wrap = document.createElement("div");
|
|
6841
|
+
wrap.className = "bw-wrap";
|
|
6842
|
+
const panel = document.createElement("div");
|
|
6843
|
+
panel.className = "bw-panel";
|
|
6844
|
+
const content = document.createElement("div");
|
|
6845
|
+
content.className = "bw-content";
|
|
6846
|
+
panel.appendChild(content);
|
|
6847
|
+
for (const corner of ["tl", "tr", "bl", "br"]) {
|
|
6848
|
+
const mk = document.createElement("span");
|
|
6849
|
+
mk.className = "bw-mk " + corner;
|
|
6850
|
+
panel.appendChild(mk);
|
|
6851
|
+
}
|
|
6852
|
+
wrap.appendChild(panel);
|
|
6853
|
+
overlay.appendChild(back);
|
|
6854
|
+
overlay.appendChild(wrap);
|
|
6855
|
+
shadow.appendChild(overlay);
|
|
6856
|
+
(document.body || document.documentElement).appendChild(root);
|
|
6857
|
+
const m = {
|
|
6858
|
+
root,
|
|
6859
|
+
overlay,
|
|
6860
|
+
panel,
|
|
6861
|
+
content,
|
|
6862
|
+
iframe: null,
|
|
6863
|
+
iframeOrigin: "",
|
|
6864
|
+
iframeReady: false,
|
|
6865
|
+
onBackdrop: null,
|
|
6866
|
+
onIframeMessage: null,
|
|
6867
|
+
chain: Promise.resolve(),
|
|
6868
|
+
fitObserver: null,
|
|
6869
|
+
generation: 0,
|
|
6870
|
+
onSupersede: null,
|
|
6871
|
+
};
|
|
6872
|
+
// The dismiss handler lives on `.bw-wrap`: it is the full-viewport flex layer
|
|
6873
|
+
// that sits ABOVE `.bw-back`, so it (not the backdrop element) receives clicks
|
|
6874
|
+
// outside the panel. Fire only when the click lands on the wrap itself, never
|
|
6875
|
+
// when it bubbles up from the panel or its content.
|
|
6876
|
+
wrap.addEventListener("click", (event) => {
|
|
6877
|
+
if (event.target === wrap && m.onBackdrop)
|
|
6878
|
+
m.onBackdrop();
|
|
6879
|
+
});
|
|
6880
|
+
window.addEventListener("message", (event) => {
|
|
6881
|
+
if (!m.iframe)
|
|
6882
|
+
return;
|
|
6883
|
+
if (event.origin !== m.iframeOrigin)
|
|
6884
|
+
return;
|
|
6885
|
+
if (event.source !== m.iframe.contentWindow)
|
|
6886
|
+
return;
|
|
6887
|
+
const d = event.data;
|
|
6888
|
+
if (!d || typeof d !== "object")
|
|
6889
|
+
return;
|
|
6890
|
+
if (m.onIframeMessage)
|
|
6891
|
+
m.onIframeMessage(d);
|
|
6892
|
+
});
|
|
6893
|
+
modal = m;
|
|
6894
|
+
return m;
|
|
6895
|
+
}
|
|
6896
|
+
function showModal(m) {
|
|
6897
|
+
m.overlay.classList.remove("closing");
|
|
6898
|
+
m.overlay.classList.add("mounted");
|
|
6899
|
+
// Force a reflow so the .show transition runs from the hidden state every open.
|
|
6900
|
+
void m.panel.offsetWidth;
|
|
6901
|
+
m.overlay.classList.add("show");
|
|
6902
|
+
}
|
|
6903
|
+
function hideModal(m, after) {
|
|
6904
|
+
m.overlay.classList.remove("show");
|
|
6905
|
+
m.overlay.classList.add("closing");
|
|
6906
|
+
// Capture the generation at hide time. If a newer open re-shows the modal within
|
|
6907
|
+
// the close tween, this stale timer must NOT strip `.mounted`/`.closing` off the
|
|
6908
|
+
// freshly reopened widget - only tear down when we are still the same open.
|
|
6909
|
+
const gen = m.generation;
|
|
6910
|
+
window.setTimeout(() => {
|
|
6911
|
+
if (m.generation === gen)
|
|
6912
|
+
m.overlay.classList.remove("mounted", "closing");
|
|
6913
|
+
}, 260);
|
|
6914
|
+
}
|
|
6915
|
+
function setPanelHeight(m, px) {
|
|
6916
|
+
const h = Math.max(140, Math.min(680, Math.round(px)));
|
|
6917
|
+
m.panel.style.height = h + "px";
|
|
6918
|
+
}
|
|
6919
|
+
// True outer height of the mounted card: the max of its padding-box scroll height
|
|
6920
|
+
// (catches overflowing descendants) and its border-box height plus own vertical
|
|
6921
|
+
// margins (catches border + margins, which scrollHeight omits). Ceiled so a
|
|
6922
|
+
// sub-pixel row is never clipped under `overflow:hidden`.
|
|
6923
|
+
function measureOuterHeight(target) {
|
|
6924
|
+
var _a;
|
|
6925
|
+
const cs = (_a = target.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.getComputedStyle(target);
|
|
6926
|
+
const marginY = cs ? parseFloat(cs.marginTop) + parseFloat(cs.marginBottom) : 0;
|
|
6927
|
+
const borderBox = target.offsetHeight + (Number.isFinite(marginY) ? marginY : 0);
|
|
6928
|
+
const rect = target.getBoundingClientRect().height;
|
|
6929
|
+
return Math.ceil(Math.max(target.scrollHeight, borderBox, rect));
|
|
6930
|
+
}
|
|
6931
|
+
/**
|
|
6932
|
+
* Measure the currently mounted native content and tween the panel to fit it.
|
|
6933
|
+
* Re-fits automatically when the card's intrinsic height changes - notably after
|
|
6934
|
+
* the Newsreader/Schibsted web fonts swap in (which grows line boxes a few px
|
|
6935
|
+
* after first paint) and on inline view swaps (email -> OTP code -> success).
|
|
6936
|
+
*/
|
|
6937
|
+
function fitPanelToContent(m) {
|
|
6938
|
+
var _a, _b;
|
|
6939
|
+
const first = m.content.firstElementChild;
|
|
6940
|
+
const target = first || m.content;
|
|
6941
|
+
const apply = () => {
|
|
6942
|
+
// Only fit while this exact node is still the mounted card.
|
|
6943
|
+
if (m.content.firstElementChild !== first && first)
|
|
6944
|
+
return;
|
|
6945
|
+
const h = measureOuterHeight(target);
|
|
6946
|
+
if (h > 0)
|
|
6947
|
+
setPanelHeight(m, h);
|
|
6948
|
+
};
|
|
6949
|
+
apply();
|
|
6950
|
+
const view = target.ownerDocument.defaultView;
|
|
6951
|
+
// Re-fit after fonts load (one-shot) and once the ResizeObserver-less browsers
|
|
6952
|
+
// have painted, so the height never lags a late reflow.
|
|
6953
|
+
(_a = view === null || view === void 0 ? void 0 : view.requestAnimationFrame) === null || _a === void 0 ? void 0 : _a.call(view, apply);
|
|
6954
|
+
const fonts = target.ownerDocument.fonts;
|
|
6955
|
+
if (fonts === null || fonts === void 0 ? void 0 : fonts.ready)
|
|
6956
|
+
fonts.ready.then(apply).catch(() => { });
|
|
6957
|
+
(_b = m.fitObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
|
|
6958
|
+
m.fitObserver = null;
|
|
6959
|
+
if (first && typeof (view === null || view === void 0 ? void 0 : view.ResizeObserver) === "function") {
|
|
6960
|
+
const ro = new view.ResizeObserver(() => apply());
|
|
6961
|
+
ro.observe(first);
|
|
6962
|
+
m.fitObserver = ro;
|
|
7097
6963
|
}
|
|
7098
|
-
const loggedInUser = await login$1(options);
|
|
7099
|
-
setCurrentUser(loggedInUser);
|
|
7100
|
-
return currentUser;
|
|
7101
6964
|
}
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
|
|
6965
|
+
/** Switch the modal into NATIVE-content mode: detach any iframe, mount `node`. */
|
|
6966
|
+
function mountContent(m, node) {
|
|
6967
|
+
var _a;
|
|
6968
|
+
detachIframe(m);
|
|
6969
|
+
(_a = m.fitObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
6970
|
+
m.fitObserver = null;
|
|
6971
|
+
m.content.replaceChildren(node);
|
|
6972
|
+
m.content.style.display = "block";
|
|
7108
6973
|
}
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
6974
|
+
/**
|
|
6975
|
+
* Destroy the warm signer iframe if one is currently mounted for `origin`, and report
|
|
6976
|
+
* whether there was one. Logout needs this: a signing session can live in that document's
|
|
6977
|
+
* MEMORY (the signer keeps an in-memory mirror when the browser blocks its storage), and a
|
|
6978
|
+
* throwaway iframe opened by the sweep can only ever clear the shared store, never another
|
|
6979
|
+
* document's memory. Removing the iframe discards its browsing context, which takes the
|
|
6980
|
+
* mirror with it.
|
|
6981
|
+
*
|
|
6982
|
+
* Deliberately does NOT call getModal(): that would BUILD a modal just to tear it down, on
|
|
6983
|
+
* every logout of every app, most of which never mounted one.
|
|
6984
|
+
*/
|
|
6985
|
+
function detachWarmSignerIframe(origin) {
|
|
6986
|
+
if (!modal || !modal.iframe || modal.iframeOrigin !== origin)
|
|
6987
|
+
return false;
|
|
6988
|
+
detachIframe(modal);
|
|
6989
|
+
return true;
|
|
7115
6990
|
}
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
const lastUser = currentUser;
|
|
7124
|
-
const wasInitializedBefore = hasRunFirstTime;
|
|
7125
|
-
const lastPrincipal = userPrincipalKey(currentUser);
|
|
7126
|
-
const nextPrincipal = userPrincipalKey(user);
|
|
7127
|
-
const shouldRunListeners = !hasRunFirstTime || lastPrincipal !== nextPrincipal;
|
|
7128
|
-
hasRunFirstTime = true;
|
|
7129
|
-
currentUser = user;
|
|
7130
|
-
if (shouldRunListeners) {
|
|
7131
|
-
// Isolate each listener: a consumer callback that throws (during logout in
|
|
7132
|
-
// particular) must not abort the notification loop OR skip the socket reopen
|
|
7133
|
-
// below. Before this, a single throwing listener propagated out of
|
|
7134
|
-
// setCurrentUser, so the realtime socket kept streaming as the signed-out
|
|
7135
|
-
// user and the other listeners were never told the principal changed.
|
|
7136
|
-
authStateListeners.forEach((callback) => {
|
|
7137
|
-
try {
|
|
7138
|
-
callback(user);
|
|
7139
|
-
}
|
|
7140
|
-
catch (error) {
|
|
7141
|
-
console.error('Error in onAuthStateChanged listener:', error);
|
|
7142
|
-
}
|
|
7143
|
-
});
|
|
7144
|
-
// Reconnect WebSocket connections with new auth when user changes.
|
|
7145
|
-
// Skip on the first setCurrentUser call during init() — there are no
|
|
7146
|
-
// existing connections to reconnect at that point.
|
|
7147
|
-
if (wasInitializedBefore && userPrincipalKey(lastUser) !== nextPrincipal) {
|
|
7148
|
-
reconnectWithNewAuth().catch((error) => {
|
|
7149
|
-
console.error('Error reconnecting WebSocket after auth change:', error);
|
|
7150
|
-
});
|
|
6991
|
+
function detachIframe(m) {
|
|
6992
|
+
if (m.iframe) {
|
|
6993
|
+
try {
|
|
6994
|
+
m.iframe.remove();
|
|
6995
|
+
}
|
|
6996
|
+
catch (_a) {
|
|
6997
|
+
/* ignore */
|
|
7151
6998
|
}
|
|
7152
6999
|
}
|
|
7153
|
-
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
function getCurrentUser() {
|
|
7158
|
-
return currentUser;
|
|
7159
|
-
}
|
|
7160
|
-
/** @internal Snapshot/restore surface for transactional auth-provider switches. */
|
|
7161
|
-
function getAuthProviderInstance() {
|
|
7162
|
-
return authProviderInstance;
|
|
7000
|
+
m.iframe = null;
|
|
7001
|
+
m.iframeReady = false;
|
|
7002
|
+
m.iframeOrigin = "";
|
|
7003
|
+
m.onIframeMessage = null;
|
|
7163
7004
|
}
|
|
7164
|
-
|
|
7165
|
-
|
|
7005
|
+
// Load the Bounded editorial typefaces (Newsreader display + Schibsted Grotesk body +
|
|
7006
|
+
// JetBrains Mono) once at the document level so they apply inside the shadow root. A
|
|
7007
|
+
// no-op if already present or off-DOM. Fonts loaded here match the hosted auth page.
|
|
7008
|
+
const FONTS_HREF = "https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght@6..72,400;6..72,500&family=Schibsted+Grotesk:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap";
|
|
7009
|
+
function ensureFonts() {
|
|
7010
|
+
if (!hasDOM$2())
|
|
7011
|
+
return;
|
|
7012
|
+
if (document.querySelector('link[data-bounded-fonts="1"]'))
|
|
7013
|
+
return;
|
|
7014
|
+
const pre1 = document.createElement("link");
|
|
7015
|
+
pre1.rel = "preconnect";
|
|
7016
|
+
pre1.href = "https://fonts.googleapis.com";
|
|
7017
|
+
const pre2 = document.createElement("link");
|
|
7018
|
+
pre2.rel = "preconnect";
|
|
7019
|
+
pre2.href = "https://fonts.gstatic.com";
|
|
7020
|
+
pre2.crossOrigin = "anonymous";
|
|
7021
|
+
const link = document.createElement("link");
|
|
7022
|
+
link.rel = "stylesheet";
|
|
7023
|
+
link.href = FONTS_HREF;
|
|
7024
|
+
link.setAttribute("data-bounded-fonts", "1");
|
|
7025
|
+
document.head.append(pre1, pre2, link);
|
|
7166
7026
|
}
|
|
7167
7027
|
|
|
7028
|
+
var boundedWidgetModal = /*#__PURE__*/Object.freeze({
|
|
7029
|
+
__proto__: null,
|
|
7030
|
+
detachIframe: detachIframe,
|
|
7031
|
+
detachWarmSignerIframe: detachWarmSignerIframe,
|
|
7032
|
+
ensureFonts: ensureFonts,
|
|
7033
|
+
fitPanelToContent: fitPanelToContent,
|
|
7034
|
+
getModal: getModal,
|
|
7035
|
+
hasDOM: hasDOM$2,
|
|
7036
|
+
hideModal: hideModal,
|
|
7037
|
+
mountContent: mountContent,
|
|
7038
|
+
setPanelHeight: setPanelHeight,
|
|
7039
|
+
showModal: showModal
|
|
7040
|
+
});
|
|
7041
|
+
|
|
7168
7042
|
// bounded-widget-ownership.ts - per-open ownership generation for the singleton
|
|
7169
7043
|
// login/signing modal (bounded-widget-modal.ts).
|
|
7170
7044
|
//
|
|
@@ -7605,72 +7479,11 @@ function shouldOfferSolanaMobileWallet(input) {
|
|
|
7605
7479
|
function hasDOM$1() {
|
|
7606
7480
|
return typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
7607
7481
|
}
|
|
7608
|
-
let requestSeq = 0;
|
|
7609
|
-
// Seal the OTP in the given hidden signer iframe on the Bounded origin. The signer page
|
|
7610
|
-
// runs the vendored @turnkey/crypto encryptOtpCodeToBundle (which verifies the enclave's
|
|
7611
|
-
// signature on the target bundle first) and KEEPS the sealing keypair for the follow-up
|
|
7612
|
-
// establishSigningSession exchange below.
|
|
7613
|
-
async function sealOtpInFrame(frame, code, otpEncryptionTargetBundle) {
|
|
7614
|
-
const d = await frame.request({
|
|
7615
|
-
type: 'bounded:turnkey:encryptOtp',
|
|
7616
|
-
requestId: `tkotp_${Date.now()}_${++requestSeq}`,
|
|
7617
|
-
otpCode: code,
|
|
7618
|
-
otpEncryptionTargetBundle,
|
|
7619
|
-
}, 30000).catch(() => { throw new Error('Securing the code timed out. Please try again.'); });
|
|
7620
|
-
if (d.ok && typeof d.encryptedOtpBundle === 'string' && d.encryptedOtpBundle) {
|
|
7621
|
-
return d.encryptedOtpBundle;
|
|
7622
|
-
}
|
|
7623
|
-
throw new Error(String(d.error || 'Could not secure the code. Please try again.'));
|
|
7624
|
-
}
|
|
7625
|
-
// Best-effort login-time signing-session establishment. Runs AFTER the login session is
|
|
7626
|
-
// live (the action authorization is minted from the freshly-established id token) against
|
|
7627
|
-
// the SAME frame that sealed the code - only that page instance holds the keypair the
|
|
7628
|
-
// verificationToken is bound to. Owns the frame: disposes it whatever happens. Never
|
|
7629
|
-
// throws; a failure only means the first signature costs one inline code.
|
|
7630
|
-
async function establishSigningSessionInBackground(frame, baseUrl, signingSession) {
|
|
7631
|
-
// The moment this work begins - captured before ANY await, because verify() has already
|
|
7632
|
-
// resolved and the user can hit logout throughout the authorization mint below. The
|
|
7633
|
-
// signer drops a session whose work began at-or-before the newest logout, so a stamp
|
|
7634
|
-
// taken later (in the frame, after the mint) would let this establishment out-run a
|
|
7635
|
-
// logout and resurrect the session.
|
|
7636
|
-
const startedAtMs = Date.now();
|
|
7637
|
-
try {
|
|
7638
|
-
let idToken = null;
|
|
7639
|
-
try {
|
|
7640
|
-
idToken = getActiveSessionManager().getIdToken();
|
|
7641
|
-
}
|
|
7642
|
-
catch (_a) {
|
|
7643
|
-
idToken = null;
|
|
7644
|
-
}
|
|
7645
|
-
if (!idToken)
|
|
7646
|
-
return;
|
|
7647
|
-
const authorization = await requestTurnkeyActionAuthorization({
|
|
7648
|
-
baseUrl,
|
|
7649
|
-
idToken,
|
|
7650
|
-
action: 'createWallet',
|
|
7651
|
-
fetchImpl: (url, init) => fetch(url, init),
|
|
7652
|
-
});
|
|
7653
|
-
const d = await frame.request({
|
|
7654
|
-
type: 'bounded:turnkey:establishSigningSession',
|
|
7655
|
-
requestId: `tkestablish_${Date.now()}_${++requestSeq}`,
|
|
7656
|
-
verificationToken: signingSession.verificationToken,
|
|
7657
|
-
authorization,
|
|
7658
|
-
startedAtMs,
|
|
7659
|
-
}, 20000);
|
|
7660
|
-
if (!d.ok)
|
|
7661
|
-
throw new Error(String(d.error || 'establish_failed'));
|
|
7662
|
-
}
|
|
7663
|
-
catch (_b) {
|
|
7664
|
-
/* best-effort: the signer's inline code flow covers the first signature */
|
|
7665
|
-
}
|
|
7666
|
-
finally {
|
|
7667
|
-
frame.dispose();
|
|
7668
|
-
}
|
|
7669
|
-
}
|
|
7670
7482
|
/**
|
|
7671
|
-
* Begin authMode:"turnkey" login: ask Turnkey to email a one-time code to `email
|
|
7672
|
-
* Resolves with a handle whose `
|
|
7673
|
-
*
|
|
7483
|
+
* Begin authMode:"turnkey" login: ask Turnkey to email a one-time code to `email`, and open a
|
|
7484
|
+
* server-bound login ceremony. Resolves with a handle whose `run(iframe)` finishes the login inside
|
|
7485
|
+
* the Bounded OTP frame. Web-only (the sealing runs in the frame); on React Native use
|
|
7486
|
+
* loginWithRedirect() instead.
|
|
7674
7487
|
*/
|
|
7675
7488
|
async function startTurnkeyEmailLogin(email) {
|
|
7676
7489
|
if (!hasDOM$1()) {
|
|
@@ -7693,51 +7506,120 @@ async function startTurnkeyEmailLogin(email) {
|
|
|
7693
7506
|
}
|
|
7694
7507
|
const otpId = data.otpId;
|
|
7695
7508
|
const otpEncryptionTargetBundle = data.otpEncryptionTargetBundle;
|
|
7509
|
+
// A tenant-origin login always gets a ceremony id; without one the OTP frame refuses to run
|
|
7510
|
+
// (there is nothing to bind the frame key to), which is the correct fail-closed posture.
|
|
7511
|
+
const ceremonyId = typeof data.ceremonyId === 'string' ? data.ceremonyId : '';
|
|
7512
|
+
const signerOrigin = new URL(base).origin;
|
|
7696
7513
|
return {
|
|
7697
7514
|
email: trimmed,
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
|
|
7706
|
-
|
|
7707
|
-
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
|
|
7714
|
-
|
|
7715
|
-
|
|
7515
|
+
run(iframe) {
|
|
7516
|
+
if (!ceremonyId) {
|
|
7517
|
+
return Promise.reject(new Error('This app is not configured for in-frame wallet login. Please try again.'));
|
|
7518
|
+
}
|
|
7519
|
+
return runOtpFrame({ iframe, base, signerOrigin, appId, email: trimmed, otpId, otpEncryptionTargetBundle, ceremonyId });
|
|
7520
|
+
},
|
|
7521
|
+
};
|
|
7522
|
+
}
|
|
7523
|
+
// Point the iframe at the Bounded OTP frame and run the postMessage handshake:
|
|
7524
|
+
// frame 'ready' -> we post {otpId, targetBundle}; frame registers its key + shows the input;
|
|
7525
|
+
// frame 'result' {session} -> we establish the inline session and resolve the User.
|
|
7526
|
+
// When the frame asks for the signing-session authorization ('need-authorization') we mint a
|
|
7527
|
+
// createWallet action authorization on THIS (registered) origin and post it in - never a key.
|
|
7528
|
+
function runOtpFrame(run) {
|
|
7529
|
+
const tenantOrigin = window.location.origin;
|
|
7530
|
+
const url = `${run.base.replace(/\/$/, '')}/wallet/turnkey/otp-frame`
|
|
7531
|
+
+ `?appId=${encodeURIComponent(run.appId)}`
|
|
7532
|
+
+ `&origin=${encodeURIComponent(tenantOrigin)}`
|
|
7533
|
+
+ `&email=${encodeURIComponent(run.email)}`
|
|
7534
|
+
+ `&ceremonyId=${encodeURIComponent(run.ceremonyId)}`;
|
|
7535
|
+
return new Promise((resolve, reject) => {
|
|
7536
|
+
let settled = false;
|
|
7537
|
+
let started = false;
|
|
7538
|
+
const cleanup = () => { settled = true; window.removeEventListener('message', onMsg); window.clearTimeout(timer); };
|
|
7539
|
+
const onMsg = async (event) => {
|
|
7540
|
+
if (settled)
|
|
7541
|
+
return;
|
|
7542
|
+
// Trust ONLY the signer origin and the frame's own window.
|
|
7543
|
+
if (event.origin !== run.signerOrigin || event.source !== run.iframe.contentWindow)
|
|
7544
|
+
return;
|
|
7545
|
+
const d = event.data;
|
|
7546
|
+
if (!d || typeof d !== 'object')
|
|
7547
|
+
return;
|
|
7548
|
+
if (d.type === 'bounded:otp:resize') {
|
|
7549
|
+
if (typeof d.height === 'number' && Number.isFinite(d.height) && d.height > 0) {
|
|
7550
|
+
run.iframe.style.height = `${Math.max(140, Math.min(680, Math.ceil(d.height)))}px`;
|
|
7716
7551
|
}
|
|
7552
|
+
return;
|
|
7717
7553
|
}
|
|
7718
|
-
|
|
7719
|
-
|
|
7720
|
-
|
|
7554
|
+
if (d.type === 'bounded:otp:ready') {
|
|
7555
|
+
if (started)
|
|
7556
|
+
return;
|
|
7557
|
+
started = true;
|
|
7558
|
+
post({ type: 'bounded:otp:start', otpId: run.otpId, otpEncryptionTargetBundle: run.otpEncryptionTargetBundle });
|
|
7559
|
+
return;
|
|
7721
7560
|
}
|
|
7722
|
-
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
|
|
7728
|
-
|
|
7729
|
-
|
|
7730
|
-
|
|
7731
|
-
|
|
7732
|
-
|
|
7733
|
-
|
|
7561
|
+
if (d.type === 'bounded:otp:need-authorization') {
|
|
7562
|
+
// Best-effort: mint the createWallet authorization on our own registered origin and hand it
|
|
7563
|
+
// to the frame so it can complete the 24h signing session with the key it holds. Never throws.
|
|
7564
|
+
try {
|
|
7565
|
+
let idToken = null;
|
|
7566
|
+
try {
|
|
7567
|
+
idToken = getActiveSessionManager().getIdToken();
|
|
7568
|
+
}
|
|
7569
|
+
catch (_a) {
|
|
7570
|
+
idToken = null;
|
|
7571
|
+
}
|
|
7572
|
+
if (!idToken) {
|
|
7573
|
+
post({ type: 'bounded:otp:authorization', authorization: '' });
|
|
7574
|
+
return;
|
|
7575
|
+
}
|
|
7576
|
+
const authorization = await requestTurnkeyActionAuthorization({
|
|
7577
|
+
baseUrl: run.base, idToken, action: 'createWallet', fetchImpl: (u, i) => fetch(u, i),
|
|
7578
|
+
});
|
|
7579
|
+
post({ type: 'bounded:otp:authorization', authorization });
|
|
7580
|
+
}
|
|
7581
|
+
catch (_b) {
|
|
7582
|
+
post({ type: 'bounded:otp:authorization', authorization: '' });
|
|
7583
|
+
}
|
|
7584
|
+
return;
|
|
7734
7585
|
}
|
|
7735
|
-
|
|
7736
|
-
|
|
7586
|
+
if (d.type === 'bounded:otp:result') {
|
|
7587
|
+
if (d.ok && d.session && typeof d.session === 'object') {
|
|
7588
|
+
try {
|
|
7589
|
+
const user = await establishInlineSession(d.session);
|
|
7590
|
+
cleanup();
|
|
7591
|
+
resolve(user);
|
|
7592
|
+
}
|
|
7593
|
+
catch (error) {
|
|
7594
|
+
cleanup();
|
|
7595
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
7596
|
+
}
|
|
7597
|
+
return;
|
|
7598
|
+
}
|
|
7599
|
+
cleanup();
|
|
7600
|
+
reject(new Error(String((d && d.error) || 'Invalid or expired code.')));
|
|
7601
|
+
return;
|
|
7737
7602
|
}
|
|
7738
|
-
|
|
7739
|
-
}
|
|
7740
|
-
|
|
7603
|
+
// 'bounded:otp:registered' is advisory; login does not depend on it.
|
|
7604
|
+
};
|
|
7605
|
+
const post = (msg) => {
|
|
7606
|
+
var _a;
|
|
7607
|
+
try {
|
|
7608
|
+
(_a = run.iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage(msg, run.signerOrigin);
|
|
7609
|
+
}
|
|
7610
|
+
catch ( /* frame gone */_b) { /* frame gone */ }
|
|
7611
|
+
};
|
|
7612
|
+
window.addEventListener('message', onMsg);
|
|
7613
|
+
// 3 minutes: the human must read the email and type the code. A frame that never reports is a
|
|
7614
|
+
// failed login the user can retry.
|
|
7615
|
+
const timer = window.setTimeout(() => {
|
|
7616
|
+
if (settled)
|
|
7617
|
+
return;
|
|
7618
|
+
cleanup();
|
|
7619
|
+
reject(new Error('The sign-in code entry timed out. Please try again.'));
|
|
7620
|
+
}, 3 * 60 * 1000);
|
|
7621
|
+
run.iframe.src = url;
|
|
7622
|
+
});
|
|
7741
7623
|
}
|
|
7742
7624
|
|
|
7743
7625
|
// bounded-login-widget.ts - the UNIFIED Bounded login surface: one in-app card
|
|
@@ -7962,7 +7844,7 @@ function untilCancelled(work, pending) {
|
|
|
7962
7844
|
* run first; call from a user gesture so social/wallet popups are allowed.
|
|
7963
7845
|
*/
|
|
7964
7846
|
async function openBoundedWidget(opts = {}) {
|
|
7965
|
-
if (!hasDOM$
|
|
7847
|
+
if (!hasDOM$2()) {
|
|
7966
7848
|
throw new Error("openBoundedWidget is web-only - on React Native use loginWithRedirect()");
|
|
7967
7849
|
}
|
|
7968
7850
|
// Registered before the first await - see PendingOpen.
|
|
@@ -8207,6 +8089,7 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8207
8089
|
m.onBackdrop = cancel;
|
|
8208
8090
|
const style = el("style");
|
|
8209
8091
|
style.textContent = CARD_CSS;
|
|
8092
|
+
let emailDraft = "";
|
|
8210
8093
|
const renderChoose = () => {
|
|
8211
8094
|
const card = el("div", "c");
|
|
8212
8095
|
card.appendChild(style.cloneNode(true));
|
|
@@ -8241,6 +8124,8 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8241
8124
|
input.autocomplete = "email";
|
|
8242
8125
|
input.placeholder = "you@example.com";
|
|
8243
8126
|
input.required = true;
|
|
8127
|
+
input.value = emailDraft;
|
|
8128
|
+
input.addEventListener("input", () => { emailDraft = input.value; });
|
|
8244
8129
|
const submit = el("button", "btn primary");
|
|
8245
8130
|
submit.type = "submit";
|
|
8246
8131
|
submit.textContent = "Continue";
|
|
@@ -8249,6 +8134,7 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8249
8134
|
e.preventDefault();
|
|
8250
8135
|
if (!input.value)
|
|
8251
8136
|
return;
|
|
8137
|
+
emailDraft = input.value;
|
|
8252
8138
|
// Starting another lane takes the card from a wallet attempt still
|
|
8253
8139
|
// preparing, and this lane holds the lock until its own request
|
|
8254
8140
|
// settles - otherwise a failed email login would keep every other lane
|
|
@@ -8265,7 +8151,7 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8265
8151
|
setBusy(submit, "Sending code\u2026");
|
|
8266
8152
|
startTurnkeyEmailLogin(input.value)
|
|
8267
8153
|
.then((handle) => { if (settleAttempt(attempt))
|
|
8268
|
-
swap(
|
|
8154
|
+
swap(renderOtpFrame(handle)); })
|
|
8269
8155
|
.catch((err) => {
|
|
8270
8156
|
if (!settleAttempt(attempt))
|
|
8271
8157
|
return;
|
|
@@ -8278,6 +8164,7 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8278
8164
|
setBusy(submit, "Opening secure sign-in\u2026");
|
|
8279
8165
|
const emailOpts = {
|
|
8280
8166
|
provider: "email",
|
|
8167
|
+
prompt: "login",
|
|
8281
8168
|
loginHint: input.value,
|
|
8282
8169
|
redirectUri: opts.redirectUri,
|
|
8283
8170
|
};
|
|
@@ -8549,75 +8436,25 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8549
8436
|
card.appendChild(status);
|
|
8550
8437
|
return card;
|
|
8551
8438
|
};
|
|
8552
|
-
// authMode:"turnkey"
|
|
8553
|
-
//
|
|
8554
|
-
|
|
8439
|
+
// BSA-2026-004: authMode:"turnkey" code entry runs ENTIRELY inside a Bounded-origin OTP frame,
|
|
8440
|
+
// never in this tenant DOM. The widget only embeds that frame and reacts to its result - it
|
|
8441
|
+
// never sees the plaintext code or the sealing key. The editorial card wraps the frame so the
|
|
8442
|
+
// experience still feels native; the code input, sealing, and verify all live behind the frame.
|
|
8443
|
+
const renderOtpFrame = (handle) => {
|
|
8555
8444
|
const card = el("div", "c");
|
|
8556
8445
|
card.appendChild(style.cloneNode(true));
|
|
8557
8446
|
const back = el("button", "back", "\u2190 Back");
|
|
8558
8447
|
back.type = "button";
|
|
8559
|
-
// Abandoning the code entry settles the email attempt that opened it, so
|
|
8560
|
-
// the next lane the user picks is not refused by a claim nobody owns.
|
|
8561
|
-
back.addEventListener("click", () => { invalidateAttempts(); swap(renderChoose()); });
|
|
8562
8448
|
card.appendChild(back);
|
|
8563
|
-
card.appendChild(el("h1", undefined, "Enter your code"));
|
|
8564
|
-
card.appendChild(el("p", "sub", `We sent a 6-digit code to ${handle.email}.`));
|
|
8565
8449
|
const status = el("div", "status");
|
|
8566
8450
|
const setErr = (msg) => { status.textContent = msg; status.classList.add("err"); };
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
|
|
8570
|
-
|
|
8571
|
-
|
|
8572
|
-
|
|
8573
|
-
|
|
8574
|
-
input.inputMode = "numeric";
|
|
8575
|
-
input.autocomplete = "one-time-code";
|
|
8576
|
-
input.maxLength = 6;
|
|
8577
|
-
input.placeholder = "000000";
|
|
8578
|
-
input.required = true;
|
|
8579
|
-
const submit = el("button", "btn primary");
|
|
8580
|
-
submit.type = "submit";
|
|
8581
|
-
submit.textContent = "Verify";
|
|
8582
|
-
form.append(label, input, submit);
|
|
8583
|
-
const verify = () => {
|
|
8584
|
-
const code = input.value.replace(/\D+/g, "");
|
|
8585
|
-
if (code.length < 6) {
|
|
8586
|
-
setErr("Enter the 6-digit code.");
|
|
8587
|
-
return;
|
|
8588
|
-
}
|
|
8589
|
-
// Verifying MINTS a session, so it takes the lock like every other lane.
|
|
8590
|
-
const attempt = beginAttempt();
|
|
8591
|
-
if (attempt === null) {
|
|
8592
|
-
setErr(BUSY_MSG);
|
|
8593
|
-
return;
|
|
8594
|
-
}
|
|
8595
|
-
status.classList.remove("err");
|
|
8596
|
-
status.textContent = "";
|
|
8597
|
-
submit.disabled = true;
|
|
8598
|
-
input.disabled = true;
|
|
8599
|
-
submit.replaceChildren(el("span", "spin"), document.createTextNode("Verifying\u2026"));
|
|
8600
|
-
handle
|
|
8601
|
-
.verify(code)
|
|
8602
|
-
.then((u) => { settleAttempt(attempt); succeed(u); })
|
|
8603
|
-
.catch((err) => {
|
|
8604
|
-
if (!settleAttempt(attempt))
|
|
8605
|
-
return;
|
|
8606
|
-
submit.disabled = false;
|
|
8607
|
-
input.disabled = false;
|
|
8608
|
-
submit.textContent = "Verify";
|
|
8609
|
-
input.value = "";
|
|
8610
|
-
input.focus();
|
|
8611
|
-
setErr(errText(err));
|
|
8612
|
-
});
|
|
8613
|
-
};
|
|
8614
|
-
form.addEventListener("submit", (e) => { e.preventDefault(); verify(); });
|
|
8615
|
-
// Auto-submit once six digits are in - the buttery one-shot paste/type path.
|
|
8616
|
-
input.addEventListener("input", () => {
|
|
8617
|
-
if (input.value.replace(/\D+/g, "").length === 6 && !submit.disabled)
|
|
8618
|
-
verify();
|
|
8619
|
-
});
|
|
8620
|
-
card.appendChild(form);
|
|
8451
|
+
// The Bounded-origin OTP frame. Its route restricts frame-ancestors to this exact origin, so
|
|
8452
|
+
// only this app may embed it; the code + the P-256 key never leave it into this realm.
|
|
8453
|
+
// Its trusted resize messages fit the heading, input, and any error copy.
|
|
8454
|
+
const frame = document.createElement("iframe");
|
|
8455
|
+
frame.setAttribute("title", "Enter your code");
|
|
8456
|
+
frame.style.cssText = "width:100%;height:210px;border:0;background:transparent;color-scheme:dark";
|
|
8457
|
+
card.appendChild(frame);
|
|
8621
8458
|
card.appendChild(status);
|
|
8622
8459
|
const foot = el("div", "foot");
|
|
8623
8460
|
const poweredBy = el("a", undefined, "Powered by Bounded");
|
|
@@ -8626,7 +8463,22 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8626
8463
|
poweredBy.rel = "noopener";
|
|
8627
8464
|
foot.appendChild(poweredBy);
|
|
8628
8465
|
card.appendChild(foot);
|
|
8629
|
-
|
|
8466
|
+
// Running the frame MINTS a session, so it takes the lock like every other lane. Abandoning
|
|
8467
|
+
// via Back settles it so the next lane the user picks is not refused by a claim nobody owns.
|
|
8468
|
+
const attempt = beginAttempt();
|
|
8469
|
+
if (attempt === null) {
|
|
8470
|
+
setErr(BUSY_MSG);
|
|
8471
|
+
return card;
|
|
8472
|
+
}
|
|
8473
|
+
back.addEventListener("click", () => { settleAttempt(attempt); invalidateAttempts(); swap(renderChoose()); });
|
|
8474
|
+
handle
|
|
8475
|
+
.run(frame)
|
|
8476
|
+
.then((u) => { settleAttempt(attempt); succeed(u); })
|
|
8477
|
+
.catch((err) => {
|
|
8478
|
+
if (!settleAttempt(attempt))
|
|
8479
|
+
return;
|
|
8480
|
+
setErr(errText(err));
|
|
8481
|
+
});
|
|
8630
8482
|
return card;
|
|
8631
8483
|
};
|
|
8632
8484
|
const swap = (node) => {
|
|
@@ -10268,4 +10120,4 @@ function defaultInjectedEvmProvider() {
|
|
|
10268
10120
|
}
|
|
10269
10121
|
|
|
10270
10122
|
export { OffchainAuthProvider 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, loginWithPopup as J, completeLoginInPopup 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, startTurnkeyEmailLogin as U, getIdToken as V, WalletConfigError as W, onramp as X, onrampQuote as Y, onrampStatus as Z, setPlatform as _, signMessageWithTurnkey as a, PrivyExpoProvider as a0, requestEip6963Providers as a1, builds as a2, BuildsApiError as a3, NON_TERMINAL_STATES as a4, TERMINAL_STATES as a5, RUN_STATES as a6, PARK_REASONS as a7, FAILURE_REASONS as a8, BUILD_REVIEW_CAPABILITY_SCHEMA as a9, BUILD_REVIEW_CAPABILITY_REFRESH_SCHEMA as aa, BUILD_DELEGATED_REVIEW_CAPABILITY_SCHEMA as ab, 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 };
|
|
10271
|
-
//# sourceMappingURL=index-
|
|
10123
|
+
//# sourceMappingURL=index-Cflemdaf.mjs.map
|