@bounded-sh/client 0.0.62 → 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.
Files changed (56) hide show
  1. package/dist/auth/providers/email-auth-provider.d.ts +4 -4
  2. package/dist/auth/turnkey-signer-bridge.d.ts +5 -0
  3. package/dist/{email-auth-provider-BxV1zZA_.js → email-auth-provider-97CluDlZ.js} +27 -30
  4. package/dist/email-auth-provider-97CluDlZ.js.map +1 -0
  5. package/dist/{email-auth-provider-BttT2sZK.js → email-auth-provider-CKM4O5Z1.js} +27 -30
  6. package/dist/email-auth-provider-CKM4O5Z1.js.map +1 -0
  7. package/dist/{email-auth-provider-vWv0rnbd.mjs → email-auth-provider-h0fPnU76.mjs} +27 -30
  8. package/dist/email-auth-provider-h0fPnU76.mjs.map +1 -0
  9. package/dist/{email-auth-provider-Cb4VKA1E.mjs → email-auth-provider-v9xvY0Ky.mjs} +27 -30
  10. package/dist/email-auth-provider-v9xvY0Ky.mjs.map +1 -0
  11. package/dist/{guest-auth-provider-CeIZw5x6.mjs → guest-auth-provider-BLRbjAv2.mjs} +2 -2
  12. package/dist/{guest-auth-provider-CeIZw5x6.mjs.map → guest-auth-provider-BLRbjAv2.mjs.map} +1 -1
  13. package/dist/{guest-auth-provider-peD5Zasl.js → guest-auth-provider-BvIf5W5c.js} +2 -2
  14. package/dist/{guest-auth-provider-peD5Zasl.js.map → guest-auth-provider-BvIf5W5c.js.map} +1 -1
  15. package/dist/{guest-auth-provider-BcR-MQ0g.js → guest-auth-provider-CLnFuodt.js} +2 -2
  16. package/dist/{guest-auth-provider-BcR-MQ0g.js.map → guest-auth-provider-CLnFuodt.js.map} +1 -1
  17. package/dist/{guest-auth-provider-BBPpydtM.mjs → guest-auth-provider-Dmup2WIL.mjs} +2 -2
  18. package/dist/{guest-auth-provider-BBPpydtM.mjs.map → guest-auth-provider-Dmup2WIL.mjs.map} +1 -1
  19. package/dist/{index-DpJl_Cpa.mjs → index-7yz-Olrm.mjs} +1366 -1519
  20. package/dist/index-7yz-Olrm.mjs.map +1 -0
  21. package/dist/{index-DEDYfO2p.js → index-Bk0nEjB6.js} +1368 -1522
  22. package/dist/index-Bk0nEjB6.js.map +1 -0
  23. package/dist/index.js +1 -1
  24. package/dist/index.mjs +1 -1
  25. package/dist/{index.native-BIUs8t7F.mjs → index.native-CWcQMPZd.mjs} +518 -221
  26. package/dist/index.native-CWcQMPZd.mjs.map +1 -0
  27. package/dist/{index.native-BSheiGj2.js → index.native-Do-VhPUG.js} +520 -224
  28. package/dist/index.native-Do-VhPUG.js.map +1 -0
  29. package/dist/index.native.js +1 -1
  30. package/dist/index.native.mjs +1 -1
  31. package/dist/{injected-evm-wallet-provider-B-9VXQcH.js → injected-evm-wallet-provider-B5MA0w8I.js} +2 -2
  32. package/dist/{injected-evm-wallet-provider-B-9VXQcH.js.map → injected-evm-wallet-provider-B5MA0w8I.js.map} +1 -1
  33. package/dist/{injected-evm-wallet-provider-7XawIUdJ.js → injected-evm-wallet-provider-BMiT8I-4.js} +2 -2
  34. package/dist/{injected-evm-wallet-provider-7XawIUdJ.js.map → injected-evm-wallet-provider-BMiT8I-4.js.map} +1 -1
  35. package/dist/{injected-evm-wallet-provider-BVsxOzYr.mjs → injected-evm-wallet-provider-DlPsOmik.mjs} +2 -2
  36. package/dist/{injected-evm-wallet-provider-BVsxOzYr.mjs.map → injected-evm-wallet-provider-DlPsOmik.mjs.map} +1 -1
  37. package/dist/{injected-evm-wallet-provider-DnOrVMDX.mjs → injected-evm-wallet-provider-xvZq9Zli.mjs} +2 -2
  38. package/dist/{injected-evm-wallet-provider-DnOrVMDX.mjs.map → injected-evm-wallet-provider-xvZq9Zli.mjs.map} +1 -1
  39. package/dist/{injected-wallet-provider-D574oPzH.js → injected-wallet-provider-CSj0lY9H.js} +2 -2
  40. package/dist/{injected-wallet-provider-D574oPzH.js.map → injected-wallet-provider-CSj0lY9H.js.map} +1 -1
  41. package/dist/{injected-wallet-provider-BMDJntMD.js → injected-wallet-provider-CoE5XQQn.js} +2 -2
  42. package/dist/{injected-wallet-provider-BMDJntMD.js.map → injected-wallet-provider-CoE5XQQn.js.map} +1 -1
  43. package/dist/{injected-wallet-provider-ZkPzVj5W.mjs → injected-wallet-provider-Dd7ij6bc.mjs} +2 -2
  44. package/dist/{injected-wallet-provider-ZkPzVj5W.mjs.map → injected-wallet-provider-Dd7ij6bc.mjs.map} +1 -1
  45. package/dist/{injected-wallet-provider-Bqk33sir.mjs → injected-wallet-provider-YHhhFzsj.mjs} +2 -2
  46. package/dist/{injected-wallet-provider-Bqk33sir.mjs.map → injected-wallet-provider-YHhhFzsj.mjs.map} +1 -1
  47. package/package.json +2 -2
  48. package/dist/auth/crossmint-signer-bridge.d.ts +0 -45
  49. package/dist/email-auth-provider-BttT2sZK.js.map +0 -1
  50. package/dist/email-auth-provider-BxV1zZA_.js.map +0 -1
  51. package/dist/email-auth-provider-Cb4VKA1E.mjs.map +0 -1
  52. package/dist/email-auth-provider-vWv0rnbd.mjs.map +0 -1
  53. package/dist/index-DEDYfO2p.js.map +0 -1
  54. package/dist/index-DpJl_Cpa.mjs.map +0 -1
  55. package/dist/index.native-BIUs8t7F.mjs.map +0 -1
  56. package/dist/index.native-BSheiGj2.js.map +0 -1
@@ -868,6 +868,8 @@ function getDefaultExportFromCjs (x) {
868
868
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
869
869
  }
870
870
 
871
+ var safeBuffer = {exports: {}};
872
+
871
873
  var buffer = {};
872
874
 
873
875
  var base64Js = {};
@@ -3237,10 +3239,6 @@ function requireBuffer () {
3237
3239
  return buffer;
3238
3240
  }
3239
3241
 
3240
- var bufferExports = requireBuffer();
3241
-
3242
- var safeBuffer = {exports: {}};
3243
-
3244
3242
  /*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
3245
3243
 
3246
3244
  var hasRequiredSafeBuffer;
@@ -3454,173 +3452,448 @@ var basex = /*@__PURE__*/getDefaultExportFromCjs(srcExports);
3454
3452
  var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
3455
3453
  var bs58 = basex(ALPHABET);
3456
3454
 
3457
- // crossmint-signer-bridge.ts — routes embedded-wallet signing through the
3458
- // Bounded-owned signer popup (auth.bounded.sh/wallet/signer).
3455
+ var bufferExports = requireBuffer();
3456
+
3457
+ // bounded-widget-modal.ts - the shared in-app WIDGET shell for Bounded's login
3458
+ // and signing surfaces. One Shadow-DOM overlay + panel that matches the Bounded
3459
+ // widget (Seal) look and MOTION: a backdrop fade, a panel rise on desktop, a
3460
+ // bottom-sheet on mobile, a height tween as content swaps, and a clean close.
3461
+ //
3462
+ // It hosts EITHER:
3463
+ // - NATIVE content (the login card the SDK renders itself), or
3464
+ // - an IFRAME (the Bounded-owned signer page, which must run on the single
3465
+ // signer origin because a WebAuthn passkey is bound to one origin).
3466
+ //
3467
+ // The modal is a warm singleton: it stays mounted (hidden) between uses so a
3468
+ // second open - or a signature right after login - is instant and, when it is
3469
+ // already open, a clean in-place view swap rather than a reopen.
3470
+ function hasDOM$3() {
3471
+ return typeof window !== "undefined" && typeof document !== "undefined";
3472
+ }
3473
+ const OVERLAY_CSS = `
3474
+ :host{all:initial}
3475
+ *{box-sizing:border-box}
3476
+ .bw-ov{position:fixed;inset:0;z-index:2147483647;display:none;
3477
+ font-family:"Schibsted Grotesk","Helvetica Neue",Arial,sans-serif}
3478
+ .bw-ov.mounted{display:block}
3479
+ .bw-back{position:fixed;inset:0;background:rgba(4,4,5,.62);opacity:0;
3480
+ transition:opacity .24s ease;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px)}
3481
+ .bw-wrap{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;padding:20px}
3482
+ .bw-panel{position:relative;width:420px;max-width:calc(100vw - 28px);height:280px;
3483
+ border-radius:14px;overflow:hidden;background:#0e0f11;border:1px solid rgba(232,230,222,.08);
3484
+ box-shadow:0 1px 0 rgba(232,230,222,.03) inset,0 40px 90px -45px rgba(0,0,0,.85);
3485
+ opacity:0;transform:translateY(14px) scale(.98);will-change:transform,opacity,height;
3486
+ transition:opacity .28s cubic-bezier(.2,.8,.2,1),transform .28s cubic-bezier(.2,.8,.2,1),
3487
+ height .3s cubic-bezier(.2,.8,.2,1)}
3488
+ .bw-ov.show .bw-back{opacity:1}
3489
+ .bw-ov.show .bw-panel{opacity:1;transform:none}
3490
+ .bw-ov.closing .bw-back{opacity:0}
3491
+ .bw-ov.closing .bw-panel{opacity:0;transform:translateY(12px) scale(.99)}
3492
+ .bw-content{position:absolute;inset:0;overflow:hidden}
3493
+ .bw-frame{display:block;width:100%;height:100%;border:0;background:transparent;color-scheme:dark}
3494
+ /* editorial corner crop-marks, matching the reference frame */
3495
+ .bw-mk{position:absolute;width:13px;height:13px;pointer-events:none;z-index:2;
3496
+ border-color:rgba(232,230,222,.22);border-style:solid;border-width:0}
3497
+ .bw-mk.tl{top:11px;left:11px;border-top-width:1px;border-left-width:1px}
3498
+ .bw-mk.tr{top:11px;right:11px;border-top-width:1px;border-right-width:1px}
3499
+ .bw-mk.bl{bottom:11px;left:11px;border-bottom-width:1px;border-left-width:1px}
3500
+ .bw-mk.br{bottom:11px;right:11px;border-bottom-width:1px;border-right-width:1px}
3501
+ @media(max-width:560px){
3502
+ .bw-wrap{align-items:flex-end;padding:0}
3503
+ .bw-panel{width:100%;max-width:100%;border-radius:18px 18px 0 0;border-bottom:0}
3504
+ .bw-content{overflow-y:auto}
3505
+ .bw-ov.show .bw-panel{transform:none}
3506
+ .bw-ov:not(.show) .bw-panel,.bw-ov.closing .bw-panel{transform:translateY(18%)}
3507
+ }
3508
+ @media(prefers-reduced-motion:reduce){.bw-back,.bw-panel{transition:opacity .12s linear!important}}
3509
+ `;
3510
+ let modal = null;
3511
+ function getModal() {
3512
+ if (modal)
3513
+ return modal;
3514
+ const root = document.createElement("div");
3515
+ root.setAttribute("data-bounded-widget", "");
3516
+ const shadow = root.attachShadow({ mode: "open" });
3517
+ const style = document.createElement("style");
3518
+ style.textContent = OVERLAY_CSS;
3519
+ shadow.appendChild(style);
3520
+ const overlay = document.createElement("div");
3521
+ overlay.className = "bw-ov";
3522
+ const back = document.createElement("div");
3523
+ back.className = "bw-back";
3524
+ const wrap = document.createElement("div");
3525
+ wrap.className = "bw-wrap";
3526
+ const panel = document.createElement("div");
3527
+ panel.className = "bw-panel";
3528
+ const content = document.createElement("div");
3529
+ content.className = "bw-content";
3530
+ panel.appendChild(content);
3531
+ for (const corner of ["tl", "tr", "bl", "br"]) {
3532
+ const mk = document.createElement("span");
3533
+ mk.className = "bw-mk " + corner;
3534
+ panel.appendChild(mk);
3535
+ }
3536
+ wrap.appendChild(panel);
3537
+ overlay.appendChild(back);
3538
+ overlay.appendChild(wrap);
3539
+ shadow.appendChild(overlay);
3540
+ (document.body || document.documentElement).appendChild(root);
3541
+ const m = {
3542
+ root,
3543
+ overlay,
3544
+ panel,
3545
+ content,
3546
+ iframe: null,
3547
+ iframeOrigin: "",
3548
+ iframeReady: false,
3549
+ onBackdrop: null,
3550
+ onIframeMessage: null,
3551
+ chain: Promise.resolve(),
3552
+ fitObserver: null,
3553
+ };
3554
+ // The dismiss handler lives on `.bw-wrap`: it is the full-viewport flex layer
3555
+ // that sits ABOVE `.bw-back`, so it (not the backdrop element) receives clicks
3556
+ // outside the panel. Fire only when the click lands on the wrap itself, never
3557
+ // when it bubbles up from the panel or its content.
3558
+ wrap.addEventListener("click", (event) => {
3559
+ if (event.target === wrap && m.onBackdrop)
3560
+ m.onBackdrop();
3561
+ });
3562
+ window.addEventListener("message", (event) => {
3563
+ if (!m.iframe)
3564
+ return;
3565
+ if (event.origin !== m.iframeOrigin)
3566
+ return;
3567
+ if (event.source !== m.iframe.contentWindow)
3568
+ return;
3569
+ const d = event.data;
3570
+ if (!d || typeof d !== "object")
3571
+ return;
3572
+ if (m.onIframeMessage)
3573
+ m.onIframeMessage(d);
3574
+ });
3575
+ modal = m;
3576
+ return m;
3577
+ }
3578
+ function showModal(m) {
3579
+ m.overlay.classList.remove("closing");
3580
+ m.overlay.classList.add("mounted");
3581
+ // Force a reflow so the .show transition runs from the hidden state every open.
3582
+ void m.panel.offsetWidth;
3583
+ m.overlay.classList.add("show");
3584
+ }
3585
+ function hideModal(m, after) {
3586
+ m.overlay.classList.remove("show");
3587
+ m.overlay.classList.add("closing");
3588
+ window.setTimeout(() => {
3589
+ m.overlay.classList.remove("mounted", "closing");
3590
+ }, 260);
3591
+ }
3592
+ function setPanelHeight(m, px) {
3593
+ const h = Math.max(140, Math.min(680, Math.round(px)));
3594
+ m.panel.style.height = h + "px";
3595
+ }
3596
+ /** Get (or lazily create) the warm iframe for signer/hosted-page mode. */
3597
+ function ensureIframe(m, url, origin) {
3598
+ var _a;
3599
+ if (m.iframe && m.iframeOrigin === origin && m.iframe.src === url)
3600
+ return m.iframe;
3601
+ detachIframe(m);
3602
+ (_a = m.fitObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
3603
+ m.fitObserver = null;
3604
+ m.content.style.display = "none";
3605
+ const iframe = document.createElement("iframe");
3606
+ iframe.className = "bw-frame";
3607
+ iframe.setAttribute("title", "Bounded");
3608
+ // Grant the framed origin WebAuthn get + create so passkey enroll/sign run
3609
+ // inside the frame from the user's click (transient activation stays in-frame).
3610
+ iframe.setAttribute("allow", "publickey-credentials-get; publickey-credentials-create; clipboard-write");
3611
+ iframe.src = url;
3612
+ m.iframeOrigin = origin;
3613
+ m.iframeReady = false;
3614
+ m.panel.appendChild(iframe);
3615
+ m.iframe = iframe;
3616
+ return iframe;
3617
+ }
3618
+ function detachIframe(m) {
3619
+ if (m.iframe) {
3620
+ try {
3621
+ m.iframe.remove();
3622
+ }
3623
+ catch (_a) {
3624
+ /* ignore */
3625
+ }
3626
+ }
3627
+ m.iframe = null;
3628
+ m.iframeReady = false;
3629
+ m.iframeOrigin = "";
3630
+ m.onIframeMessage = null;
3631
+ }
3632
+
3633
+ // turnkey-wallet-widget.ts - runs one Turnkey signer exchange inside the shared
3634
+ // in-app WIDGET (bounded-widget-modal.ts). The Bounded-owned signer page is loaded
3635
+ // in a warm iframe behind the modal so signing feels native: an in-app card plus
3636
+ // the OS Face ID / Touch ID sheet, never a jarring popup.
3637
+ //
3638
+ // WHY AN IFRAME: a WebAuthn passkey is bound to ONE origin, so passkey create/sign
3639
+ // MUST run on the single Bounded signer origin. The iframe carries the
3640
+ // publickey-credentials-{get,create} permission policy and the user's click lands
3641
+ // INSIDE it, giving WebAuthn the transient activation it needs.
3642
+ //
3643
+ // SAFARI / restricted embedders: cross-origin iframe passkey CREATE is unreliable
3644
+ // in Safari. The signer detects that and posts `fallbackPopup`; we then rerun the
3645
+ // SAME request through `popupFallback` (a real window). Callers pass a popup
3646
+ // implementation and never see the difference.
3647
+ /**
3648
+ * Run one signer exchange through the in-app widget. Resolves when `onResult`
3649
+ * accepts a result; falls back to `popupFallback` if the frame cannot run WebAuthn
3650
+ * (Safari cross-origin create) or cannot be mounted.
3651
+ */
3652
+ async function runWidget(url, signerOrigin, ex, popupFallback) {
3653
+ if (!hasDOM$3())
3654
+ return popupFallback();
3655
+ const m = getModal();
3656
+ const requestId = String(ex.request.requestId);
3657
+ // Serialize: WebAuthn is modal, and one warm frame handles one request at a time.
3658
+ const run = m.chain.then(() => new Promise((resolve, reject) => {
3659
+ let settled = false;
3660
+ let usedFallback = false;
3661
+ const iframe = ensureIframe(m, url, signerOrigin);
3662
+ const send = () => {
3663
+ if (!iframe.contentWindow)
3664
+ return;
3665
+ try {
3666
+ iframe.contentWindow.postMessage(ex.request, signerOrigin);
3667
+ }
3668
+ catch (_a) {
3669
+ /* frame gone */
3670
+ }
3671
+ };
3672
+ let loadTimer = 0;
3673
+ let ceilingTimer = 0;
3674
+ const finish = (fn) => {
3675
+ if (settled)
3676
+ return;
3677
+ settled = true;
3678
+ m.onIframeMessage = null;
3679
+ m.onBackdrop = null;
3680
+ window.clearTimeout(loadTimer);
3681
+ window.clearTimeout(ceilingTimer);
3682
+ fn();
3683
+ };
3684
+ const goFallback = () => {
3685
+ if (usedFallback || settled)
3686
+ return;
3687
+ usedFallback = true;
3688
+ hideModal(m);
3689
+ finish(() => popupFallback().then(resolve, reject));
3690
+ };
3691
+ m.onBackdrop = () => {
3692
+ hideModal(m);
3693
+ finish(() => reject(new Error("cancelled")));
3694
+ };
3695
+ m.onIframeMessage = (d) => {
3696
+ if (d.type === "bounded:turnkey:ready") {
3697
+ m.iframeReady = true;
3698
+ send();
3699
+ return;
3700
+ }
3701
+ if (d.type === "bounded:turnkey:resize" && typeof d.height === "number") {
3702
+ setPanelHeight(m, d.height);
3703
+ return;
3704
+ }
3705
+ if (d.type === "bounded:turnkey:fallbackPopup" && d.requestId === requestId) {
3706
+ goFallback();
3707
+ return;
3708
+ }
3709
+ if (d.type === "bounded:turnkey:result" && d.requestId === requestId) {
3710
+ const outcome = ex.onResult(d);
3711
+ if ("error" in outcome) {
3712
+ hideModal(m);
3713
+ finish(() => reject(new Error(outcome.error)));
3714
+ return;
3715
+ }
3716
+ if (outcome.done) {
3717
+ hideModal(m);
3718
+ finish(() => resolve(outcome.value));
3719
+ }
3720
+ }
3721
+ };
3722
+ showModal(m);
3723
+ if (m.iframeReady)
3724
+ send();
3725
+ // If the frame never loads, degrade to the popup (best-effort - a post-load
3726
+ // popup may be blocked without a gesture, in which case the fallback rejects).
3727
+ loadTimer = window.setTimeout(() => {
3728
+ if (!m.iframeReady && !settled)
3729
+ goFallback();
3730
+ }, 8000);
3731
+ // Absolute ceiling so a stuck flow cannot hang forever.
3732
+ ceilingTimer = window.setTimeout(() => {
3733
+ if (!settled) {
3734
+ hideModal(m);
3735
+ finish(() => reject(new Error("Wallet approval timed out.")));
3736
+ }
3737
+ }, 5 * 60 * 1000);
3738
+ }));
3739
+ m.chain = run.then(() => undefined, () => undefined);
3740
+ return run;
3741
+ }
3742
+
3743
+ // turnkey-signer-bridge.ts - routes NON-CUSTODIAL Turnkey embedded-wallet signing
3744
+ // through the Bounded-owned signer page (auth.bounded.sh/wallet/turnkey/signer).
3459
3745
  //
3460
- // Slice-1 attached a non-custodial Crossmint smart wallet to email logins and
3461
- // populated `@user.address`. This bridge is the slice-2 counterpart: a user
3462
- // whose address came from `auth.wallets` can APPROVE transactions with that
3463
- // wallet from ANY app, non-custodially, by having the Crossmint client SDK run
3464
- // ONLY on the Bounded signer page (one whitelisted origin) and talking to it via
3465
- // postMessage.
3746
+ // TRANSPORT: by default the signer runs inside the in-app WIDGET (turnkey-wallet-
3747
+ // widget.ts) - an iframe behind a Shadow-DOM modal that matches the Bounded widget
3748
+ // look + motion, so signing feels native. Safari (unreliable at iframe passkey
3749
+ // CREATE) and any environment where the frame cannot mount fall back to a real
3750
+ // popup window; both transports speak the same postMessage protocol.
3466
3751
  //
3467
- // SEMANTICS (Crossmint Solana smart wallets): these wallets cannot produce raw
3468
- // detached signatures — there is no signMessage and no sign-without-submit. The
3469
- // only honest primitive is EXECUTION (sign + submit) via the wallet's email-OTP
3470
- // authorization. So this bridge implements `signAndSubmitTransaction` and a
3471
- // token-send; `signMessage` / `signTransaction` throw a clear unsupported error.
3472
- const EMBEDDED_WALLET_UNSUPPORTED = 'Unsupported for embedded smart wallets — Crossmint Solana smart wallets sign ' +
3473
- 'and submit atomically. Use signAndSubmitTransaction() (or bounded.sendWalletToken) ' +
3474
- 'instead of signMessage/signTransaction.';
3475
- const NO_EMBEDDED_WALLET = 'This login has no embedded wallet. Enable `"auth": { "wallets": true }` in ' +
3476
- 'the app policy so email logins get a non-custodial wallet (@user.address), ' +
3477
- 'then sign from a user gesture.';
3752
+ // Turnkey wallets produce raw detached signatures. The signer runs the Turnkey
3753
+ // browser SDK on the single Bounded origin and stamps an ed25519 signRawPayload
3754
+ // with the user's passkey. The app retains the transaction itself.
3755
+ //
3756
+ // ONE ORIGIN, ONE PASSKEY: a WebAuthn passkey is bound to a single origin, so ALL
3757
+ // Bounded apps (any subdomain / custom domain) sign through this one origin - giving
3758
+ // every user one wallet + one passkey that roams across every app.
3478
3759
  function hasDOM$2() {
3479
3760
  return typeof window !== 'undefined' && typeof document !== 'undefined';
3480
3761
  }
3762
+ // Safari (incl. iOS WebViews) is unreliable at running a WebAuthn CREATE inside a
3763
+ // cross-origin iframe, so the widget's automatic in-iframe passkey enrollment can
3764
+ // fail - and a post-failure popup would no longer have a user gesture to open with.
3765
+ // There we pick the popup up front, from the original click, so enrollment is solid.
3766
+ // Everywhere else the inline widget is used (buttery in-app modal).
3767
+ function preferPopup() {
3768
+ if (!hasDOM$2() || typeof navigator === 'undefined')
3769
+ return true;
3770
+ const ua = navigator.userAgent || '';
3771
+ return /^((?!chrome|android|crios|fxios|edg|edga|opr).)*safari/i.test(ua);
3772
+ }
3773
+ // Dispatch one signer exchange through the in-app WIDGET, degrading to the POPUP
3774
+ // when we cannot embed (Safari enrollment, or the frame never loads).
3775
+ async function deliver(url, origin, ex) {
3776
+ const popup = () => runPopup(url, origin, ex);
3777
+ if (preferPopup())
3778
+ return popup();
3779
+ return runWidget(url, origin, { request: ex.request, onResult: ex.onResult }, popup);
3780
+ }
3781
+ async function turnkeySignerPage() {
3782
+ const cfg = await core.getConfig();
3783
+ const base = (cfg.humanAuthApiUrl || 'https://auth.bounded.sh').replace(/\/$/, '');
3784
+ return { url: `${base}/wallet/turnkey/signer`, origin: new URL(base).origin };
3785
+ }
3786
+ function toHex(bytes) {
3787
+ let h = '';
3788
+ for (const b of bytes)
3789
+ h += b.toString(16).padStart(2, '0');
3790
+ return h;
3791
+ }
3792
+ function fromHex(hex) {
3793
+ const clean = hex.startsWith('0x') ? hex.slice(2) : hex;
3794
+ const out = new Uint8Array(clean.length / 2);
3795
+ for (let i = 0; i < out.length; i++)
3796
+ out[i] = parseInt(clean.substr(i * 2, 2), 16);
3797
+ return out;
3798
+ }
3481
3799
  function decodeJwt$1(token) {
3482
3800
  try {
3483
- let b64 = token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/');
3484
- const pad = b64.length % 4;
3485
- if (pad === 2)
3486
- b64 += '==';
3487
- else if (pad === 3)
3488
- b64 += '=';
3489
- return JSON.parse(bufferExports.Buffer.from(b64, 'base64').toString('utf8'));
3801
+ let value = token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/');
3802
+ const padding = value.length % 4;
3803
+ if (padding === 2)
3804
+ value += '==';
3805
+ else if (padding === 3)
3806
+ value += '=';
3807
+ return JSON.parse(getPlatform().atob(value));
3490
3808
  }
3491
3809
  catch (_a) {
3492
3810
  return {};
3493
3811
  }
3494
3812
  }
3495
- // Pull the embedded-wallet identity out of the active session's id token.
3496
- // Returns null when this session has no wallet (so callers can throw the
3497
- // informative NO_EMBEDDED_WALLET error).
3498
- function walletClaimsFromSession(chain = 'solana') {
3499
- let idToken = null;
3813
+ function activeTurnkeyAddress() {
3814
+ let token = null;
3500
3815
  try {
3501
- idToken = core.getActiveSessionManager().getIdToken();
3816
+ token = core.getActiveSessionManager().getIdToken();
3502
3817
  }
3503
3818
  catch (_a) {
3504
- idToken = null;
3819
+ token = null;
3505
3820
  }
3506
- if (!idToken)
3507
- return null;
3508
- const c = decodeJwt$1(idToken);
3509
- const address = c['custom:walletAddress'];
3510
- const evmAddress = c['custom:evmWalletAddress'];
3511
- const email = c['email'];
3512
- if (typeof email !== 'string' || !email)
3821
+ if (!token)
3513
3822
  return null;
3514
- if (chain === 'solana' && (typeof address !== 'string' || !address))
3515
- return null;
3516
- if (chain === 'evm' && (typeof evmAddress !== 'string' || !/^0x[0-9a-fA-F]{40}$/.test(evmAddress)))
3517
- return null;
3518
- const envClaim = c['custom:walletEnvironment'];
3519
- const environment = envClaim === 'staging' || envClaim === 'production' ? envClaim : undefined;
3520
- return Object.assign(Object.assign(Object.assign({ email }, (typeof address === 'string' && address ? { address } : {})), (typeof evmAddress === 'string' ? { evmAddress: evmAddress.toLowerCase() } : {})), { environment });
3521
- }
3522
- async function signerPageUrl() {
3523
- const cfg = await core.getConfig();
3524
- const base = (cfg.humanAuthApiUrl || 'https://auth.bounded.sh').replace(/\/$/, '');
3525
- return { url: `${base}/wallet/signer`, origin: new URL(base).origin };
3823
+ const claims = decodeJwt$1(token);
3824
+ const address = claims['custom:walletAddress'];
3825
+ const provider = claims['custom:walletProvider'];
3826
+ return provider === 'turnkey' && typeof address === 'string' && address
3827
+ ? address
3828
+ : null;
3526
3829
  }
3527
3830
  let requestSeq = 0;
3528
- /**
3529
- * Open the Bounded signer popup, send `action` to it, and resolve with the
3530
- * submitted transaction result. Must be called from a USER GESTURE (click/tap) or
3531
- * the browser will block the popup — in which case this rejects with a clear
3532
- * "Popup blocked" error telling the app to call from a user gesture.
3533
- *
3534
- * Non-custodial: the popup gates signing behind an email OTP delivered to the
3535
- * wallet's owner, and validates that the wallet address matches the account.
3536
- */
3537
- async function signViaSignerPopup(action) {
3538
- if (!hasDOM$2()) {
3539
- throw new Error('Embedded-wallet signing is only available in the browser (popup-based).');
3540
- }
3541
- const isEvm = action.kind === 'evmTransaction';
3542
- const claims = walletClaimsFromSession(isEvm ? 'evm' : 'solana');
3543
- if (!claims)
3544
- throw new Error(NO_EMBEDDED_WALLET);
3545
- const { url, origin: signerOrigin } = await signerPageUrl();
3546
- const requestId = `bsign_${Date.now()}_${++requestSeq}`;
3547
- // Centered popup, sized for the OTP form (matches the OIDC login popup shape).
3548
- const w = 420, h = 600;
3831
+ // Shared popup driver: open the signer page, do the ready/postMessage handshake, and
3832
+ // resolve when `onResult` accepts a result message. Origin + source are pinned.
3833
+ async function runPopup(url, signerOrigin, ex) {
3834
+ var _a, _b;
3835
+ const w = (_a = ex.width) !== null && _a !== void 0 ? _a : 420, h = (_b = ex.height) !== null && _b !== void 0 ? _b : 620;
3549
3836
  const left = window.screenX + Math.max(0, (window.outerWidth - w) / 2);
3550
3837
  const top = window.screenY + Math.max(0, (window.outerHeight - h) / 2);
3551
- const popup = window.open(url, 'bounded-wallet-signer', `width=${w},height=${h},left=${left},top=${top}`);
3838
+ const popup = window.open(url, 'bounded-turnkey-signer', `width=${w},height=${h},left=${left},top=${top}`);
3552
3839
  if (!popup) {
3553
- throw new Error('Popup blocked — call signAndSubmitTransaction() from a user gesture (e.g. a click handler) so the wallet approval window can open.');
3554
- }
3555
- const request = {
3556
- type: 'bounded:sign',
3557
- requestId,
3558
- environment: claims.environment, // may be undefined → page auto-detects
3559
- email: claims.email,
3560
- address: isEvm ? claims.evmAddress : claims.address,
3561
- action,
3562
- };
3840
+ throw new Error('Popup blocked - call this from a user gesture (e.g. a click handler) so the passkey approval window can open.');
3841
+ }
3563
3842
  return await new Promise((resolve, reject) => {
3564
3843
  let settled = false;
3565
- let closeTimer;
3566
3844
  let sentRequest = false;
3567
- const cleanup = () => {
3568
- settled = true;
3569
- window.removeEventListener('message', onMsg);
3570
- if (closeTimer)
3571
- clearInterval(closeTimer);
3572
- };
3573
- const sendRequest = () => {
3574
- if (sentRequest)
3845
+ let closeTimer;
3846
+ const cleanup = () => { settled = true; window.removeEventListener('message', onMsg); if (closeTimer)
3847
+ clearInterval(closeTimer); };
3848
+ const sendRequest = () => { if (sentRequest)
3849
+ return; sentRequest = true; try {
3850
+ popup.postMessage(ex.request, signerOrigin);
3851
+ }
3852
+ catch ( /* popup gone */_a) { /* popup gone */ } };
3853
+ const onMsg = (event) => {
3854
+ if (event.origin !== signerOrigin)
3575
3855
  return;
3576
- sentRequest = true;
3577
- try {
3578
- popup.postMessage(request, signerOrigin);
3579
- }
3580
- catch ( /* popup gone */_a) { /* popup gone */ }
3581
- };
3582
- const onMsg = (ev) => {
3583
- if (ev.origin !== signerOrigin)
3584
- return; // only trust the signer page origin
3585
- if (ev.source !== popup)
3586
- return; // only trust this signer popup window
3587
- const d = ev.data;
3856
+ if (event.source !== popup)
3857
+ return;
3858
+ const d = event.data;
3588
3859
  if (!d || typeof d !== 'object')
3589
3860
  return;
3590
- if (d.type === 'bounded:signer:ready') {
3861
+ if (d.type === 'bounded:turnkey:ready') {
3591
3862
  sendRequest();
3592
3863
  return;
3593
3864
  }
3594
- if (d.type === 'bounded:signer:result' && d.requestId === requestId) {
3595
- cleanup();
3596
- try {
3597
- popup.close();
3865
+ if (d.type === 'bounded:turnkey:result' && d.requestId === ex.request.requestId) {
3866
+ const outcome = ex.onResult(d);
3867
+ if ('error' in outcome) {
3868
+ cleanup();
3869
+ try {
3870
+ popup.close();
3871
+ }
3872
+ catch ( /* ignore */_a) { /* ignore */ }
3873
+ reject(new Error(outcome.error));
3874
+ return;
3875
+ }
3876
+ if (outcome.done) {
3877
+ cleanup();
3878
+ try {
3879
+ popup.close();
3880
+ }
3881
+ catch ( /* ignore */_b) { /* ignore */ }
3882
+ resolve(outcome.value);
3598
3883
  }
3599
- catch ( /* ignore */_a) { /* ignore */ }
3600
- if (d.ok)
3601
- resolve({ hash: d.hash, explorerLink: d.explorerLink, transactionId: d.transactionId });
3602
- else
3603
- reject(new Error(String(d.error || 'Wallet signing failed')));
3604
3884
  }
3605
3885
  };
3606
3886
  window.addEventListener('message', onMsg);
3607
- // Fallback: if the ready ping was missed (fast load / focus race), push the
3608
- // request shortly after opening. The page ignores it until a bounded:sign
3609
- // arrives and only acts on the first one, so a duplicate is harmless.
3610
3887
  setTimeout(sendRequest, 1200);
3611
- // If the user closes the popup before completing, reject (unless a result
3612
- // just arrived — give any in-flight message a beat to settle first).
3613
3888
  closeTimer = setInterval(() => {
3614
3889
  if (popup.closed) {
3615
3890
  clearInterval(closeTimer);
3616
3891
  setTimeout(() => { if (!settled) {
3617
3892
  cleanup();
3618
- reject(new Error('Wallet approval window was closed before signing completed.'));
3893
+ reject(new Error('Wallet approval window was closed before it completed.'));
3619
3894
  } }, 400);
3620
3895
  }
3621
3896
  }, 500);
3622
- // Overall safety timeout (OTP + signing). Generous — the user may take a
3623
- // while to fetch the code from their email.
3624
3897
  setTimeout(() => { if (!settled) {
3625
3898
  cleanup();
3626
3899
  try {
@@ -3631,80 +3904,105 @@ async function signViaSignerPopup(action) {
3631
3904
  } }, 5 * 60 * 1000);
3632
3905
  });
3633
3906
  }
3634
- // Serialize a legacy or versioned Solana transaction to BASE58 for the signer
3635
- // page. Crossmint's smart-wallet createTransaction endpoint requires the
3636
- // `serializedTransaction` string to be base58 — it rejects base64 with
3637
- // "Invalid base58 string" (verified against Crossmint staging 2026-07-07). The
3638
- // `wallets-sdk` object path bs58-encodes internally, so base58 is the contract.
3639
- //
3640
- // We do NOT require existing signatures (the smart wallet signs on the page);
3641
- // Crossmint extracts the instructions, overrides the fee payer to its sponsor,
3642
- // and re-wraps them for the smart wallet.
3643
- function serializeTransaction(transaction) {
3644
- const isLegacy = 'recentBlockhash' in transaction &&
3645
- !('message' in transaction && 'staticAccountKeys' in transaction.message);
3646
- const bytes = isLegacy
3647
- ? transaction.serialize({ requireAllSignatures: false, verifySignatures: false })
3648
- : transaction.serialize();
3649
- return bs58.encode(bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes));
3907
+ function hasTurnkeyWallet() {
3908
+ return activeTurnkeyAddress() !== null;
3650
3909
  }
3651
3910
  /**
3652
- * Whether the active session carries an embedded wallet (so the provider should
3653
- * route signing through the popup rather than throw "no wallet").
3911
+ * Open the Bounded Turnkey signer popup and sign `message` (raw bytes) with the
3912
+ * user's non-custodial Turnkey wallet, resolving with the ed25519 signature +
3913
+ * the wallet address. MUST be called from a USER GESTURE (click/tap) or the
3914
+ * browser blocks the popup.
3915
+ *
3916
+ * On the user's FIRST signature the popup transparently enrolls a device passkey
3917
+ * (Face ID / Touch ID) and creates their wallet - no email code. Subsequent
3918
+ * signatures are just a passkey approval.
3654
3919
  */
3655
- function hasEmbeddedWallet() {
3656
- return walletClaimsFromSession() != null;
3657
- }
3658
- /** Whether the active email/social session carries an embedded Crossmint EVM wallet. */
3659
- function hasEmbeddedEvmWallet() {
3660
- return walletClaimsFromSession('evm') != null;
3661
- }
3662
- /** signAndSubmitTransaction for embedded wallets: serialize + route through the
3663
- * signer popup, resolve with the on-chain transaction signature/hash. */
3664
- async function embeddedSignAndSubmit(transaction) {
3665
- const serializedTransaction = serializeTransaction(transaction);
3666
- const result = await signViaSignerPopup({ kind: 'transaction', serializedTransaction });
3667
- const hash = result.hash || result.transactionId;
3668
- if (!hash)
3669
- throw new Error('Signer returned no transaction hash.');
3670
- return hash;
3671
- }
3672
- /** Submit a validated BoundedRuntime EVM write through the user's email signer. */
3673
- async function embeddedRunEvmTransaction(transaction) {
3674
- var _a, _b;
3675
- if (!transaction.to || !transaction.data || !transaction.chainId)
3676
- throw new Error('Incomplete embedded EVM transaction');
3677
- if (!/^0x[0-9a-fA-F]{40}$/.test(transaction.to))
3678
- throw new Error('Invalid embedded EVM runtime address');
3679
- core.assertCanonicalBoundedRuntimeWriteCalldata(transaction.data);
3680
- if (!Number.isSafeInteger(transaction.chainId) || transaction.chainId <= 0)
3681
- throw new Error('Invalid embedded EVM chain id');
3682
- if (transaction.nonce !== undefined)
3683
- throw new Error('Server-supplied EVM nonces are not accepted');
3684
- try {
3685
- if (BigInt((_a = transaction.value) !== null && _a !== void 0 ? _a : '0') !== BigInt(0))
3686
- throw new Error('Bounded EVM writes cannot transfer native value');
3920
+ async function signSolanaMessageViaTurnkey(message) {
3921
+ if (!hasDOM$2()) {
3922
+ throw new Error('Turnkey embedded-wallet signing is only available in the browser (popup-based).');
3923
+ }
3924
+ const { url, origin } = await turnkeySignerPage();
3925
+ const requestId = `tksign_${Date.now()}_${++requestSeq}`;
3926
+ const messageHex = toHex(message);
3927
+ return await deliver(url, origin, {
3928
+ request: { type: 'bounded:turnkey:sign', requestId, messageHex },
3929
+ onResult: (d) => {
3930
+ if (d.ok && typeof d.signatureHex === 'string' && typeof d.address === 'string') {
3931
+ return { done: true, value: { signature: fromHex(d.signatureHex), address: d.address, subOrgId: String(d.subOrgId || '') } };
3932
+ }
3933
+ return { error: String(d.error || 'Turnkey signing failed') };
3934
+ },
3935
+ });
3936
+ }
3937
+ function requireMatchingAddress(result) {
3938
+ const expected = activeTurnkeyAddress();
3939
+ if (!expected)
3940
+ throw new Error('This session has no Turnkey wallet. Sign in again to provision one.');
3941
+ if (result.address !== expected)
3942
+ throw new Error('Turnkey signer returned a different wallet address than the active session.');
3943
+ return expected;
3944
+ }
3945
+ async function signMessageWithTurnkey(message) {
3946
+ const result = await signSolanaMessageViaTurnkey(getPlatform().textEncode(message));
3947
+ requireMatchingAddress(result);
3948
+ return bs58.encode(result.signature);
3949
+ }
3950
+ async function signTransactionWithTurnkey(transaction) {
3951
+ const isLegacy = 'serializeMessage' in transaction;
3952
+ const message = isLegacy
3953
+ ? transaction.serializeMessage()
3954
+ : transaction.message.serialize();
3955
+ const result = await signSolanaMessageViaTurnkey(new Uint8Array(message));
3956
+ const address = requireMatchingAddress(result);
3957
+ const { PublicKey } = await import('@solana/web3.js');
3958
+ if (isLegacy) {
3959
+ transaction.addSignature(new PublicKey(address), bufferExports.Buffer.from(result.signature));
3687
3960
  }
3688
- catch (error) {
3689
- if (error instanceof Error && error.message.includes('cannot transfer'))
3690
- throw error;
3691
- throw new Error('Invalid embedded EVM transaction value');
3961
+ else {
3962
+ transaction.addSignature(new PublicKey(address), result.signature);
3963
+ }
3964
+ return transaction;
3965
+ }
3966
+ async function signAndSubmitTransactionWithTurnkey(transaction, feePayer) {
3967
+ var _a;
3968
+ const config = await core.getConfig();
3969
+ const rpcUrl = (_a = config.rpcUrl) === null || _a === void 0 ? void 0 : _a.trim();
3970
+ if (!rpcUrl)
3971
+ throw new Error('Turnkey transaction submission requires init({ rpcUrl }).');
3972
+ const { Connection, PublicKey } = await import('@solana/web3.js');
3973
+ const connection = new Connection(rpcUrl, 'confirmed');
3974
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
3975
+ const isLegacy = 'serializeMessage' in transaction;
3976
+ if (isLegacy) {
3977
+ const legacy = transaction;
3978
+ legacy.recentBlockhash = blockhash;
3979
+ legacy.lastValidBlockHeight = lastValidBlockHeight;
3980
+ if (!legacy.feePayer) {
3981
+ const address = activeTurnkeyAddress();
3982
+ if (!address)
3983
+ throw new Error('This session has no Turnkey wallet. Sign in again to provision one.');
3984
+ legacy.feePayer = feePayer !== null && feePayer !== void 0 ? feePayer : new PublicKey(address);
3985
+ }
3692
3986
  }
3693
- const result = await signViaSignerPopup({
3694
- kind: 'evmTransaction',
3695
- transaction: { to: transaction.to, data: transaction.data, value: (_b = transaction.value) !== null && _b !== void 0 ? _b : '0', chainId: transaction.chainId },
3987
+ else {
3988
+ transaction.message.recentBlockhash = blockhash;
3989
+ }
3990
+ const signed = await signTransactionWithTurnkey(transaction);
3991
+ const signature = await connection.sendRawTransaction(signed.serialize(), {
3992
+ skipPreflight: false,
3993
+ maxRetries: 3,
3696
3994
  });
3697
- const hash = result.hash || result.transactionId;
3698
- if (!hash)
3699
- throw new Error('Signer returned no EVM transaction hash.');
3700
- return { transactionSignature: hash, blockNumber: 0, gasUsed: '0', data: result };
3995
+ const confirmation = await connection.confirmTransaction({ signature, blockhash, lastValidBlockHeight }, 'confirmed');
3996
+ if (confirmation.value.err) {
3997
+ throw new Error(`Turnkey transaction failed: ${JSON.stringify(confirmation.value.err)}`);
3998
+ }
3999
+ return signature;
3701
4000
  }
3702
4001
 
3703
4002
  // Same message the email provider uses when a hosted (OIDC) login has no
3704
4003
  // embedded wallet — enable `auth.wallets` in policy to get one.
3705
- const OIDC_NO_WALLET = 'This login has no embedded wallet. Enable `"auth": { "wallets": true }` in ' +
3706
- 'the app policy so logins get a non-custodial Crossmint wallet (@user.address), ' +
3707
- 'then sign from a user gesture.';
4004
+ const OIDC_NO_WALLET = 'This session has no Turnkey wallet. Sign in again to provision the default ' +
4005
+ 'embedded wallet, or check whether the app explicitly sets auth.wallets:false.';
3708
4006
  const PKCE_STORE_KEY = 'bounded.oidc.pkce';
3709
4007
  const STORED_AUTH_METHOD_KEY$1 = 'bounded_last_auth_method';
3710
4008
  const ISSUER_SESSION_KIND_KEY$1 = 'bounded_issuer_session_kind';
@@ -3730,10 +4028,8 @@ function decodeJwt(token) {
3730
4028
  }
3731
4029
  }
3732
4030
  // A minimal AuthProvider so getSession()/logout() work for OIDC sessions, mirroring email.
3733
- // Signing surface (slice 2): a hosted login on a wallets-enabled app carries an
3734
- // embedded Crossmint wallet (@user.address). signAndSubmitTransaction routes
3735
- // through the Bounded signer popup; signMessage/signTransaction are structurally
3736
- // unsupported for Crossmint smart wallets (sign+submit atomically, no raw sig).
4031
+ // Turnkey supplies the default Solana wallet and supports raw message and transaction
4032
+ // signatures through the Bounded signer window.
3737
4033
  const oidcProviderSingleton = {
3738
4034
  async login() {
3739
4035
  const idToken = sessionManager().getIdToken();
@@ -3744,37 +4040,38 @@ const oidcProviderSingleton = {
3744
4040
  return idToken ? userFromIdToken(idToken) : null;
3745
4041
  },
3746
4042
  async logout() { await sessionManager().clearSession(); },
3747
- async signMessage(_message) {
3748
- throw new Error(hasEmbeddedWallet() ? EMBEDDED_WALLET_UNSUPPORTED : OIDC_NO_WALLET);
4043
+ async signMessage(message) {
4044
+ if (!hasTurnkeyWallet())
4045
+ throw new Error(OIDC_NO_WALLET);
4046
+ return signMessageWithTurnkey(message);
3749
4047
  },
3750
- async signTransaction(_t) {
3751
- throw new Error(hasEmbeddedWallet() ? EMBEDDED_WALLET_UNSUPPORTED : OIDC_NO_WALLET);
4048
+ async signTransaction(transaction) {
4049
+ if (!hasTurnkeyWallet())
4050
+ throw new Error(OIDC_NO_WALLET);
4051
+ return signTransactionWithTurnkey(transaction);
3752
4052
  },
3753
- async runTransaction(evm, sol, options) {
4053
+ async runTransaction(evm, sol, _options) {
3754
4054
  if (evm && sol)
3755
4055
  throw new Error('A transaction cannot target EVM and Solana at the same time.');
3756
- if (!evm)
4056
+ if (!hasTurnkeyWallet())
3757
4057
  throw new Error(OIDC_NO_WALLET);
3758
- if ((options === null || options === void 0 ? void 0 : options.shouldSubmitTx) === false)
3759
- throw new Error('Embedded EVM wallets sign and submit atomically; shouldSubmitTx:false is unsupported.');
3760
- if (!hasEmbeddedEvmWallet())
3761
- throw new Error('This login has no embedded EVM wallet. Enable auth.wallets on an app with an EVM collection and sign in again.');
3762
- return embeddedRunEvmTransaction(evm);
4058
+ if (evm)
4059
+ throw new Error('Turnkey embedded wallets currently support Solana only. Connect an EVM wallet for EVM transactions.');
4060
+ throw new Error('This Solana transaction shape is not supported by the Turnkey provider. Use a pre-built transaction.');
3763
4061
  },
3764
- async signAndSubmitTransaction(transaction, _feePayer) {
3765
- if (!hasEmbeddedWallet())
4062
+ async signAndSubmitTransaction(transaction, feePayer) {
4063
+ if (!hasTurnkeyWallet())
3766
4064
  throw new Error(OIDC_NO_WALLET);
3767
- return embeddedSignAndSubmit(transaction);
4065
+ return signAndSubmitTransactionWithTurnkey(transaction, feePayer);
3768
4066
  },
3769
4067
  };
3770
4068
  function userFromIdToken(idToken) {
3771
4069
  const c = decodeJwt(idToken);
3772
4070
  const id = c['custom:userId'] || c.sub || c['custom:walletAddress'] || '';
3773
4071
  return {
3774
- id, address: (c['custom:walletAddress'] || null),
3775
- evmAddress: typeof c['custom:evmWalletAddress'] === 'string' && /^0x[0-9a-fA-F]{40}$/.test(c['custom:evmWalletAddress'])
3776
- ? c['custom:evmWalletAddress'].toLowerCase()
3777
- : null,
4072
+ id,
4073
+ address: (c['custom:walletProvider'] === 'turnkey' && c['custom:walletAddress'] || null),
4074
+ evmAddress: null,
3778
4075
  email: (c.email || null), provider: oidcProviderSingleton,
3779
4076
  };
3780
4077
  }
@@ -4497,7 +4794,7 @@ async function getAuthProvider(config) {
4497
4794
  // manager as legacy email sessions. Human login should be started
4498
4795
  // with loginWithRedirect(); this provider is kept as the restore and
4499
4796
  // logout surface for those sessions.
4500
- currentAuthProvider = new (await Promise.resolve().then(function () { return require('./email-auth-provider-BttT2sZK.js'); })).EmailAuthProvider();
4797
+ currentAuthProvider = new (await Promise.resolve().then(function () { return require('./email-auth-provider-CKM4O5Z1.js'); })).EmailAuthProvider();
4501
4798
  break;
4502
4799
  case "wallet":
4503
4800
  case "phantom": {
@@ -4516,7 +4813,7 @@ async function getAuthProvider(config) {
4516
4813
  if (!isWalletLoginEnabled(config)) {
4517
4814
  throw walletLoginNotEnabledError(authMethod);
4518
4815
  }
4519
- const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-BMDJntMD.js'); });
4816
+ const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-CoE5XQQn.js'); });
4520
4817
  currentAuthProvider = new InjectedWalletProvider(resolveInjectedWalletConfig(config), rpcUrl, configuredNetwork);
4521
4818
  break;
4522
4819
  }
@@ -4529,7 +4826,7 @@ async function getAuthProvider(config) {
4529
4826
  // Selecting authMethod:'evm-wallet' IS the opt-in — pass evmWalletConfig
4530
4827
  // to point at a specific wallet or set chainId/domain.
4531
4828
  const evmWalletConfig = ((_a = config.evmWalletConfig) !== null && _a !== void 0 ? _a : {});
4532
- const { InjectedEvmWalletProvider } = await Promise.resolve().then(function () { return require('./injected-evm-wallet-provider-7XawIUdJ.js'); });
4829
+ const { InjectedEvmWalletProvider } = await Promise.resolve().then(function () { return require('./injected-evm-wallet-provider-BMiT8I-4.js'); });
4533
4830
  currentAuthProvider = new InjectedEvmWalletProvider(evmWalletConfig);
4534
4831
  break;
4535
4832
  }
@@ -4557,7 +4854,7 @@ async function getAuthProvider(config) {
4557
4854
  break;
4558
4855
  case "guest":
4559
4856
  // Anonymous auth: a device-local ed25519 keypair signs the challenge.
4560
- currentAuthProvider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-BcR-MQ0g.js'); })).GuestAuthProvider();
4857
+ currentAuthProvider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-CLnFuodt.js'); })).GuestAuthProvider();
4561
4858
  break;
4562
4859
  }
4563
4860
  if (!currentAuthProvider) {
@@ -4613,7 +4910,7 @@ async function signInAnonymously() {
4613
4910
  // Lazy-load the guest provider so its ed25519/web3 dependencies stay out of
4614
4911
  // the main bundle for data-only apps. Specifier is a static string literal
4615
4912
  // so bundle-splitting can see it.
4616
- const provider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-BcR-MQ0g.js'); })).GuestAuthProvider();
4913
+ const provider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-CLnFuodt.js'); })).GuestAuthProvider();
4617
4914
  setAuthLoading(true); // reflect "signing in…" while the guest keypair session is minted
4618
4915
  const commit = (user) => {
4619
4916
  // No await/interleaving inside this block: provider/method/config/marker
@@ -6443,7 +6740,6 @@ exports.BUILD_DELEGATED_REVIEW_CAPABILITY_SCHEMA = BUILD_DELEGATED_REVIEW_CAPABI
6443
6740
  exports.BUILD_REVIEW_CAPABILITY_REFRESH_SCHEMA = BUILD_REVIEW_CAPABILITY_REFRESH_SCHEMA;
6444
6741
  exports.BUILD_REVIEW_CAPABILITY_SCHEMA = BUILD_REVIEW_CAPABILITY_SCHEMA;
6445
6742
  exports.BuildsApiError = BuildsApiError;
6446
- exports.EMBEDDED_WALLET_UNSUPPORTED = EMBEDDED_WALLET_UNSUPPORTED;
6447
6743
  exports.FAILURE_REASONS = FAILURE_REASONS;
6448
6744
  exports.NON_TERMINAL_STATES = NON_TERMINAL_STATES;
6449
6745
  exports.OffchainAuthProvider = OffchainAuthProvider;
@@ -6459,15 +6755,12 @@ exports.completeLoginFromRedirect = completeLoginFromRedirect;
6459
6755
  exports.completeLoginInPopup = completeLoginInPopup;
6460
6756
  exports.confirmAndCheckTransaction = confirmAndCheckTransaction;
6461
6757
  exports.deserializeTransaction = deserializeTransaction;
6462
- exports.embeddedRunEvmTransaction = embeddedRunEvmTransaction;
6463
- exports.embeddedSignAndSubmit = embeddedSignAndSubmit;
6464
6758
  exports.getAuthLoading = getAuthLoading;
6465
6759
  exports.getAuthProvider = getAuthProvider;
6466
6760
  exports.getCurrentUser = getCurrentUser;
6467
6761
  exports.getIdToken = getIdToken;
6468
6762
  exports.getPlatform = getPlatform;
6469
- exports.hasEmbeddedEvmWallet = hasEmbeddedEvmWallet;
6470
- exports.hasEmbeddedWallet = hasEmbeddedWallet;
6763
+ exports.hasTurnkeyWallet = hasTurnkeyWallet;
6471
6764
  exports.init = init;
6472
6765
  exports.login = login;
6473
6766
  exports.loginWithPopup = loginWithPopup;
@@ -6484,8 +6777,11 @@ exports.resolveSolanaRpcUrl = resolveSolanaRpcUrl;
6484
6777
  exports.setAuthLoading = setAuthLoading;
6485
6778
  exports.setCurrentUser = setCurrentUser;
6486
6779
  exports.setPlatform = setPlatform;
6780
+ exports.signAndSubmitTransactionWithTurnkey = signAndSubmitTransactionWithTurnkey;
6487
6781
  exports.signInAnonymously = signInAnonymously;
6782
+ exports.signMessageWithTurnkey = signMessageWithTurnkey;
6783
+ exports.signTransactionWithTurnkey = signTransactionWithTurnkey;
6488
6784
  exports.useAuth = useAuth;
6489
6785
  exports.useBuildRun = useBuildRun;
6490
6786
  exports.useQuery = useQuery;
6491
- //# sourceMappingURL=index.native-BSheiGj2.js.map
6787
+ //# sourceMappingURL=index.native-Do-VhPUG.js.map