@bounded-sh/client 0.0.61 → 0.0.64
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-login-widget.d.ts +1 -1
- package/dist/auth/index.d.ts +4 -5
- package/dist/auth/providers/email-auth-provider.d.ts +4 -4
- package/dist/auth/turnkey-signer-bridge.d.ts +5 -0
- package/dist/{email-auth-provider-9BwSziWj.js → email-auth-provider-97CluDlZ.js} +27 -30
- package/dist/email-auth-provider-97CluDlZ.js.map +1 -0
- package/dist/{email-auth-provider-BttT2sZK.js → email-auth-provider-CKM4O5Z1.js} +27 -30
- package/dist/email-auth-provider-CKM4O5Z1.js.map +1 -0
- package/dist/{email-auth-provider-B3XaJw-G.mjs → email-auth-provider-h0fPnU76.mjs} +27 -30
- package/dist/email-auth-provider-h0fPnU76.mjs.map +1 -0
- package/dist/{email-auth-provider-Cb4VKA1E.mjs → email-auth-provider-v9xvY0Ky.mjs} +27 -30
- package/dist/email-auth-provider-v9xvY0Ky.mjs.map +1 -0
- package/dist/{guest-auth-provider-BBSFawAr.mjs → guest-auth-provider-BLRbjAv2.mjs} +2 -2
- package/dist/{guest-auth-provider-BBPpydtM.mjs.map → guest-auth-provider-BLRbjAv2.mjs.map} +1 -1
- package/dist/{guest-auth-provider-Di0TRg-z.js → guest-auth-provider-BvIf5W5c.js} +2 -2
- package/dist/{guest-auth-provider-Di0TRg-z.js.map → guest-auth-provider-BvIf5W5c.js.map} +1 -1
- package/dist/{guest-auth-provider-BcR-MQ0g.js → guest-auth-provider-CLnFuodt.js} +2 -2
- package/dist/{guest-auth-provider-BcR-MQ0g.js.map → guest-auth-provider-CLnFuodt.js.map} +1 -1
- package/dist/{guest-auth-provider-BBPpydtM.mjs → guest-auth-provider-Dmup2WIL.mjs} +2 -2
- package/dist/{guest-auth-provider-BBSFawAr.mjs.map → guest-auth-provider-Dmup2WIL.mjs.map} +1 -1
- package/dist/{index-L2R6C5Vl.mjs → index-7yz-Olrm.mjs} +1371 -1525
- package/dist/index-7yz-Olrm.mjs.map +1 -0
- package/dist/{index-C_L497w1.js → index-Bk0nEjB6.js} +1373 -1528
- package/dist/index-Bk0nEjB6.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{index.native-BIUs8t7F.mjs → index.native-CWcQMPZd.mjs} +518 -221
- package/dist/index.native-CWcQMPZd.mjs.map +1 -0
- package/dist/{index.native-BSheiGj2.js → index.native-Do-VhPUG.js} +520 -224
- package/dist/index.native-Do-VhPUG.js.map +1 -0
- package/dist/index.native.js +1 -1
- package/dist/index.native.mjs +1 -1
- package/dist/{injected-evm-wallet-provider-DgWUaVtt.js → injected-evm-wallet-provider-B5MA0w8I.js} +2 -2
- package/dist/{injected-evm-wallet-provider-DgWUaVtt.js.map → injected-evm-wallet-provider-B5MA0w8I.js.map} +1 -1
- package/dist/{injected-evm-wallet-provider-7XawIUdJ.js → injected-evm-wallet-provider-BMiT8I-4.js} +2 -2
- package/dist/{injected-evm-wallet-provider-7XawIUdJ.js.map → injected-evm-wallet-provider-BMiT8I-4.js.map} +1 -1
- package/dist/{injected-evm-wallet-provider-DSFDC8fh.mjs → injected-evm-wallet-provider-DlPsOmik.mjs} +2 -2
- package/dist/{injected-evm-wallet-provider-DSFDC8fh.mjs.map → injected-evm-wallet-provider-DlPsOmik.mjs.map} +1 -1
- package/dist/{injected-evm-wallet-provider-DnOrVMDX.mjs → injected-evm-wallet-provider-xvZq9Zli.mjs} +2 -2
- package/dist/{injected-evm-wallet-provider-DnOrVMDX.mjs.map → injected-evm-wallet-provider-xvZq9Zli.mjs.map} +1 -1
- package/dist/{injected-wallet-provider-oCRGuls5.js → injected-wallet-provider-CSj0lY9H.js} +2 -2
- package/dist/{injected-wallet-provider-oCRGuls5.js.map → injected-wallet-provider-CSj0lY9H.js.map} +1 -1
- package/dist/{injected-wallet-provider-BMDJntMD.js → injected-wallet-provider-CoE5XQQn.js} +2 -2
- package/dist/{injected-wallet-provider-BMDJntMD.js.map → injected-wallet-provider-CoE5XQQn.js.map} +1 -1
- package/dist/{injected-wallet-provider-ZkPzVj5W.mjs → injected-wallet-provider-Dd7ij6bc.mjs} +2 -2
- package/dist/{injected-wallet-provider-ZkPzVj5W.mjs.map → injected-wallet-provider-Dd7ij6bc.mjs.map} +1 -1
- package/dist/{injected-wallet-provider-DfJvN3sV.mjs → injected-wallet-provider-YHhhFzsj.mjs} +2 -2
- package/dist/{injected-wallet-provider-DfJvN3sV.mjs.map → injected-wallet-provider-YHhhFzsj.mjs.map} +1 -1
- package/package.json +2 -2
- package/dist/auth/crossmint-signer-bridge.d.ts +0 -45
- package/dist/email-auth-provider-9BwSziWj.js.map +0 -1
- package/dist/email-auth-provider-B3XaJw-G.mjs.map +0 -1
- package/dist/email-auth-provider-BttT2sZK.js.map +0 -1
- package/dist/email-auth-provider-Cb4VKA1E.mjs.map +0 -1
- package/dist/index-C_L497w1.js.map +0 -1
- package/dist/index-L2R6C5Vl.mjs.map +0 -1
- package/dist/index.native-BIUs8t7F.mjs.map +0 -1
- package/dist/index.native-BSheiGj2.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getConfig, getActiveSessionManager, WebSessionManager, ReactNativeSessionManager, revokeSession, init as init$1, onSessionCleared, reconnectWithNewAuth, deriveUserIdentityFromIdToken, subscribe, getIdToken as getIdToken$1, convertRemainingAccounts, buildSetDocumentsTransaction, genAuthNonce, genSolanaMessage, createSessionWithSignature } from '@bounded-sh/core';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -847,6 +847,8 @@ function getDefaultExportFromCjs (x) {
|
|
|
847
847
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
848
848
|
}
|
|
849
849
|
|
|
850
|
+
var safeBuffer = {exports: {}};
|
|
851
|
+
|
|
850
852
|
var buffer = {};
|
|
851
853
|
|
|
852
854
|
var base64Js = {};
|
|
@@ -3216,10 +3218,6 @@ function requireBuffer () {
|
|
|
3216
3218
|
return buffer;
|
|
3217
3219
|
}
|
|
3218
3220
|
|
|
3219
|
-
var bufferExports = requireBuffer();
|
|
3220
|
-
|
|
3221
|
-
var safeBuffer = {exports: {}};
|
|
3222
|
-
|
|
3223
3221
|
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
|
3224
3222
|
|
|
3225
3223
|
var hasRequiredSafeBuffer;
|
|
@@ -3433,173 +3431,448 @@ var basex = /*@__PURE__*/getDefaultExportFromCjs(srcExports);
|
|
|
3433
3431
|
var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
3434
3432
|
var bs58 = basex(ALPHABET);
|
|
3435
3433
|
|
|
3436
|
-
|
|
3437
|
-
|
|
3434
|
+
var bufferExports = requireBuffer();
|
|
3435
|
+
|
|
3436
|
+
// bounded-widget-modal.ts - the shared in-app WIDGET shell for Bounded's login
|
|
3437
|
+
// and signing surfaces. One Shadow-DOM overlay + panel that matches the Bounded
|
|
3438
|
+
// widget (Seal) look and MOTION: a backdrop fade, a panel rise on desktop, a
|
|
3439
|
+
// bottom-sheet on mobile, a height tween as content swaps, and a clean close.
|
|
3440
|
+
//
|
|
3441
|
+
// It hosts EITHER:
|
|
3442
|
+
// - NATIVE content (the login card the SDK renders itself), or
|
|
3443
|
+
// - an IFRAME (the Bounded-owned signer page, which must run on the single
|
|
3444
|
+
// signer origin because a WebAuthn passkey is bound to one origin).
|
|
3445
|
+
//
|
|
3446
|
+
// The modal is a warm singleton: it stays mounted (hidden) between uses so a
|
|
3447
|
+
// second open - or a signature right after login - is instant and, when it is
|
|
3448
|
+
// already open, a clean in-place view swap rather than a reopen.
|
|
3449
|
+
function hasDOM$3() {
|
|
3450
|
+
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
3451
|
+
}
|
|
3452
|
+
const OVERLAY_CSS = `
|
|
3453
|
+
:host{all:initial}
|
|
3454
|
+
*{box-sizing:border-box}
|
|
3455
|
+
.bw-ov{position:fixed;inset:0;z-index:2147483647;display:none;
|
|
3456
|
+
font-family:"Schibsted Grotesk","Helvetica Neue",Arial,sans-serif}
|
|
3457
|
+
.bw-ov.mounted{display:block}
|
|
3458
|
+
.bw-back{position:fixed;inset:0;background:rgba(4,4,5,.62);opacity:0;
|
|
3459
|
+
transition:opacity .24s ease;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px)}
|
|
3460
|
+
.bw-wrap{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;padding:20px}
|
|
3461
|
+
.bw-panel{position:relative;width:420px;max-width:calc(100vw - 28px);height:280px;
|
|
3462
|
+
border-radius:14px;overflow:hidden;background:#0e0f11;border:1px solid rgba(232,230,222,.08);
|
|
3463
|
+
box-shadow:0 1px 0 rgba(232,230,222,.03) inset,0 40px 90px -45px rgba(0,0,0,.85);
|
|
3464
|
+
opacity:0;transform:translateY(14px) scale(.98);will-change:transform,opacity,height;
|
|
3465
|
+
transition:opacity .28s cubic-bezier(.2,.8,.2,1),transform .28s cubic-bezier(.2,.8,.2,1),
|
|
3466
|
+
height .3s cubic-bezier(.2,.8,.2,1)}
|
|
3467
|
+
.bw-ov.show .bw-back{opacity:1}
|
|
3468
|
+
.bw-ov.show .bw-panel{opacity:1;transform:none}
|
|
3469
|
+
.bw-ov.closing .bw-back{opacity:0}
|
|
3470
|
+
.bw-ov.closing .bw-panel{opacity:0;transform:translateY(12px) scale(.99)}
|
|
3471
|
+
.bw-content{position:absolute;inset:0;overflow:hidden}
|
|
3472
|
+
.bw-frame{display:block;width:100%;height:100%;border:0;background:transparent;color-scheme:dark}
|
|
3473
|
+
/* editorial corner crop-marks, matching the reference frame */
|
|
3474
|
+
.bw-mk{position:absolute;width:13px;height:13px;pointer-events:none;z-index:2;
|
|
3475
|
+
border-color:rgba(232,230,222,.22);border-style:solid;border-width:0}
|
|
3476
|
+
.bw-mk.tl{top:11px;left:11px;border-top-width:1px;border-left-width:1px}
|
|
3477
|
+
.bw-mk.tr{top:11px;right:11px;border-top-width:1px;border-right-width:1px}
|
|
3478
|
+
.bw-mk.bl{bottom:11px;left:11px;border-bottom-width:1px;border-left-width:1px}
|
|
3479
|
+
.bw-mk.br{bottom:11px;right:11px;border-bottom-width:1px;border-right-width:1px}
|
|
3480
|
+
@media(max-width:560px){
|
|
3481
|
+
.bw-wrap{align-items:flex-end;padding:0}
|
|
3482
|
+
.bw-panel{width:100%;max-width:100%;border-radius:18px 18px 0 0;border-bottom:0}
|
|
3483
|
+
.bw-content{overflow-y:auto}
|
|
3484
|
+
.bw-ov.show .bw-panel{transform:none}
|
|
3485
|
+
.bw-ov:not(.show) .bw-panel,.bw-ov.closing .bw-panel{transform:translateY(18%)}
|
|
3486
|
+
}
|
|
3487
|
+
@media(prefers-reduced-motion:reduce){.bw-back,.bw-panel{transition:opacity .12s linear!important}}
|
|
3488
|
+
`;
|
|
3489
|
+
let modal = null;
|
|
3490
|
+
function getModal() {
|
|
3491
|
+
if (modal)
|
|
3492
|
+
return modal;
|
|
3493
|
+
const root = document.createElement("div");
|
|
3494
|
+
root.setAttribute("data-bounded-widget", "");
|
|
3495
|
+
const shadow = root.attachShadow({ mode: "open" });
|
|
3496
|
+
const style = document.createElement("style");
|
|
3497
|
+
style.textContent = OVERLAY_CSS;
|
|
3498
|
+
shadow.appendChild(style);
|
|
3499
|
+
const overlay = document.createElement("div");
|
|
3500
|
+
overlay.className = "bw-ov";
|
|
3501
|
+
const back = document.createElement("div");
|
|
3502
|
+
back.className = "bw-back";
|
|
3503
|
+
const wrap = document.createElement("div");
|
|
3504
|
+
wrap.className = "bw-wrap";
|
|
3505
|
+
const panel = document.createElement("div");
|
|
3506
|
+
panel.className = "bw-panel";
|
|
3507
|
+
const content = document.createElement("div");
|
|
3508
|
+
content.className = "bw-content";
|
|
3509
|
+
panel.appendChild(content);
|
|
3510
|
+
for (const corner of ["tl", "tr", "bl", "br"]) {
|
|
3511
|
+
const mk = document.createElement("span");
|
|
3512
|
+
mk.className = "bw-mk " + corner;
|
|
3513
|
+
panel.appendChild(mk);
|
|
3514
|
+
}
|
|
3515
|
+
wrap.appendChild(panel);
|
|
3516
|
+
overlay.appendChild(back);
|
|
3517
|
+
overlay.appendChild(wrap);
|
|
3518
|
+
shadow.appendChild(overlay);
|
|
3519
|
+
(document.body || document.documentElement).appendChild(root);
|
|
3520
|
+
const m = {
|
|
3521
|
+
root,
|
|
3522
|
+
overlay,
|
|
3523
|
+
panel,
|
|
3524
|
+
content,
|
|
3525
|
+
iframe: null,
|
|
3526
|
+
iframeOrigin: "",
|
|
3527
|
+
iframeReady: false,
|
|
3528
|
+
onBackdrop: null,
|
|
3529
|
+
onIframeMessage: null,
|
|
3530
|
+
chain: Promise.resolve(),
|
|
3531
|
+
fitObserver: null,
|
|
3532
|
+
};
|
|
3533
|
+
// The dismiss handler lives on `.bw-wrap`: it is the full-viewport flex layer
|
|
3534
|
+
// that sits ABOVE `.bw-back`, so it (not the backdrop element) receives clicks
|
|
3535
|
+
// outside the panel. Fire only when the click lands on the wrap itself, never
|
|
3536
|
+
// when it bubbles up from the panel or its content.
|
|
3537
|
+
wrap.addEventListener("click", (event) => {
|
|
3538
|
+
if (event.target === wrap && m.onBackdrop)
|
|
3539
|
+
m.onBackdrop();
|
|
3540
|
+
});
|
|
3541
|
+
window.addEventListener("message", (event) => {
|
|
3542
|
+
if (!m.iframe)
|
|
3543
|
+
return;
|
|
3544
|
+
if (event.origin !== m.iframeOrigin)
|
|
3545
|
+
return;
|
|
3546
|
+
if (event.source !== m.iframe.contentWindow)
|
|
3547
|
+
return;
|
|
3548
|
+
const d = event.data;
|
|
3549
|
+
if (!d || typeof d !== "object")
|
|
3550
|
+
return;
|
|
3551
|
+
if (m.onIframeMessage)
|
|
3552
|
+
m.onIframeMessage(d);
|
|
3553
|
+
});
|
|
3554
|
+
modal = m;
|
|
3555
|
+
return m;
|
|
3556
|
+
}
|
|
3557
|
+
function showModal(m) {
|
|
3558
|
+
m.overlay.classList.remove("closing");
|
|
3559
|
+
m.overlay.classList.add("mounted");
|
|
3560
|
+
// Force a reflow so the .show transition runs from the hidden state every open.
|
|
3561
|
+
void m.panel.offsetWidth;
|
|
3562
|
+
m.overlay.classList.add("show");
|
|
3563
|
+
}
|
|
3564
|
+
function hideModal(m, after) {
|
|
3565
|
+
m.overlay.classList.remove("show");
|
|
3566
|
+
m.overlay.classList.add("closing");
|
|
3567
|
+
window.setTimeout(() => {
|
|
3568
|
+
m.overlay.classList.remove("mounted", "closing");
|
|
3569
|
+
}, 260);
|
|
3570
|
+
}
|
|
3571
|
+
function setPanelHeight(m, px) {
|
|
3572
|
+
const h = Math.max(140, Math.min(680, Math.round(px)));
|
|
3573
|
+
m.panel.style.height = h + "px";
|
|
3574
|
+
}
|
|
3575
|
+
/** Get (or lazily create) the warm iframe for signer/hosted-page mode. */
|
|
3576
|
+
function ensureIframe(m, url, origin) {
|
|
3577
|
+
var _a;
|
|
3578
|
+
if (m.iframe && m.iframeOrigin === origin && m.iframe.src === url)
|
|
3579
|
+
return m.iframe;
|
|
3580
|
+
detachIframe(m);
|
|
3581
|
+
(_a = m.fitObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
3582
|
+
m.fitObserver = null;
|
|
3583
|
+
m.content.style.display = "none";
|
|
3584
|
+
const iframe = document.createElement("iframe");
|
|
3585
|
+
iframe.className = "bw-frame";
|
|
3586
|
+
iframe.setAttribute("title", "Bounded");
|
|
3587
|
+
// Grant the framed origin WebAuthn get + create so passkey enroll/sign run
|
|
3588
|
+
// inside the frame from the user's click (transient activation stays in-frame).
|
|
3589
|
+
iframe.setAttribute("allow", "publickey-credentials-get; publickey-credentials-create; clipboard-write");
|
|
3590
|
+
iframe.src = url;
|
|
3591
|
+
m.iframeOrigin = origin;
|
|
3592
|
+
m.iframeReady = false;
|
|
3593
|
+
m.panel.appendChild(iframe);
|
|
3594
|
+
m.iframe = iframe;
|
|
3595
|
+
return iframe;
|
|
3596
|
+
}
|
|
3597
|
+
function detachIframe(m) {
|
|
3598
|
+
if (m.iframe) {
|
|
3599
|
+
try {
|
|
3600
|
+
m.iframe.remove();
|
|
3601
|
+
}
|
|
3602
|
+
catch (_a) {
|
|
3603
|
+
/* ignore */
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3606
|
+
m.iframe = null;
|
|
3607
|
+
m.iframeReady = false;
|
|
3608
|
+
m.iframeOrigin = "";
|
|
3609
|
+
m.onIframeMessage = null;
|
|
3610
|
+
}
|
|
3611
|
+
|
|
3612
|
+
// turnkey-wallet-widget.ts - runs one Turnkey signer exchange inside the shared
|
|
3613
|
+
// in-app WIDGET (bounded-widget-modal.ts). The Bounded-owned signer page is loaded
|
|
3614
|
+
// in a warm iframe behind the modal so signing feels native: an in-app card plus
|
|
3615
|
+
// the OS Face ID / Touch ID sheet, never a jarring popup.
|
|
3616
|
+
//
|
|
3617
|
+
// WHY AN IFRAME: a WebAuthn passkey is bound to ONE origin, so passkey create/sign
|
|
3618
|
+
// MUST run on the single Bounded signer origin. The iframe carries the
|
|
3619
|
+
// publickey-credentials-{get,create} permission policy and the user's click lands
|
|
3620
|
+
// INSIDE it, giving WebAuthn the transient activation it needs.
|
|
3621
|
+
//
|
|
3622
|
+
// SAFARI / restricted embedders: cross-origin iframe passkey CREATE is unreliable
|
|
3623
|
+
// in Safari. The signer detects that and posts `fallbackPopup`; we then rerun the
|
|
3624
|
+
// SAME request through `popupFallback` (a real window). Callers pass a popup
|
|
3625
|
+
// implementation and never see the difference.
|
|
3626
|
+
/**
|
|
3627
|
+
* Run one signer exchange through the in-app widget. Resolves when `onResult`
|
|
3628
|
+
* accepts a result; falls back to `popupFallback` if the frame cannot run WebAuthn
|
|
3629
|
+
* (Safari cross-origin create) or cannot be mounted.
|
|
3630
|
+
*/
|
|
3631
|
+
async function runWidget(url, signerOrigin, ex, popupFallback) {
|
|
3632
|
+
if (!hasDOM$3())
|
|
3633
|
+
return popupFallback();
|
|
3634
|
+
const m = getModal();
|
|
3635
|
+
const requestId = String(ex.request.requestId);
|
|
3636
|
+
// Serialize: WebAuthn is modal, and one warm frame handles one request at a time.
|
|
3637
|
+
const run = m.chain.then(() => new Promise((resolve, reject) => {
|
|
3638
|
+
let settled = false;
|
|
3639
|
+
let usedFallback = false;
|
|
3640
|
+
const iframe = ensureIframe(m, url, signerOrigin);
|
|
3641
|
+
const send = () => {
|
|
3642
|
+
if (!iframe.contentWindow)
|
|
3643
|
+
return;
|
|
3644
|
+
try {
|
|
3645
|
+
iframe.contentWindow.postMessage(ex.request, signerOrigin);
|
|
3646
|
+
}
|
|
3647
|
+
catch (_a) {
|
|
3648
|
+
/* frame gone */
|
|
3649
|
+
}
|
|
3650
|
+
};
|
|
3651
|
+
let loadTimer = 0;
|
|
3652
|
+
let ceilingTimer = 0;
|
|
3653
|
+
const finish = (fn) => {
|
|
3654
|
+
if (settled)
|
|
3655
|
+
return;
|
|
3656
|
+
settled = true;
|
|
3657
|
+
m.onIframeMessage = null;
|
|
3658
|
+
m.onBackdrop = null;
|
|
3659
|
+
window.clearTimeout(loadTimer);
|
|
3660
|
+
window.clearTimeout(ceilingTimer);
|
|
3661
|
+
fn();
|
|
3662
|
+
};
|
|
3663
|
+
const goFallback = () => {
|
|
3664
|
+
if (usedFallback || settled)
|
|
3665
|
+
return;
|
|
3666
|
+
usedFallback = true;
|
|
3667
|
+
hideModal(m);
|
|
3668
|
+
finish(() => popupFallback().then(resolve, reject));
|
|
3669
|
+
};
|
|
3670
|
+
m.onBackdrop = () => {
|
|
3671
|
+
hideModal(m);
|
|
3672
|
+
finish(() => reject(new Error("cancelled")));
|
|
3673
|
+
};
|
|
3674
|
+
m.onIframeMessage = (d) => {
|
|
3675
|
+
if (d.type === "bounded:turnkey:ready") {
|
|
3676
|
+
m.iframeReady = true;
|
|
3677
|
+
send();
|
|
3678
|
+
return;
|
|
3679
|
+
}
|
|
3680
|
+
if (d.type === "bounded:turnkey:resize" && typeof d.height === "number") {
|
|
3681
|
+
setPanelHeight(m, d.height);
|
|
3682
|
+
return;
|
|
3683
|
+
}
|
|
3684
|
+
if (d.type === "bounded:turnkey:fallbackPopup" && d.requestId === requestId) {
|
|
3685
|
+
goFallback();
|
|
3686
|
+
return;
|
|
3687
|
+
}
|
|
3688
|
+
if (d.type === "bounded:turnkey:result" && d.requestId === requestId) {
|
|
3689
|
+
const outcome = ex.onResult(d);
|
|
3690
|
+
if ("error" in outcome) {
|
|
3691
|
+
hideModal(m);
|
|
3692
|
+
finish(() => reject(new Error(outcome.error)));
|
|
3693
|
+
return;
|
|
3694
|
+
}
|
|
3695
|
+
if (outcome.done) {
|
|
3696
|
+
hideModal(m);
|
|
3697
|
+
finish(() => resolve(outcome.value));
|
|
3698
|
+
}
|
|
3699
|
+
}
|
|
3700
|
+
};
|
|
3701
|
+
showModal(m);
|
|
3702
|
+
if (m.iframeReady)
|
|
3703
|
+
send();
|
|
3704
|
+
// If the frame never loads, degrade to the popup (best-effort - a post-load
|
|
3705
|
+
// popup may be blocked without a gesture, in which case the fallback rejects).
|
|
3706
|
+
loadTimer = window.setTimeout(() => {
|
|
3707
|
+
if (!m.iframeReady && !settled)
|
|
3708
|
+
goFallback();
|
|
3709
|
+
}, 8000);
|
|
3710
|
+
// Absolute ceiling so a stuck flow cannot hang forever.
|
|
3711
|
+
ceilingTimer = window.setTimeout(() => {
|
|
3712
|
+
if (!settled) {
|
|
3713
|
+
hideModal(m);
|
|
3714
|
+
finish(() => reject(new Error("Wallet approval timed out.")));
|
|
3715
|
+
}
|
|
3716
|
+
}, 5 * 60 * 1000);
|
|
3717
|
+
}));
|
|
3718
|
+
m.chain = run.then(() => undefined, () => undefined);
|
|
3719
|
+
return run;
|
|
3720
|
+
}
|
|
3721
|
+
|
|
3722
|
+
// turnkey-signer-bridge.ts - routes NON-CUSTODIAL Turnkey embedded-wallet signing
|
|
3723
|
+
// through the Bounded-owned signer page (auth.bounded.sh/wallet/turnkey/signer).
|
|
3438
3724
|
//
|
|
3439
|
-
//
|
|
3440
|
-
//
|
|
3441
|
-
//
|
|
3442
|
-
//
|
|
3443
|
-
//
|
|
3444
|
-
// postMessage.
|
|
3725
|
+
// TRANSPORT: by default the signer runs inside the in-app WIDGET (turnkey-wallet-
|
|
3726
|
+
// widget.ts) - an iframe behind a Shadow-DOM modal that matches the Bounded widget
|
|
3727
|
+
// look + motion, so signing feels native. Safari (unreliable at iframe passkey
|
|
3728
|
+
// CREATE) and any environment where the frame cannot mount fall back to a real
|
|
3729
|
+
// popup window; both transports speak the same postMessage protocol.
|
|
3445
3730
|
//
|
|
3446
|
-
//
|
|
3447
|
-
//
|
|
3448
|
-
//
|
|
3449
|
-
//
|
|
3450
|
-
//
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
'instead of signMessage/signTransaction.';
|
|
3454
|
-
const NO_EMBEDDED_WALLET = 'This login has no embedded wallet. Enable `"auth": { "wallets": true }` in ' +
|
|
3455
|
-
'the app policy so email logins get a non-custodial wallet (@user.address), ' +
|
|
3456
|
-
'then sign from a user gesture.';
|
|
3731
|
+
// Turnkey wallets produce raw detached signatures. The signer runs the Turnkey
|
|
3732
|
+
// browser SDK on the single Bounded origin and stamps an ed25519 signRawPayload
|
|
3733
|
+
// with the user's passkey. The app retains the transaction itself.
|
|
3734
|
+
//
|
|
3735
|
+
// ONE ORIGIN, ONE PASSKEY: a WebAuthn passkey is bound to a single origin, so ALL
|
|
3736
|
+
// Bounded apps (any subdomain / custom domain) sign through this one origin - giving
|
|
3737
|
+
// every user one wallet + one passkey that roams across every app.
|
|
3457
3738
|
function hasDOM$2() {
|
|
3458
3739
|
return typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
3459
3740
|
}
|
|
3741
|
+
// Safari (incl. iOS WebViews) is unreliable at running a WebAuthn CREATE inside a
|
|
3742
|
+
// cross-origin iframe, so the widget's automatic in-iframe passkey enrollment can
|
|
3743
|
+
// fail - and a post-failure popup would no longer have a user gesture to open with.
|
|
3744
|
+
// There we pick the popup up front, from the original click, so enrollment is solid.
|
|
3745
|
+
// Everywhere else the inline widget is used (buttery in-app modal).
|
|
3746
|
+
function preferPopup() {
|
|
3747
|
+
if (!hasDOM$2() || typeof navigator === 'undefined')
|
|
3748
|
+
return true;
|
|
3749
|
+
const ua = navigator.userAgent || '';
|
|
3750
|
+
return /^((?!chrome|android|crios|fxios|edg|edga|opr).)*safari/i.test(ua);
|
|
3751
|
+
}
|
|
3752
|
+
// Dispatch one signer exchange through the in-app WIDGET, degrading to the POPUP
|
|
3753
|
+
// when we cannot embed (Safari enrollment, or the frame never loads).
|
|
3754
|
+
async function deliver(url, origin, ex) {
|
|
3755
|
+
const popup = () => runPopup(url, origin, ex);
|
|
3756
|
+
if (preferPopup())
|
|
3757
|
+
return popup();
|
|
3758
|
+
return runWidget(url, origin, { request: ex.request, onResult: ex.onResult }, popup);
|
|
3759
|
+
}
|
|
3760
|
+
async function turnkeySignerPage() {
|
|
3761
|
+
const cfg = await getConfig();
|
|
3762
|
+
const base = (cfg.humanAuthApiUrl || 'https://auth.bounded.sh').replace(/\/$/, '');
|
|
3763
|
+
return { url: `${base}/wallet/turnkey/signer`, origin: new URL(base).origin };
|
|
3764
|
+
}
|
|
3765
|
+
function toHex(bytes) {
|
|
3766
|
+
let h = '';
|
|
3767
|
+
for (const b of bytes)
|
|
3768
|
+
h += b.toString(16).padStart(2, '0');
|
|
3769
|
+
return h;
|
|
3770
|
+
}
|
|
3771
|
+
function fromHex(hex) {
|
|
3772
|
+
const clean = hex.startsWith('0x') ? hex.slice(2) : hex;
|
|
3773
|
+
const out = new Uint8Array(clean.length / 2);
|
|
3774
|
+
for (let i = 0; i < out.length; i++)
|
|
3775
|
+
out[i] = parseInt(clean.substr(i * 2, 2), 16);
|
|
3776
|
+
return out;
|
|
3777
|
+
}
|
|
3460
3778
|
function decodeJwt$1(token) {
|
|
3461
3779
|
try {
|
|
3462
|
-
let
|
|
3463
|
-
const
|
|
3464
|
-
if (
|
|
3465
|
-
|
|
3466
|
-
else if (
|
|
3467
|
-
|
|
3468
|
-
return JSON.parse(
|
|
3780
|
+
let value = token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/');
|
|
3781
|
+
const padding = value.length % 4;
|
|
3782
|
+
if (padding === 2)
|
|
3783
|
+
value += '==';
|
|
3784
|
+
else if (padding === 3)
|
|
3785
|
+
value += '=';
|
|
3786
|
+
return JSON.parse(getPlatform().atob(value));
|
|
3469
3787
|
}
|
|
3470
3788
|
catch (_a) {
|
|
3471
3789
|
return {};
|
|
3472
3790
|
}
|
|
3473
3791
|
}
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
// informative NO_EMBEDDED_WALLET error).
|
|
3477
|
-
function walletClaimsFromSession(chain = 'solana') {
|
|
3478
|
-
let idToken = null;
|
|
3792
|
+
function activeTurnkeyAddress() {
|
|
3793
|
+
let token = null;
|
|
3479
3794
|
try {
|
|
3480
|
-
|
|
3795
|
+
token = getActiveSessionManager().getIdToken();
|
|
3481
3796
|
}
|
|
3482
3797
|
catch (_a) {
|
|
3483
|
-
|
|
3798
|
+
token = null;
|
|
3484
3799
|
}
|
|
3485
|
-
if (!
|
|
3486
|
-
return null;
|
|
3487
|
-
const c = decodeJwt$1(idToken);
|
|
3488
|
-
const address = c['custom:walletAddress'];
|
|
3489
|
-
const evmAddress = c['custom:evmWalletAddress'];
|
|
3490
|
-
const email = c['email'];
|
|
3491
|
-
if (typeof email !== 'string' || !email)
|
|
3800
|
+
if (!token)
|
|
3492
3801
|
return null;
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
return Object.assign(Object.assign(Object.assign({ email }, (typeof address === 'string' && address ? { address } : {})), (typeof evmAddress === 'string' ? { evmAddress: evmAddress.toLowerCase() } : {})), { environment });
|
|
3500
|
-
}
|
|
3501
|
-
async function signerPageUrl() {
|
|
3502
|
-
const cfg = await getConfig();
|
|
3503
|
-
const base = (cfg.humanAuthApiUrl || 'https://auth.bounded.sh').replace(/\/$/, '');
|
|
3504
|
-
return { url: `${base}/wallet/signer`, origin: new URL(base).origin };
|
|
3802
|
+
const claims = decodeJwt$1(token);
|
|
3803
|
+
const address = claims['custom:walletAddress'];
|
|
3804
|
+
const provider = claims['custom:walletProvider'];
|
|
3805
|
+
return provider === 'turnkey' && typeof address === 'string' && address
|
|
3806
|
+
? address
|
|
3807
|
+
: null;
|
|
3505
3808
|
}
|
|
3506
3809
|
let requestSeq = 0;
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
*
|
|
3513
|
-
* Non-custodial: the popup gates signing behind an email OTP delivered to the
|
|
3514
|
-
* wallet's owner, and validates that the wallet address matches the account.
|
|
3515
|
-
*/
|
|
3516
|
-
async function signViaSignerPopup(action) {
|
|
3517
|
-
if (!hasDOM$2()) {
|
|
3518
|
-
throw new Error('Embedded-wallet signing is only available in the browser (popup-based).');
|
|
3519
|
-
}
|
|
3520
|
-
const isEvm = action.kind === 'evmTransaction';
|
|
3521
|
-
const claims = walletClaimsFromSession(isEvm ? 'evm' : 'solana');
|
|
3522
|
-
if (!claims)
|
|
3523
|
-
throw new Error(NO_EMBEDDED_WALLET);
|
|
3524
|
-
const { url, origin: signerOrigin } = await signerPageUrl();
|
|
3525
|
-
const requestId = `bsign_${Date.now()}_${++requestSeq}`;
|
|
3526
|
-
// Centered popup, sized for the OTP form (matches the OIDC login popup shape).
|
|
3527
|
-
const w = 420, h = 600;
|
|
3810
|
+
// Shared popup driver: open the signer page, do the ready/postMessage handshake, and
|
|
3811
|
+
// resolve when `onResult` accepts a result message. Origin + source are pinned.
|
|
3812
|
+
async function runPopup(url, signerOrigin, ex) {
|
|
3813
|
+
var _a, _b;
|
|
3814
|
+
const w = (_a = ex.width) !== null && _a !== void 0 ? _a : 420, h = (_b = ex.height) !== null && _b !== void 0 ? _b : 620;
|
|
3528
3815
|
const left = window.screenX + Math.max(0, (window.outerWidth - w) / 2);
|
|
3529
3816
|
const top = window.screenY + Math.max(0, (window.outerHeight - h) / 2);
|
|
3530
|
-
const popup = window.open(url, 'bounded-
|
|
3817
|
+
const popup = window.open(url, 'bounded-turnkey-signer', `width=${w},height=${h},left=${left},top=${top}`);
|
|
3531
3818
|
if (!popup) {
|
|
3532
|
-
throw new Error('Popup blocked
|
|
3533
|
-
}
|
|
3534
|
-
const request = {
|
|
3535
|
-
type: 'bounded:sign',
|
|
3536
|
-
requestId,
|
|
3537
|
-
environment: claims.environment, // may be undefined → page auto-detects
|
|
3538
|
-
email: claims.email,
|
|
3539
|
-
address: isEvm ? claims.evmAddress : claims.address,
|
|
3540
|
-
action,
|
|
3541
|
-
};
|
|
3819
|
+
throw new Error('Popup blocked - call this from a user gesture (e.g. a click handler) so the passkey approval window can open.');
|
|
3820
|
+
}
|
|
3542
3821
|
return await new Promise((resolve, reject) => {
|
|
3543
3822
|
let settled = false;
|
|
3544
|
-
let closeTimer;
|
|
3545
3823
|
let sentRequest = false;
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3824
|
+
let closeTimer;
|
|
3825
|
+
const cleanup = () => { settled = true; window.removeEventListener('message', onMsg); if (closeTimer)
|
|
3826
|
+
clearInterval(closeTimer); };
|
|
3827
|
+
const sendRequest = () => { if (sentRequest)
|
|
3828
|
+
return; sentRequest = true; try {
|
|
3829
|
+
popup.postMessage(ex.request, signerOrigin);
|
|
3830
|
+
}
|
|
3831
|
+
catch ( /* popup gone */_a) { /* popup gone */ } };
|
|
3832
|
+
const onMsg = (event) => {
|
|
3833
|
+
if (event.origin !== signerOrigin)
|
|
3554
3834
|
return;
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
}
|
|
3559
|
-
catch ( /* popup gone */_a) { /* popup gone */ }
|
|
3560
|
-
};
|
|
3561
|
-
const onMsg = (ev) => {
|
|
3562
|
-
if (ev.origin !== signerOrigin)
|
|
3563
|
-
return; // only trust the signer page origin
|
|
3564
|
-
if (ev.source !== popup)
|
|
3565
|
-
return; // only trust this signer popup window
|
|
3566
|
-
const d = ev.data;
|
|
3835
|
+
if (event.source !== popup)
|
|
3836
|
+
return;
|
|
3837
|
+
const d = event.data;
|
|
3567
3838
|
if (!d || typeof d !== 'object')
|
|
3568
3839
|
return;
|
|
3569
|
-
if (d.type === 'bounded:
|
|
3840
|
+
if (d.type === 'bounded:turnkey:ready') {
|
|
3570
3841
|
sendRequest();
|
|
3571
3842
|
return;
|
|
3572
3843
|
}
|
|
3573
|
-
if (d.type === 'bounded:
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3844
|
+
if (d.type === 'bounded:turnkey:result' && d.requestId === ex.request.requestId) {
|
|
3845
|
+
const outcome = ex.onResult(d);
|
|
3846
|
+
if ('error' in outcome) {
|
|
3847
|
+
cleanup();
|
|
3848
|
+
try {
|
|
3849
|
+
popup.close();
|
|
3850
|
+
}
|
|
3851
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
3852
|
+
reject(new Error(outcome.error));
|
|
3853
|
+
return;
|
|
3854
|
+
}
|
|
3855
|
+
if (outcome.done) {
|
|
3856
|
+
cleanup();
|
|
3857
|
+
try {
|
|
3858
|
+
popup.close();
|
|
3859
|
+
}
|
|
3860
|
+
catch ( /* ignore */_b) { /* ignore */ }
|
|
3861
|
+
resolve(outcome.value);
|
|
3577
3862
|
}
|
|
3578
|
-
catch ( /* ignore */_a) { /* ignore */ }
|
|
3579
|
-
if (d.ok)
|
|
3580
|
-
resolve({ hash: d.hash, explorerLink: d.explorerLink, transactionId: d.transactionId });
|
|
3581
|
-
else
|
|
3582
|
-
reject(new Error(String(d.error || 'Wallet signing failed')));
|
|
3583
3863
|
}
|
|
3584
3864
|
};
|
|
3585
3865
|
window.addEventListener('message', onMsg);
|
|
3586
|
-
// Fallback: if the ready ping was missed (fast load / focus race), push the
|
|
3587
|
-
// request shortly after opening. The page ignores it until a bounded:sign
|
|
3588
|
-
// arrives and only acts on the first one, so a duplicate is harmless.
|
|
3589
3866
|
setTimeout(sendRequest, 1200);
|
|
3590
|
-
// If the user closes the popup before completing, reject (unless a result
|
|
3591
|
-
// just arrived — give any in-flight message a beat to settle first).
|
|
3592
3867
|
closeTimer = setInterval(() => {
|
|
3593
3868
|
if (popup.closed) {
|
|
3594
3869
|
clearInterval(closeTimer);
|
|
3595
3870
|
setTimeout(() => { if (!settled) {
|
|
3596
3871
|
cleanup();
|
|
3597
|
-
reject(new Error('Wallet approval window was closed before
|
|
3872
|
+
reject(new Error('Wallet approval window was closed before it completed.'));
|
|
3598
3873
|
} }, 400);
|
|
3599
3874
|
}
|
|
3600
3875
|
}, 500);
|
|
3601
|
-
// Overall safety timeout (OTP + signing). Generous — the user may take a
|
|
3602
|
-
// while to fetch the code from their email.
|
|
3603
3876
|
setTimeout(() => { if (!settled) {
|
|
3604
3877
|
cleanup();
|
|
3605
3878
|
try {
|
|
@@ -3610,80 +3883,105 @@ async function signViaSignerPopup(action) {
|
|
|
3610
3883
|
} }, 5 * 60 * 1000);
|
|
3611
3884
|
});
|
|
3612
3885
|
}
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
// `serializedTransaction` string to be base58 — it rejects base64 with
|
|
3616
|
-
// "Invalid base58 string" (verified against Crossmint staging 2026-07-07). The
|
|
3617
|
-
// `wallets-sdk` object path bs58-encodes internally, so base58 is the contract.
|
|
3618
|
-
//
|
|
3619
|
-
// We do NOT require existing signatures (the smart wallet signs on the page);
|
|
3620
|
-
// Crossmint extracts the instructions, overrides the fee payer to its sponsor,
|
|
3621
|
-
// and re-wraps them for the smart wallet.
|
|
3622
|
-
function serializeTransaction(transaction) {
|
|
3623
|
-
const isLegacy = 'recentBlockhash' in transaction &&
|
|
3624
|
-
!('message' in transaction && 'staticAccountKeys' in transaction.message);
|
|
3625
|
-
const bytes = isLegacy
|
|
3626
|
-
? transaction.serialize({ requireAllSignatures: false, verifySignatures: false })
|
|
3627
|
-
: transaction.serialize();
|
|
3628
|
-
return bs58.encode(bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes));
|
|
3886
|
+
function hasTurnkeyWallet() {
|
|
3887
|
+
return activeTurnkeyAddress() !== null;
|
|
3629
3888
|
}
|
|
3630
3889
|
/**
|
|
3631
|
-
*
|
|
3632
|
-
*
|
|
3890
|
+
* Open the Bounded Turnkey signer popup and sign `message` (raw bytes) with the
|
|
3891
|
+
* user's non-custodial Turnkey wallet, resolving with the ed25519 signature +
|
|
3892
|
+
* the wallet address. MUST be called from a USER GESTURE (click/tap) or the
|
|
3893
|
+
* browser blocks the popup.
|
|
3894
|
+
*
|
|
3895
|
+
* On the user's FIRST signature the popup transparently enrolls a device passkey
|
|
3896
|
+
* (Face ID / Touch ID) and creates their wallet - no email code. Subsequent
|
|
3897
|
+
* signatures are just a passkey approval.
|
|
3633
3898
|
*/
|
|
3634
|
-
function
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
}
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3899
|
+
async function signSolanaMessageViaTurnkey(message) {
|
|
3900
|
+
if (!hasDOM$2()) {
|
|
3901
|
+
throw new Error('Turnkey embedded-wallet signing is only available in the browser (popup-based).');
|
|
3902
|
+
}
|
|
3903
|
+
const { url, origin } = await turnkeySignerPage();
|
|
3904
|
+
const requestId = `tksign_${Date.now()}_${++requestSeq}`;
|
|
3905
|
+
const messageHex = toHex(message);
|
|
3906
|
+
return await deliver(url, origin, {
|
|
3907
|
+
request: { type: 'bounded:turnkey:sign', requestId, messageHex },
|
|
3908
|
+
onResult: (d) => {
|
|
3909
|
+
if (d.ok && typeof d.signatureHex === 'string' && typeof d.address === 'string') {
|
|
3910
|
+
return { done: true, value: { signature: fromHex(d.signatureHex), address: d.address, subOrgId: String(d.subOrgId || '') } };
|
|
3911
|
+
}
|
|
3912
|
+
return { error: String(d.error || 'Turnkey signing failed') };
|
|
3913
|
+
},
|
|
3914
|
+
});
|
|
3915
|
+
}
|
|
3916
|
+
function requireMatchingAddress(result) {
|
|
3917
|
+
const expected = activeTurnkeyAddress();
|
|
3918
|
+
if (!expected)
|
|
3919
|
+
throw new Error('This session has no Turnkey wallet. Sign in again to provision one.');
|
|
3920
|
+
if (result.address !== expected)
|
|
3921
|
+
throw new Error('Turnkey signer returned a different wallet address than the active session.');
|
|
3922
|
+
return expected;
|
|
3923
|
+
}
|
|
3924
|
+
async function signMessageWithTurnkey(message) {
|
|
3925
|
+
const result = await signSolanaMessageViaTurnkey(getPlatform().textEncode(message));
|
|
3926
|
+
requireMatchingAddress(result);
|
|
3927
|
+
return bs58.encode(result.signature);
|
|
3928
|
+
}
|
|
3929
|
+
async function signTransactionWithTurnkey(transaction) {
|
|
3930
|
+
const isLegacy = 'serializeMessage' in transaction;
|
|
3931
|
+
const message = isLegacy
|
|
3932
|
+
? transaction.serializeMessage()
|
|
3933
|
+
: transaction.message.serialize();
|
|
3934
|
+
const result = await signSolanaMessageViaTurnkey(new Uint8Array(message));
|
|
3935
|
+
const address = requireMatchingAddress(result);
|
|
3936
|
+
const { PublicKey } = await import('@solana/web3.js');
|
|
3937
|
+
if (isLegacy) {
|
|
3938
|
+
transaction.addSignature(new PublicKey(address), bufferExports.Buffer.from(result.signature));
|
|
3666
3939
|
}
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3940
|
+
else {
|
|
3941
|
+
transaction.addSignature(new PublicKey(address), result.signature);
|
|
3942
|
+
}
|
|
3943
|
+
return transaction;
|
|
3944
|
+
}
|
|
3945
|
+
async function signAndSubmitTransactionWithTurnkey(transaction, feePayer) {
|
|
3946
|
+
var _a;
|
|
3947
|
+
const config = await getConfig();
|
|
3948
|
+
const rpcUrl = (_a = config.rpcUrl) === null || _a === void 0 ? void 0 : _a.trim();
|
|
3949
|
+
if (!rpcUrl)
|
|
3950
|
+
throw new Error('Turnkey transaction submission requires init({ rpcUrl }).');
|
|
3951
|
+
const { Connection, PublicKey } = await import('@solana/web3.js');
|
|
3952
|
+
const connection = new Connection(rpcUrl, 'confirmed');
|
|
3953
|
+
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
|
|
3954
|
+
const isLegacy = 'serializeMessage' in transaction;
|
|
3955
|
+
if (isLegacy) {
|
|
3956
|
+
const legacy = transaction;
|
|
3957
|
+
legacy.recentBlockhash = blockhash;
|
|
3958
|
+
legacy.lastValidBlockHeight = lastValidBlockHeight;
|
|
3959
|
+
if (!legacy.feePayer) {
|
|
3960
|
+
const address = activeTurnkeyAddress();
|
|
3961
|
+
if (!address)
|
|
3962
|
+
throw new Error('This session has no Turnkey wallet. Sign in again to provision one.');
|
|
3963
|
+
legacy.feePayer = feePayer !== null && feePayer !== void 0 ? feePayer : new PublicKey(address);
|
|
3964
|
+
}
|
|
3671
3965
|
}
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3966
|
+
else {
|
|
3967
|
+
transaction.message.recentBlockhash = blockhash;
|
|
3968
|
+
}
|
|
3969
|
+
const signed = await signTransactionWithTurnkey(transaction);
|
|
3970
|
+
const signature = await connection.sendRawTransaction(signed.serialize(), {
|
|
3971
|
+
skipPreflight: false,
|
|
3972
|
+
maxRetries: 3,
|
|
3675
3973
|
});
|
|
3676
|
-
const
|
|
3677
|
-
if (
|
|
3678
|
-
throw new Error(
|
|
3679
|
-
|
|
3974
|
+
const confirmation = await connection.confirmTransaction({ signature, blockhash, lastValidBlockHeight }, 'confirmed');
|
|
3975
|
+
if (confirmation.value.err) {
|
|
3976
|
+
throw new Error(`Turnkey transaction failed: ${JSON.stringify(confirmation.value.err)}`);
|
|
3977
|
+
}
|
|
3978
|
+
return signature;
|
|
3680
3979
|
}
|
|
3681
3980
|
|
|
3682
3981
|
// Same message the email provider uses when a hosted (OIDC) login has no
|
|
3683
3982
|
// embedded wallet — enable `auth.wallets` in policy to get one.
|
|
3684
|
-
const OIDC_NO_WALLET = 'This
|
|
3685
|
-
'
|
|
3686
|
-
'then sign from a user gesture.';
|
|
3983
|
+
const OIDC_NO_WALLET = 'This session has no Turnkey wallet. Sign in again to provision the default ' +
|
|
3984
|
+
'embedded wallet, or check whether the app explicitly sets auth.wallets:false.';
|
|
3687
3985
|
const PKCE_STORE_KEY = 'bounded.oidc.pkce';
|
|
3688
3986
|
const STORED_AUTH_METHOD_KEY$1 = 'bounded_last_auth_method';
|
|
3689
3987
|
const ISSUER_SESSION_KIND_KEY$1 = 'bounded_issuer_session_kind';
|
|
@@ -3709,10 +4007,8 @@ function decodeJwt(token) {
|
|
|
3709
4007
|
}
|
|
3710
4008
|
}
|
|
3711
4009
|
// A minimal AuthProvider so getSession()/logout() work for OIDC sessions, mirroring email.
|
|
3712
|
-
//
|
|
3713
|
-
//
|
|
3714
|
-
// through the Bounded signer popup; signMessage/signTransaction are structurally
|
|
3715
|
-
// unsupported for Crossmint smart wallets (sign+submit atomically, no raw sig).
|
|
4010
|
+
// Turnkey supplies the default Solana wallet and supports raw message and transaction
|
|
4011
|
+
// signatures through the Bounded signer window.
|
|
3716
4012
|
const oidcProviderSingleton = {
|
|
3717
4013
|
async login() {
|
|
3718
4014
|
const idToken = sessionManager().getIdToken();
|
|
@@ -3723,37 +4019,38 @@ const oidcProviderSingleton = {
|
|
|
3723
4019
|
return idToken ? userFromIdToken(idToken) : null;
|
|
3724
4020
|
},
|
|
3725
4021
|
async logout() { await sessionManager().clearSession(); },
|
|
3726
|
-
async signMessage(
|
|
3727
|
-
|
|
4022
|
+
async signMessage(message) {
|
|
4023
|
+
if (!hasTurnkeyWallet())
|
|
4024
|
+
throw new Error(OIDC_NO_WALLET);
|
|
4025
|
+
return signMessageWithTurnkey(message);
|
|
3728
4026
|
},
|
|
3729
|
-
async signTransaction(
|
|
3730
|
-
|
|
4027
|
+
async signTransaction(transaction) {
|
|
4028
|
+
if (!hasTurnkeyWallet())
|
|
4029
|
+
throw new Error(OIDC_NO_WALLET);
|
|
4030
|
+
return signTransactionWithTurnkey(transaction);
|
|
3731
4031
|
},
|
|
3732
|
-
async runTransaction(evm, sol,
|
|
4032
|
+
async runTransaction(evm, sol, _options) {
|
|
3733
4033
|
if (evm && sol)
|
|
3734
4034
|
throw new Error('A transaction cannot target EVM and Solana at the same time.');
|
|
3735
|
-
if (!
|
|
4035
|
+
if (!hasTurnkeyWallet())
|
|
3736
4036
|
throw new Error(OIDC_NO_WALLET);
|
|
3737
|
-
if (
|
|
3738
|
-
throw new Error('
|
|
3739
|
-
|
|
3740
|
-
throw new Error('This login has no embedded EVM wallet. Enable auth.wallets on an app with an EVM collection and sign in again.');
|
|
3741
|
-
return embeddedRunEvmTransaction(evm);
|
|
4037
|
+
if (evm)
|
|
4038
|
+
throw new Error('Turnkey embedded wallets currently support Solana only. Connect an EVM wallet for EVM transactions.');
|
|
4039
|
+
throw new Error('This Solana transaction shape is not supported by the Turnkey provider. Use a pre-built transaction.');
|
|
3742
4040
|
},
|
|
3743
|
-
async signAndSubmitTransaction(transaction,
|
|
3744
|
-
if (!
|
|
4041
|
+
async signAndSubmitTransaction(transaction, feePayer) {
|
|
4042
|
+
if (!hasTurnkeyWallet())
|
|
3745
4043
|
throw new Error(OIDC_NO_WALLET);
|
|
3746
|
-
return
|
|
4044
|
+
return signAndSubmitTransactionWithTurnkey(transaction, feePayer);
|
|
3747
4045
|
},
|
|
3748
4046
|
};
|
|
3749
4047
|
function userFromIdToken(idToken) {
|
|
3750
4048
|
const c = decodeJwt(idToken);
|
|
3751
4049
|
const id = c['custom:userId'] || c.sub || c['custom:walletAddress'] || '';
|
|
3752
4050
|
return {
|
|
3753
|
-
id,
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
: null,
|
|
4051
|
+
id,
|
|
4052
|
+
address: (c['custom:walletProvider'] === 'turnkey' && c['custom:walletAddress'] || null),
|
|
4053
|
+
evmAddress: null,
|
|
3757
4054
|
email: (c.email || null), provider: oidcProviderSingleton,
|
|
3758
4055
|
};
|
|
3759
4056
|
}
|
|
@@ -4476,7 +4773,7 @@ async function getAuthProvider(config) {
|
|
|
4476
4773
|
// manager as legacy email sessions. Human login should be started
|
|
4477
4774
|
// with loginWithRedirect(); this provider is kept as the restore and
|
|
4478
4775
|
// logout surface for those sessions.
|
|
4479
|
-
currentAuthProvider = new (await import('./email-auth-provider-
|
|
4776
|
+
currentAuthProvider = new (await import('./email-auth-provider-h0fPnU76.mjs')).EmailAuthProvider();
|
|
4480
4777
|
break;
|
|
4481
4778
|
case "wallet":
|
|
4482
4779
|
case "phantom": {
|
|
@@ -4495,7 +4792,7 @@ async function getAuthProvider(config) {
|
|
|
4495
4792
|
if (!isWalletLoginEnabled(config)) {
|
|
4496
4793
|
throw walletLoginNotEnabledError(authMethod);
|
|
4497
4794
|
}
|
|
4498
|
-
const { InjectedWalletProvider } = await import('./injected-wallet-provider-
|
|
4795
|
+
const { InjectedWalletProvider } = await import('./injected-wallet-provider-Dd7ij6bc.mjs');
|
|
4499
4796
|
currentAuthProvider = new InjectedWalletProvider(resolveInjectedWalletConfig(config), rpcUrl, configuredNetwork);
|
|
4500
4797
|
break;
|
|
4501
4798
|
}
|
|
@@ -4508,7 +4805,7 @@ async function getAuthProvider(config) {
|
|
|
4508
4805
|
// Selecting authMethod:'evm-wallet' IS the opt-in — pass evmWalletConfig
|
|
4509
4806
|
// to point at a specific wallet or set chainId/domain.
|
|
4510
4807
|
const evmWalletConfig = ((_a = config.evmWalletConfig) !== null && _a !== void 0 ? _a : {});
|
|
4511
|
-
const { InjectedEvmWalletProvider } = await import('./injected-evm-wallet-provider-
|
|
4808
|
+
const { InjectedEvmWalletProvider } = await import('./injected-evm-wallet-provider-xvZq9Zli.mjs');
|
|
4512
4809
|
currentAuthProvider = new InjectedEvmWalletProvider(evmWalletConfig);
|
|
4513
4810
|
break;
|
|
4514
4811
|
}
|
|
@@ -4536,7 +4833,7 @@ async function getAuthProvider(config) {
|
|
|
4536
4833
|
break;
|
|
4537
4834
|
case "guest":
|
|
4538
4835
|
// Anonymous auth: a device-local ed25519 keypair signs the challenge.
|
|
4539
|
-
currentAuthProvider = new (await import('./guest-auth-provider-
|
|
4836
|
+
currentAuthProvider = new (await import('./guest-auth-provider-Dmup2WIL.mjs')).GuestAuthProvider();
|
|
4540
4837
|
break;
|
|
4541
4838
|
}
|
|
4542
4839
|
if (!currentAuthProvider) {
|
|
@@ -4592,7 +4889,7 @@ async function signInAnonymously() {
|
|
|
4592
4889
|
// Lazy-load the guest provider so its ed25519/web3 dependencies stay out of
|
|
4593
4890
|
// the main bundle for data-only apps. Specifier is a static string literal
|
|
4594
4891
|
// so bundle-splitting can see it.
|
|
4595
|
-
const provider = new (await import('./guest-auth-provider-
|
|
4892
|
+
const provider = new (await import('./guest-auth-provider-Dmup2WIL.mjs')).GuestAuthProvider();
|
|
4596
4893
|
setAuthLoading(true); // reflect "signing in…" while the guest keypair session is minted
|
|
4597
4894
|
const commit = (user) => {
|
|
4598
4895
|
// No await/interleaving inside this block: provider/method/config/marker
|
|
@@ -6418,5 +6715,5 @@ class PrivyExpoProvider {
|
|
|
6418
6715
|
}
|
|
6419
6716
|
}
|
|
6420
6717
|
|
|
6421
|
-
export { useAuth as A, useQuery as B, useBuildRun as C, apps as D,
|
|
6422
|
-
//# sourceMappingURL=index.native-
|
|
6718
|
+
export { useAuth as A, useQuery as B, useBuildRun as C, apps as D, deserializeTransaction as E, getIdToken as F, onramp as G, onrampQuote as H, onrampStatus as I, setPlatform as J, builds as K, BuildsApiError as L, PARK_REASONS as M, NON_TERMINAL_STATES as N, OffchainAuthProvider as O, PrivyExpoProvider as P, FAILURE_REASONS as Q, RUN_STATES as R, BUILD_REVIEW_CAPABILITY_SCHEMA as S, TERMINAL_STATES as T, BUILD_REVIEW_CAPABILITY_REFRESH_SCHEMA as U, BUILD_DELEGATED_REVIEW_CAPABILITY_SCHEMA as V, signMessageWithTurnkey as a, signTransactionWithTurnkey as b, signAndSubmitTransactionWithTurnkey as c, setAuthLoading as d, bufferExports as e, bs58 as f, getPlatform as g, hasTurnkeyWallet as h, confirmAndCheckTransaction as i, init as j, getCurrentUser as k, onAuthLoadingChanged as l, getAuthLoading as m, normalizeSolanaRpcUrl as n, onAuthStateChanged as o, login as p, logout as q, resolveSolanaRpcUrl as r, setCurrentUser as s, getAuthProvider as t, signInAnonymously as u, loginWithPrivy as v, loginWithRedirect as w, completeLoginFromRedirect as x, loginWithPopup as y, completeLoginInPopup as z };
|
|
6719
|
+
//# sourceMappingURL=index.native-CWcQMPZd.mjs.map
|