@bounded-sh/client 0.0.97 → 0.0.99
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 +7 -2
- package/dist/auth/oidc-auth.d.ts +1 -1
- package/dist/auth/session-provider.d.ts +1 -0
- package/dist/auth/turnkey-auth.d.ts +7 -1
- package/dist/auth/turnkey-signer-bridge.d.ts +8 -5
- package/dist/auth/turnkey-signer-frame.d.ts +4 -1
- package/dist/auth/turnkey-wallet-context.d.ts +24 -0
- package/dist/auth/turnkey-wallet-widget.d.ts +2 -0
- package/dist/builds/client.d.ts +5 -2
- package/dist/builds/types.d.ts +108 -1
- package/dist/{email-auth-provider-SqE5H8jv.js → email-auth-provider-62OK5X30.js} +2 -2
- package/dist/{email-auth-provider-SqE5H8jv.js.map → email-auth-provider-62OK5X30.js.map} +1 -1
- package/dist/{email-auth-provider-DbBN1MXS.mjs → email-auth-provider-BKYVi3dl.mjs} +2 -2
- package/dist/{email-auth-provider-CiPAD3vz.mjs.map → email-auth-provider-BKYVi3dl.mjs.map} +1 -1
- package/dist/{email-auth-provider-CiPAD3vz.mjs → email-auth-provider-CIRbOSM3.mjs} +2 -2
- package/dist/{email-auth-provider-DbBN1MXS.mjs.map → email-auth-provider-CIRbOSM3.mjs.map} +1 -1
- package/dist/{email-auth-provider-BhYzRN0r.js → email-auth-provider-Cpj8hIFu.js} +2 -2
- package/dist/{email-auth-provider-BhYzRN0r.js.map → email-auth-provider-Cpj8hIFu.js.map} +1 -1
- package/dist/{guest-auth-provider-BiM35KHb.js → guest-auth-provider-0PjGFGDm.js} +2 -2
- package/dist/{guest-auth-provider-BiM35KHb.js.map → guest-auth-provider-0PjGFGDm.js.map} +1 -1
- package/dist/{guest-auth-provider-JE0zdREA.js → guest-auth-provider-B6dJixRm.js} +2 -2
- package/dist/{guest-auth-provider-JE0zdREA.js.map → guest-auth-provider-B6dJixRm.js.map} +1 -1
- package/dist/{guest-auth-provider-Dtsq4QaY.mjs → guest-auth-provider-C23vWrOT.mjs} +2 -2
- package/dist/{guest-auth-provider-KCalcsKu.mjs.map → guest-auth-provider-C23vWrOT.mjs.map} +1 -1
- package/dist/{guest-auth-provider-KCalcsKu.mjs → guest-auth-provider-E7Fg7-E2.mjs} +2 -2
- package/dist/{guest-auth-provider-Dtsq4QaY.mjs.map → guest-auth-provider-E7Fg7-E2.mjs.map} +1 -1
- package/dist/{index-Bb7I-AoO.js → index-BrU_tGd-.js} +1159 -600
- package/dist/index-BrU_tGd-.js.map +1 -0
- package/dist/{index-C01Q7k1A.mjs → index-l5E4pjpt.mjs} +1156 -601
- package/dist/index-l5E4pjpt.mjs.map +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{index.native-BZOWS_sR.js → index.native-CllNqdoy.js} +442 -81
- package/dist/index.native-CllNqdoy.js.map +1 -0
- package/dist/{index.native-gVbAsohv.mjs → index.native-r1I-9E8e.mjs} +442 -81
- package/dist/index.native-r1I-9E8e.mjs.map +1 -0
- package/dist/index.native.js +1 -1
- package/dist/index.native.mjs +1 -1
- package/dist/{injected-evm-wallet-provider-C3MwUTRd.js → injected-evm-wallet-provider-BXM8TfS3.js} +2 -2
- package/dist/{injected-evm-wallet-provider-C3MwUTRd.js.map → injected-evm-wallet-provider-BXM8TfS3.js.map} +1 -1
- package/dist/{injected-evm-wallet-provider-DIMM0HdQ.mjs → injected-evm-wallet-provider-BmDPRV5L.mjs} +2 -2
- package/dist/{injected-evm-wallet-provider-DIMM0HdQ.mjs.map → injected-evm-wallet-provider-BmDPRV5L.mjs.map} +1 -1
- package/dist/{injected-evm-wallet-provider-ZrxW8UES.js → injected-evm-wallet-provider-CO_aC4TY.js} +2 -2
- package/dist/{injected-evm-wallet-provider-ZrxW8UES.js.map → injected-evm-wallet-provider-CO_aC4TY.js.map} +1 -1
- package/dist/{injected-evm-wallet-provider-K0j697jt.mjs → injected-evm-wallet-provider-CkhN5u3d.mjs} +2 -2
- package/dist/{injected-evm-wallet-provider-K0j697jt.mjs.map → injected-evm-wallet-provider-CkhN5u3d.mjs.map} +1 -1
- package/dist/{injected-wallet-provider-CDl-az6P.js → injected-wallet-provider-B9eU7t8o.js} +2 -2
- package/dist/{injected-wallet-provider-CDl-az6P.js.map → injected-wallet-provider-B9eU7t8o.js.map} +1 -1
- package/dist/{injected-wallet-provider-CG3oKdp_.js → injected-wallet-provider-Bi_mB_q3.js} +2 -2
- package/dist/{injected-wallet-provider-CG3oKdp_.js.map → injected-wallet-provider-Bi_mB_q3.js.map} +1 -1
- package/dist/{injected-wallet-provider-DH8yLpyf.mjs → injected-wallet-provider-BlSdRbgq.mjs} +2 -2
- package/dist/{injected-wallet-provider-DH8yLpyf.mjs.map → injected-wallet-provider-BlSdRbgq.mjs.map} +1 -1
- package/dist/{injected-wallet-provider-DCaT1pKl.mjs → injected-wallet-provider-yl51pLBa.mjs} +2 -2
- package/dist/{injected-wallet-provider-DCaT1pKl.mjs.map → injected-wallet-provider-yl51pLBa.mjs.map} +1 -1
- package/dist/services/broadcast.d.ts +28 -0
- package/dist/services/session.d.ts +28 -0
- package/package.json +7 -3
- package/dist/bounded-widget-modal-C0Z7gmxH.mjs +0 -31
- package/dist/bounded-widget-modal-C0Z7gmxH.mjs.map +0 -1
- package/dist/bounded-widget-modal-s0PL86Y-.js +0 -33
- package/dist/bounded-widget-modal-s0PL86Y-.js.map +0 -1
- package/dist/index-Bb7I-AoO.js.map +0 -1
- package/dist/index-C01Q7k1A.mjs.map +0 -1
- package/dist/index.native-BZOWS_sR.js.map +0 -1
- package/dist/index.native-gVbAsohv.mjs.map +0 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface BroadcastTicket {
|
|
2
|
+
url: string;
|
|
3
|
+
token: string;
|
|
4
|
+
expiresAt: number;
|
|
5
|
+
broadcastId: string;
|
|
6
|
+
transport: "webrtc-broadcast";
|
|
7
|
+
role: "publisher" | "listener";
|
|
8
|
+
maxSeconds: number;
|
|
9
|
+
}
|
|
10
|
+
export interface BroadcastConnection {
|
|
11
|
+
/** Resolves when local media stops, independently of delayed settlement. */
|
|
12
|
+
readonly closed: Promise<void>;
|
|
13
|
+
/** Stops this connection immediately; server billing reconciles asynchronously. */
|
|
14
|
+
close(): Promise<void>;
|
|
15
|
+
status(): Promise<{
|
|
16
|
+
state: string;
|
|
17
|
+
chargedMicroUsd: number | null;
|
|
18
|
+
egressBytes: number | null;
|
|
19
|
+
}>;
|
|
20
|
+
}
|
|
21
|
+
/** Admission comes from an app-authenticated function invoking the Cloudflare
|
|
22
|
+
* broadcast connector. No application membership is managed by this helper. */
|
|
23
|
+
export declare function connectBroadcast(ticket: BroadcastTicket, options: {
|
|
24
|
+
microphone?: MediaStream;
|
|
25
|
+
assistant?: MediaStream;
|
|
26
|
+
audio?: [HTMLAudioElement, HTMLAudioElement];
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
}): Promise<BroadcastConnection>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** One-use admission capability returned by ctx.services.invoke. Do not log it. */
|
|
2
|
+
export interface ServiceSessionTicket {
|
|
3
|
+
url: string;
|
|
4
|
+
token: string;
|
|
5
|
+
expiresAt: number;
|
|
6
|
+
transport: "webrtc-session";
|
|
7
|
+
maxSeconds: number;
|
|
8
|
+
}
|
|
9
|
+
export interface ServiceSessionReceipt {
|
|
10
|
+
seconds: number;
|
|
11
|
+
chargedMicroUsd: number;
|
|
12
|
+
finalUsage: true;
|
|
13
|
+
}
|
|
14
|
+
export interface ServiceSession {
|
|
15
|
+
/** Assistant audio received from the provider, available for opt-in broadcast. */
|
|
16
|
+
readonly audioStream: MediaStream;
|
|
17
|
+
send(event: Record<string, unknown>): void;
|
|
18
|
+
close(): Promise<ServiceSessionReceipt>;
|
|
19
|
+
readonly closed: Promise<ServiceSessionReceipt>;
|
|
20
|
+
}
|
|
21
|
+
/** Attach browser media directly to the connector's provider. Bounded observes
|
|
22
|
+
* usage independently; data-channel messages never count as billing receipts. */
|
|
23
|
+
export declare function connectServiceSession(ticket: ServiceSessionTicket, options: {
|
|
24
|
+
stream: MediaStream;
|
|
25
|
+
audio: HTMLAudioElement;
|
|
26
|
+
onEvent?: (event: Record<string, any>) => void;
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
}): Promise<ServiceSession>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bounded-sh/client",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.99",
|
|
4
4
|
"description": "Web and React Native client SDK for Bounded, the full-stack app builder and runtime for AI-built apps: hosted auth, policy-enforced data, files and search, functions, realtime subscriptions, and atomic writes.",
|
|
5
5
|
"homepage": "https://bounded.sh/docs/sdk",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
"vite": "7.3.5"
|
|
116
116
|
},
|
|
117
117
|
"dependencies": {
|
|
118
|
-
"@bounded-sh/core": "0.0.
|
|
118
|
+
"@bounded-sh/core": "0.0.99",
|
|
119
119
|
"@coral-xyz/anchor": "0.31.1",
|
|
120
120
|
"@noble/curves": "^1.9.7",
|
|
121
121
|
"@solana/kit": "8.2.0",
|
|
@@ -129,8 +129,12 @@
|
|
|
129
129
|
"rpc-websockets": "9.3.9",
|
|
130
130
|
"ws": "^8.21.0"
|
|
131
131
|
},
|
|
132
|
+
"overrides": {
|
|
133
|
+
"toml": "4.2.0"
|
|
134
|
+
},
|
|
132
135
|
"resolutions": {
|
|
133
|
-
"@bounded-sh/core": "portal:../tarobase-core"
|
|
136
|
+
"@bounded-sh/core": "portal:../tarobase-core",
|
|
137
|
+
"toml": "npm:4.2.0"
|
|
134
138
|
},
|
|
135
139
|
"packageManager": "yarn@4.17.1+sha512.ccbfabf7d7b6b32075088be9386fb9a2e00bb6887ef07fa56effabc890a56d53da1ccc4128d62db245fcbd3961b236d75335bdf7d5320ed6eafb7588b7ad4697",
|
|
136
140
|
"publishConfig": {
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
// bounded-widget-modal.ts - the shared in-app WIDGET shell for Bounded's login
|
|
2
|
-
// and signing surfaces. One Shadow-DOM overlay + panel that matches the Bounded
|
|
3
|
-
// widget (Seal) look and MOTION: a backdrop fade, a panel rise on desktop, a
|
|
4
|
-
// bottom-sheet on mobile, a height tween as content swaps, and a clean close.
|
|
5
|
-
//
|
|
6
|
-
// It hosts EITHER:
|
|
7
|
-
// - NATIVE content (the login card the SDK renders itself), or
|
|
8
|
-
// - an IFRAME (the Bounded-owned signer page, which must run on the single
|
|
9
|
-
// signer origin because the wallet's 24h signing session lives in that
|
|
10
|
-
// origin's storage, out of every app's reach).
|
|
11
|
-
//
|
|
12
|
-
// The modal is a warm singleton: it stays mounted (hidden) between uses so a
|
|
13
|
-
// second open - or a signature right after login - is instant and, when it is
|
|
14
|
-
// already open, a clean in-place view swap rather than a reopen.
|
|
15
|
-
/**
|
|
16
|
-
* Destroy the warm signer iframe if one is currently mounted for `origin`, and report
|
|
17
|
-
* whether there was one. Logout needs this: a signing session can live in that document's
|
|
18
|
-
* MEMORY (the signer keeps an in-memory mirror when the browser blocks its storage), and a
|
|
19
|
-
* throwaway iframe opened by the sweep can only ever clear the shared store, never another
|
|
20
|
-
* document's memory. Removing the iframe discards its browsing context, which takes the
|
|
21
|
-
* mirror with it.
|
|
22
|
-
*
|
|
23
|
-
* Deliberately does NOT call getModal(): that would BUILD a modal just to tear it down, on
|
|
24
|
-
* every logout of every app, most of which never mounted one.
|
|
25
|
-
*/
|
|
26
|
-
function detachWarmSignerIframe(origin) {
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export { detachWarmSignerIframe };
|
|
31
|
-
//# sourceMappingURL=bounded-widget-modal-C0Z7gmxH.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bounded-widget-modal-C0Z7gmxH.mjs","sources":["../.rollup-tmp/auth/bounded-widget-modal.js"],"sourcesContent":["// bounded-widget-modal.ts - the shared in-app WIDGET shell for Bounded's login\n// and signing surfaces. One Shadow-DOM overlay + panel that matches the Bounded\n// widget (Seal) look and MOTION: a backdrop fade, a panel rise on desktop, a\n// bottom-sheet on mobile, a height tween as content swaps, and a clean close.\n//\n// It hosts EITHER:\n// - NATIVE content (the login card the SDK renders itself), or\n// - an IFRAME (the Bounded-owned signer page, which must run on the single\n// signer origin because the wallet's 24h signing session lives in that\n// origin's storage, out of every app's reach).\n//\n// The modal is a warm singleton: it stays mounted (hidden) between uses so a\n// second open - or a signature right after login - is instant and, when it is\n// already open, a clean in-place view swap rather than a reopen.\nfunction hasDOM() {\n return typeof window !== \"undefined\" && typeof document !== \"undefined\";\n}\nconst OVERLAY_CSS = `\n:host{all:initial}\n*{box-sizing:border-box}\n.bw-ov{position:fixed;inset:0;z-index:2147483647;display:none;\n font-family:\"Schibsted Grotesk\",\"Helvetica Neue\",Arial,sans-serif}\n.bw-ov.mounted{display:block}\n.bw-back{position:fixed;inset:0;background:rgba(4,4,5,.62);opacity:0;\n transition:opacity .24s ease;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px)}\n.bw-wrap{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;padding:20px}\n.bw-panel{position:relative;width:420px;max-width:calc(100vw - 28px);height:280px;\n border-radius:14px;overflow:hidden;background:#0e0f11;border:1px solid rgba(232,230,222,.08);\n box-shadow:0 1px 0 rgba(232,230,222,.03) inset,0 40px 90px -45px rgba(0,0,0,.85);\n opacity:0;transform:translateY(14px) scale(.98);will-change:transform,opacity,height;\n transition:opacity .28s cubic-bezier(.2,.8,.2,1),transform .28s cubic-bezier(.2,.8,.2,1),\n height .3s cubic-bezier(.2,.8,.2,1)}\n.bw-ov.show .bw-back{opacity:1}\n.bw-ov.show .bw-panel{opacity:1;transform:none}\n.bw-ov.closing .bw-back{opacity:0}\n.bw-ov.closing .bw-panel{opacity:0;transform:translateY(12px) scale(.99)}\n.bw-content{position:absolute;inset:0;overflow:hidden}\n.bw-frame{display:block;width:100%;height:100%;border:0;background:transparent;color-scheme:dark}\n/* editorial corner crop-marks, matching the reference frame */\n.bw-mk{position:absolute;width:13px;height:13px;pointer-events:none;z-index:2;\n border-color:rgba(232,230,222,.22);border-style:solid;border-width:0}\n.bw-mk.tl{top:11px;left:11px;border-top-width:1px;border-left-width:1px}\n.bw-mk.tr{top:11px;right:11px;border-top-width:1px;border-right-width:1px}\n.bw-mk.bl{bottom:11px;left:11px;border-bottom-width:1px;border-left-width:1px}\n.bw-mk.br{bottom:11px;right:11px;border-bottom-width:1px;border-right-width:1px}\n@media(max-width:560px){\n .bw-wrap{align-items:flex-end;padding:0}\n .bw-panel{width:100%;max-width:100%;border-radius:18px 18px 0 0;border-bottom:0}\n .bw-content{overflow-y:auto}\n .bw-ov.show .bw-panel{transform:none}\n .bw-ov:not(.show) .bw-panel,.bw-ov.closing .bw-panel{transform:translateY(18%)}\n}\n@media(prefers-reduced-motion:reduce){.bw-back,.bw-panel{transition:opacity .12s linear!important}}\n`;\nlet modal = null;\nexport function getModal() {\n if (modal)\n return modal;\n const root = document.createElement(\"div\");\n root.setAttribute(\"data-bounded-widget\", \"\");\n const shadow = root.attachShadow({ mode: \"open\" });\n const style = document.createElement(\"style\");\n style.textContent = OVERLAY_CSS;\n shadow.appendChild(style);\n const overlay = document.createElement(\"div\");\n overlay.className = \"bw-ov\";\n const back = document.createElement(\"div\");\n back.className = \"bw-back\";\n const wrap = document.createElement(\"div\");\n wrap.className = \"bw-wrap\";\n const panel = document.createElement(\"div\");\n panel.className = \"bw-panel\";\n const content = document.createElement(\"div\");\n content.className = \"bw-content\";\n panel.appendChild(content);\n for (const corner of [\"tl\", \"tr\", \"bl\", \"br\"]) {\n const mk = document.createElement(\"span\");\n mk.className = \"bw-mk \" + corner;\n panel.appendChild(mk);\n }\n wrap.appendChild(panel);\n overlay.appendChild(back);\n overlay.appendChild(wrap);\n shadow.appendChild(overlay);\n (document.body || document.documentElement).appendChild(root);\n const m = {\n root,\n overlay,\n panel,\n content,\n iframe: null,\n iframeOrigin: \"\",\n iframeReady: false,\n onBackdrop: null,\n onIframeMessage: null,\n chain: Promise.resolve(),\n fitObserver: null,\n generation: 0,\n onSupersede: null,\n };\n // The dismiss handler lives on `.bw-wrap`: it is the full-viewport flex layer\n // that sits ABOVE `.bw-back`, so it (not the backdrop element) receives clicks\n // outside the panel. Fire only when the click lands on the wrap itself, never\n // when it bubbles up from the panel or its content.\n wrap.addEventListener(\"click\", (event) => {\n if (event.target === wrap && m.onBackdrop)\n m.onBackdrop();\n });\n window.addEventListener(\"message\", (event) => {\n if (!m.iframe)\n return;\n if (event.origin !== m.iframeOrigin)\n return;\n if (event.source !== m.iframe.contentWindow)\n return;\n const d = event.data;\n if (!d || typeof d !== \"object\")\n return;\n if (m.onIframeMessage)\n m.onIframeMessage(d);\n });\n modal = m;\n return m;\n}\nexport function modalIsMounted() {\n return !!modal && modal.overlay.classList.contains(\"mounted\");\n}\nexport function showModal(m) {\n m.overlay.classList.remove(\"closing\");\n m.overlay.classList.add(\"mounted\");\n // Force a reflow so the .show transition runs from the hidden state every open.\n void m.panel.offsetWidth;\n m.overlay.classList.add(\"show\");\n}\nexport function hideModal(m, after) {\n m.overlay.classList.remove(\"show\");\n m.overlay.classList.add(\"closing\");\n // Capture the generation at hide time. If a newer open re-shows the modal within\n // the close tween, this stale timer must NOT strip `.mounted`/`.closing` off the\n // freshly reopened widget - only tear down when we are still the same open.\n const gen = m.generation;\n window.setTimeout(() => {\n if (m.generation === gen)\n m.overlay.classList.remove(\"mounted\", \"closing\");\n if (after)\n after();\n }, 260);\n}\nexport function setPanelHeight(m, px) {\n const h = Math.max(140, Math.min(680, Math.round(px)));\n m.panel.style.height = h + \"px\";\n}\n// True outer height of the mounted card: the max of its padding-box scroll height\n// (catches overflowing descendants) and its border-box height plus own vertical\n// margins (catches border + margins, which scrollHeight omits). Ceiled so a\n// sub-pixel row is never clipped under `overflow:hidden`.\nfunction measureOuterHeight(target) {\n var _a;\n const cs = (_a = target.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.getComputedStyle(target);\n const marginY = cs ? parseFloat(cs.marginTop) + parseFloat(cs.marginBottom) : 0;\n const borderBox = target.offsetHeight + (Number.isFinite(marginY) ? marginY : 0);\n const rect = target.getBoundingClientRect().height;\n return Math.ceil(Math.max(target.scrollHeight, borderBox, rect));\n}\n/**\n * Measure the currently mounted native content and tween the panel to fit it.\n * Re-fits automatically when the card's intrinsic height changes - notably after\n * the Newsreader/Schibsted web fonts swap in (which grows line boxes a few px\n * after first paint) and on inline view swaps (email -> OTP code -> success).\n */\nexport function fitPanelToContent(m) {\n var _a, _b;\n const first = m.content.firstElementChild;\n const target = first || m.content;\n const apply = () => {\n // Only fit while this exact node is still the mounted card.\n if (m.content.firstElementChild !== first && first)\n return;\n const h = measureOuterHeight(target);\n if (h > 0)\n setPanelHeight(m, h);\n };\n apply();\n const view = target.ownerDocument.defaultView;\n // Re-fit after fonts load (one-shot) and once the ResizeObserver-less browsers\n // have painted, so the height never lags a late reflow.\n (_a = view === null || view === void 0 ? void 0 : view.requestAnimationFrame) === null || _a === void 0 ? void 0 : _a.call(view, apply);\n const fonts = target.ownerDocument.fonts;\n if (fonts === null || fonts === void 0 ? void 0 : fonts.ready)\n fonts.ready.then(apply).catch(() => { });\n (_b = m.fitObserver) === null || _b === void 0 ? void 0 : _b.disconnect();\n m.fitObserver = null;\n if (first && typeof (view === null || view === void 0 ? void 0 : view.ResizeObserver) === \"function\") {\n const ro = new view.ResizeObserver(() => apply());\n ro.observe(first);\n m.fitObserver = ro;\n }\n}\n/** Switch the modal into NATIVE-content mode: detach any iframe, mount `node`. */\nexport function mountContent(m, node) {\n var _a;\n detachIframe(m);\n (_a = m.fitObserver) === null || _a === void 0 ? void 0 : _a.disconnect();\n m.fitObserver = null;\n m.content.replaceChildren(node);\n m.content.style.display = \"block\";\n}\n/** Get (or lazily create) the warm iframe for signer/hosted-page mode. */\nexport function ensureIframe(m, url, origin) {\n var _a;\n if (m.iframe && m.iframeOrigin === origin && m.iframe.src === url)\n return m.iframe;\n detachIframe(m);\n (_a = m.fitObserver) === null || _a === void 0 ? void 0 : _a.disconnect();\n m.fitObserver = null;\n m.content.style.display = \"none\";\n const iframe = document.createElement(\"iframe\");\n iframe.className = \"bw-frame\";\n iframe.setAttribute(\"title\", \"Bounded\");\n iframe.setAttribute(\"allow\", \"clipboard-write\");\n iframe.src = url;\n m.iframeOrigin = origin;\n m.iframeReady = false;\n m.panel.appendChild(iframe);\n m.iframe = iframe;\n return iframe;\n}\n/**\n * Destroy the warm signer iframe if one is currently mounted for `origin`, and report\n * whether there was one. Logout needs this: a signing session can live in that document's\n * MEMORY (the signer keeps an in-memory mirror when the browser blocks its storage), and a\n * throwaway iframe opened by the sweep can only ever clear the shared store, never another\n * document's memory. Removing the iframe discards its browsing context, which takes the\n * mirror with it.\n *\n * Deliberately does NOT call getModal(): that would BUILD a modal just to tear it down, on\n * every logout of every app, most of which never mounted one.\n */\nexport function detachWarmSignerIframe(origin) {\n if (!modal || !modal.iframe || modal.iframeOrigin !== origin)\n return false;\n detachIframe(modal);\n return true;\n}\nexport function detachIframe(m) {\n if (m.iframe) {\n try {\n m.iframe.remove();\n }\n catch (_a) {\n /* ignore */\n }\n }\n m.iframe = null;\n m.iframeReady = false;\n m.iframeOrigin = \"\";\n m.onIframeMessage = null;\n}\n// Load the Bounded editorial typefaces (Newsreader display + Schibsted Grotesk body +\n// JetBrains Mono) once at the document level so they apply inside the shadow root. A\n// no-op if already present or off-DOM. Fonts loaded here match the hosted auth page.\nconst 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\";\nexport function ensureFonts() {\n if (!hasDOM())\n return;\n if (document.querySelector('link[data-bounded-fonts=\"1\"]'))\n return;\n const pre1 = document.createElement(\"link\");\n pre1.rel = \"preconnect\";\n pre1.href = \"https://fonts.googleapis.com\";\n const pre2 = document.createElement(\"link\");\n pre2.rel = \"preconnect\";\n pre2.href = \"https://fonts.gstatic.com\";\n pre2.crossOrigin = \"anonymous\";\n const link = document.createElement(\"link\");\n link.rel = \"stylesheet\";\n link.href = FONTS_HREF;\n link.setAttribute(\"data-bounded-fonts\", \"1\");\n document.head.append(pre1, pre2, link);\n}\nexport { hasDOM };\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAsNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,sBAAsB,CAAC,MAAM,EAAE;AAC/C,IACQ,OAAO,KAAK;AAGpB;;;;"}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// bounded-widget-modal.ts - the shared in-app WIDGET shell for Bounded's login
|
|
4
|
-
// and signing surfaces. One Shadow-DOM overlay + panel that matches the Bounded
|
|
5
|
-
// widget (Seal) look and MOTION: a backdrop fade, a panel rise on desktop, a
|
|
6
|
-
// bottom-sheet on mobile, a height tween as content swaps, and a clean close.
|
|
7
|
-
//
|
|
8
|
-
// It hosts EITHER:
|
|
9
|
-
// - NATIVE content (the login card the SDK renders itself), or
|
|
10
|
-
// - an IFRAME (the Bounded-owned signer page, which must run on the single
|
|
11
|
-
// signer origin because the wallet's 24h signing session lives in that
|
|
12
|
-
// origin's storage, out of every app's reach).
|
|
13
|
-
//
|
|
14
|
-
// The modal is a warm singleton: it stays mounted (hidden) between uses so a
|
|
15
|
-
// second open - or a signature right after login - is instant and, when it is
|
|
16
|
-
// already open, a clean in-place view swap rather than a reopen.
|
|
17
|
-
/**
|
|
18
|
-
* Destroy the warm signer iframe if one is currently mounted for `origin`, and report
|
|
19
|
-
* whether there was one. Logout needs this: a signing session can live in that document's
|
|
20
|
-
* MEMORY (the signer keeps an in-memory mirror when the browser blocks its storage), and a
|
|
21
|
-
* throwaway iframe opened by the sweep can only ever clear the shared store, never another
|
|
22
|
-
* document's memory. Removing the iframe discards its browsing context, which takes the
|
|
23
|
-
* mirror with it.
|
|
24
|
-
*
|
|
25
|
-
* Deliberately does NOT call getModal(): that would BUILD a modal just to tear it down, on
|
|
26
|
-
* every logout of every app, most of which never mounted one.
|
|
27
|
-
*/
|
|
28
|
-
function detachWarmSignerIframe(origin) {
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
exports.detachWarmSignerIframe = detachWarmSignerIframe;
|
|
33
|
-
//# sourceMappingURL=bounded-widget-modal-s0PL86Y-.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bounded-widget-modal-s0PL86Y-.js","sources":["../.rollup-tmp/auth/bounded-widget-modal.js"],"sourcesContent":["// bounded-widget-modal.ts - the shared in-app WIDGET shell for Bounded's login\n// and signing surfaces. One Shadow-DOM overlay + panel that matches the Bounded\n// widget (Seal) look and MOTION: a backdrop fade, a panel rise on desktop, a\n// bottom-sheet on mobile, a height tween as content swaps, and a clean close.\n//\n// It hosts EITHER:\n// - NATIVE content (the login card the SDK renders itself), or\n// - an IFRAME (the Bounded-owned signer page, which must run on the single\n// signer origin because the wallet's 24h signing session lives in that\n// origin's storage, out of every app's reach).\n//\n// The modal is a warm singleton: it stays mounted (hidden) between uses so a\n// second open - or a signature right after login - is instant and, when it is\n// already open, a clean in-place view swap rather than a reopen.\nfunction hasDOM() {\n return typeof window !== \"undefined\" && typeof document !== \"undefined\";\n}\nconst OVERLAY_CSS = `\n:host{all:initial}\n*{box-sizing:border-box}\n.bw-ov{position:fixed;inset:0;z-index:2147483647;display:none;\n font-family:\"Schibsted Grotesk\",\"Helvetica Neue\",Arial,sans-serif}\n.bw-ov.mounted{display:block}\n.bw-back{position:fixed;inset:0;background:rgba(4,4,5,.62);opacity:0;\n transition:opacity .24s ease;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px)}\n.bw-wrap{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;padding:20px}\n.bw-panel{position:relative;width:420px;max-width:calc(100vw - 28px);height:280px;\n border-radius:14px;overflow:hidden;background:#0e0f11;border:1px solid rgba(232,230,222,.08);\n box-shadow:0 1px 0 rgba(232,230,222,.03) inset,0 40px 90px -45px rgba(0,0,0,.85);\n opacity:0;transform:translateY(14px) scale(.98);will-change:transform,opacity,height;\n transition:opacity .28s cubic-bezier(.2,.8,.2,1),transform .28s cubic-bezier(.2,.8,.2,1),\n height .3s cubic-bezier(.2,.8,.2,1)}\n.bw-ov.show .bw-back{opacity:1}\n.bw-ov.show .bw-panel{opacity:1;transform:none}\n.bw-ov.closing .bw-back{opacity:0}\n.bw-ov.closing .bw-panel{opacity:0;transform:translateY(12px) scale(.99)}\n.bw-content{position:absolute;inset:0;overflow:hidden}\n.bw-frame{display:block;width:100%;height:100%;border:0;background:transparent;color-scheme:dark}\n/* editorial corner crop-marks, matching the reference frame */\n.bw-mk{position:absolute;width:13px;height:13px;pointer-events:none;z-index:2;\n border-color:rgba(232,230,222,.22);border-style:solid;border-width:0}\n.bw-mk.tl{top:11px;left:11px;border-top-width:1px;border-left-width:1px}\n.bw-mk.tr{top:11px;right:11px;border-top-width:1px;border-right-width:1px}\n.bw-mk.bl{bottom:11px;left:11px;border-bottom-width:1px;border-left-width:1px}\n.bw-mk.br{bottom:11px;right:11px;border-bottom-width:1px;border-right-width:1px}\n@media(max-width:560px){\n .bw-wrap{align-items:flex-end;padding:0}\n .bw-panel{width:100%;max-width:100%;border-radius:18px 18px 0 0;border-bottom:0}\n .bw-content{overflow-y:auto}\n .bw-ov.show .bw-panel{transform:none}\n .bw-ov:not(.show) .bw-panel,.bw-ov.closing .bw-panel{transform:translateY(18%)}\n}\n@media(prefers-reduced-motion:reduce){.bw-back,.bw-panel{transition:opacity .12s linear!important}}\n`;\nlet modal = null;\nexport function getModal() {\n if (modal)\n return modal;\n const root = document.createElement(\"div\");\n root.setAttribute(\"data-bounded-widget\", \"\");\n const shadow = root.attachShadow({ mode: \"open\" });\n const style = document.createElement(\"style\");\n style.textContent = OVERLAY_CSS;\n shadow.appendChild(style);\n const overlay = document.createElement(\"div\");\n overlay.className = \"bw-ov\";\n const back = document.createElement(\"div\");\n back.className = \"bw-back\";\n const wrap = document.createElement(\"div\");\n wrap.className = \"bw-wrap\";\n const panel = document.createElement(\"div\");\n panel.className = \"bw-panel\";\n const content = document.createElement(\"div\");\n content.className = \"bw-content\";\n panel.appendChild(content);\n for (const corner of [\"tl\", \"tr\", \"bl\", \"br\"]) {\n const mk = document.createElement(\"span\");\n mk.className = \"bw-mk \" + corner;\n panel.appendChild(mk);\n }\n wrap.appendChild(panel);\n overlay.appendChild(back);\n overlay.appendChild(wrap);\n shadow.appendChild(overlay);\n (document.body || document.documentElement).appendChild(root);\n const m = {\n root,\n overlay,\n panel,\n content,\n iframe: null,\n iframeOrigin: \"\",\n iframeReady: false,\n onBackdrop: null,\n onIframeMessage: null,\n chain: Promise.resolve(),\n fitObserver: null,\n generation: 0,\n onSupersede: null,\n };\n // The dismiss handler lives on `.bw-wrap`: it is the full-viewport flex layer\n // that sits ABOVE `.bw-back`, so it (not the backdrop element) receives clicks\n // outside the panel. Fire only when the click lands on the wrap itself, never\n // when it bubbles up from the panel or its content.\n wrap.addEventListener(\"click\", (event) => {\n if (event.target === wrap && m.onBackdrop)\n m.onBackdrop();\n });\n window.addEventListener(\"message\", (event) => {\n if (!m.iframe)\n return;\n if (event.origin !== m.iframeOrigin)\n return;\n if (event.source !== m.iframe.contentWindow)\n return;\n const d = event.data;\n if (!d || typeof d !== \"object\")\n return;\n if (m.onIframeMessage)\n m.onIframeMessage(d);\n });\n modal = m;\n return m;\n}\nexport function modalIsMounted() {\n return !!modal && modal.overlay.classList.contains(\"mounted\");\n}\nexport function showModal(m) {\n m.overlay.classList.remove(\"closing\");\n m.overlay.classList.add(\"mounted\");\n // Force a reflow so the .show transition runs from the hidden state every open.\n void m.panel.offsetWidth;\n m.overlay.classList.add(\"show\");\n}\nexport function hideModal(m, after) {\n m.overlay.classList.remove(\"show\");\n m.overlay.classList.add(\"closing\");\n // Capture the generation at hide time. If a newer open re-shows the modal within\n // the close tween, this stale timer must NOT strip `.mounted`/`.closing` off the\n // freshly reopened widget - only tear down when we are still the same open.\n const gen = m.generation;\n window.setTimeout(() => {\n if (m.generation === gen)\n m.overlay.classList.remove(\"mounted\", \"closing\");\n if (after)\n after();\n }, 260);\n}\nexport function setPanelHeight(m, px) {\n const h = Math.max(140, Math.min(680, Math.round(px)));\n m.panel.style.height = h + \"px\";\n}\n// True outer height of the mounted card: the max of its padding-box scroll height\n// (catches overflowing descendants) and its border-box height plus own vertical\n// margins (catches border + margins, which scrollHeight omits). Ceiled so a\n// sub-pixel row is never clipped under `overflow:hidden`.\nfunction measureOuterHeight(target) {\n var _a;\n const cs = (_a = target.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.getComputedStyle(target);\n const marginY = cs ? parseFloat(cs.marginTop) + parseFloat(cs.marginBottom) : 0;\n const borderBox = target.offsetHeight + (Number.isFinite(marginY) ? marginY : 0);\n const rect = target.getBoundingClientRect().height;\n return Math.ceil(Math.max(target.scrollHeight, borderBox, rect));\n}\n/**\n * Measure the currently mounted native content and tween the panel to fit it.\n * Re-fits automatically when the card's intrinsic height changes - notably after\n * the Newsreader/Schibsted web fonts swap in (which grows line boxes a few px\n * after first paint) and on inline view swaps (email -> OTP code -> success).\n */\nexport function fitPanelToContent(m) {\n var _a, _b;\n const first = m.content.firstElementChild;\n const target = first || m.content;\n const apply = () => {\n // Only fit while this exact node is still the mounted card.\n if (m.content.firstElementChild !== first && first)\n return;\n const h = measureOuterHeight(target);\n if (h > 0)\n setPanelHeight(m, h);\n };\n apply();\n const view = target.ownerDocument.defaultView;\n // Re-fit after fonts load (one-shot) and once the ResizeObserver-less browsers\n // have painted, so the height never lags a late reflow.\n (_a = view === null || view === void 0 ? void 0 : view.requestAnimationFrame) === null || _a === void 0 ? void 0 : _a.call(view, apply);\n const fonts = target.ownerDocument.fonts;\n if (fonts === null || fonts === void 0 ? void 0 : fonts.ready)\n fonts.ready.then(apply).catch(() => { });\n (_b = m.fitObserver) === null || _b === void 0 ? void 0 : _b.disconnect();\n m.fitObserver = null;\n if (first && typeof (view === null || view === void 0 ? void 0 : view.ResizeObserver) === \"function\") {\n const ro = new view.ResizeObserver(() => apply());\n ro.observe(first);\n m.fitObserver = ro;\n }\n}\n/** Switch the modal into NATIVE-content mode: detach any iframe, mount `node`. */\nexport function mountContent(m, node) {\n var _a;\n detachIframe(m);\n (_a = m.fitObserver) === null || _a === void 0 ? void 0 : _a.disconnect();\n m.fitObserver = null;\n m.content.replaceChildren(node);\n m.content.style.display = \"block\";\n}\n/** Get (or lazily create) the warm iframe for signer/hosted-page mode. */\nexport function ensureIframe(m, url, origin) {\n var _a;\n if (m.iframe && m.iframeOrigin === origin && m.iframe.src === url)\n return m.iframe;\n detachIframe(m);\n (_a = m.fitObserver) === null || _a === void 0 ? void 0 : _a.disconnect();\n m.fitObserver = null;\n m.content.style.display = \"none\";\n const iframe = document.createElement(\"iframe\");\n iframe.className = \"bw-frame\";\n iframe.setAttribute(\"title\", \"Bounded\");\n iframe.setAttribute(\"allow\", \"clipboard-write\");\n iframe.src = url;\n m.iframeOrigin = origin;\n m.iframeReady = false;\n m.panel.appendChild(iframe);\n m.iframe = iframe;\n return iframe;\n}\n/**\n * Destroy the warm signer iframe if one is currently mounted for `origin`, and report\n * whether there was one. Logout needs this: a signing session can live in that document's\n * MEMORY (the signer keeps an in-memory mirror when the browser blocks its storage), and a\n * throwaway iframe opened by the sweep can only ever clear the shared store, never another\n * document's memory. Removing the iframe discards its browsing context, which takes the\n * mirror with it.\n *\n * Deliberately does NOT call getModal(): that would BUILD a modal just to tear it down, on\n * every logout of every app, most of which never mounted one.\n */\nexport function detachWarmSignerIframe(origin) {\n if (!modal || !modal.iframe || modal.iframeOrigin !== origin)\n return false;\n detachIframe(modal);\n return true;\n}\nexport function detachIframe(m) {\n if (m.iframe) {\n try {\n m.iframe.remove();\n }\n catch (_a) {\n /* ignore */\n }\n }\n m.iframe = null;\n m.iframeReady = false;\n m.iframeOrigin = \"\";\n m.onIframeMessage = null;\n}\n// Load the Bounded editorial typefaces (Newsreader display + Schibsted Grotesk body +\n// JetBrains Mono) once at the document level so they apply inside the shadow root. A\n// no-op if already present or off-DOM. Fonts loaded here match the hosted auth page.\nconst 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\";\nexport function ensureFonts() {\n if (!hasDOM())\n return;\n if (document.querySelector('link[data-bounded-fonts=\"1\"]'))\n return;\n const pre1 = document.createElement(\"link\");\n pre1.rel = \"preconnect\";\n pre1.href = \"https://fonts.googleapis.com\";\n const pre2 = document.createElement(\"link\");\n pre2.rel = \"preconnect\";\n pre2.href = \"https://fonts.gstatic.com\";\n pre2.crossOrigin = \"anonymous\";\n const link = document.createElement(\"link\");\n link.rel = \"stylesheet\";\n link.href = FONTS_HREF;\n link.setAttribute(\"data-bounded-fonts\", \"1\");\n document.head.append(pre1, pre2, link);\n}\nexport { hasDOM };\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAsNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,sBAAsB,CAAC,MAAM,EAAE;AAC/C,IACQ,OAAO,KAAK;AAGpB;;;;"}
|