@bounded-sh/client 0.0.114 → 0.0.115

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 (58) hide show
  1. package/dist/auth/providers/injected-wallet-types.d.ts +11 -2
  2. package/dist/auth/providers/wallet-standard-discovery.d.ts +2 -0
  3. package/dist/auth/turnkey-signer-window.d.ts +19 -0
  4. package/dist/auth/turnkey-signing-capability.d.ts +5 -1
  5. package/dist/{email-auth-provider-nDZjRDpj.mjs → email-auth-provider-ByNBWdfi.mjs} +2 -2
  6. package/dist/{email-auth-provider-Bk5GSpYT.mjs.map → email-auth-provider-ByNBWdfi.mjs.map} +1 -1
  7. package/dist/{email-auth-provider-Bk5GSpYT.mjs → email-auth-provider-CODHCC3h.mjs} +2 -2
  8. package/dist/{email-auth-provider-nDZjRDpj.mjs.map → email-auth-provider-CODHCC3h.mjs.map} +1 -1
  9. package/dist/{email-auth-provider-DeORQbTK.js → email-auth-provider-CPHrcy_b.js} +2 -2
  10. package/dist/{email-auth-provider-DeORQbTK.js.map → email-auth-provider-CPHrcy_b.js.map} +1 -1
  11. package/dist/{email-auth-provider-Cr66GaKw.js → email-auth-provider-CwG04f4u.js} +2 -2
  12. package/dist/{email-auth-provider-Cr66GaKw.js.map → email-auth-provider-CwG04f4u.js.map} +1 -1
  13. package/dist/{guest-auth-provider-CUNkZVFK.js → guest-auth-provider-3rfSwq3f.js} +2 -2
  14. package/dist/{guest-auth-provider-CUNkZVFK.js.map → guest-auth-provider-3rfSwq3f.js.map} +1 -1
  15. package/dist/{guest-auth-provider-ejUTbjCC.mjs → guest-auth-provider-CGN4k_LG.mjs} +2 -2
  16. package/dist/{guest-auth-provider-DDudqqxY.mjs.map → guest-auth-provider-CGN4k_LG.mjs.map} +1 -1
  17. package/dist/{guest-auth-provider-DDudqqxY.mjs → guest-auth-provider-PfOp_Yzj.mjs} +2 -2
  18. package/dist/{guest-auth-provider-ejUTbjCC.mjs.map → guest-auth-provider-PfOp_Yzj.mjs.map} +1 -1
  19. package/dist/{guest-auth-provider-5bX-xt6K.js → guest-auth-provider-d6dk97x6.js} +2 -2
  20. package/dist/{guest-auth-provider-5bX-xt6K.js.map → guest-auth-provider-d6dk97x6.js.map} +1 -1
  21. package/dist/{index-BAiLpNEQ.mjs → index-C63ceG_z.mjs} +789 -73
  22. package/dist/index-C63ceG_z.mjs.map +1 -0
  23. package/dist/{index-BZ0X1Z9X.js → index-nU0ZSfWs.js} +793 -71
  24. package/dist/index-nU0ZSfWs.js.map +1 -0
  25. package/dist/index.d.ts +3 -1
  26. package/dist/index.js +6 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/index.mjs +1 -1
  29. package/dist/{index.native-DJSOqyKQ.js → index.native-BBLBnqal.js} +75 -22
  30. package/dist/index.native-BBLBnqal.js.map +1 -0
  31. package/dist/{index.native-DcW2klyn.mjs → index.native-DLAEWwuZ.mjs} +76 -23
  32. package/dist/index.native-DLAEWwuZ.mjs.map +1 -0
  33. package/dist/index.native.js +1 -1
  34. package/dist/index.native.mjs +1 -1
  35. package/dist/{injected-evm-wallet-provider-C4aKa2v1.mjs → injected-evm-wallet-provider-C4vNOS4P.mjs} +2 -2
  36. package/dist/{injected-evm-wallet-provider-C4aKa2v1.mjs.map → injected-evm-wallet-provider-C4vNOS4P.mjs.map} +1 -1
  37. package/dist/{injected-evm-wallet-provider-BDYWjIOQ.js → injected-evm-wallet-provider-C6KC7pJ6.js} +2 -2
  38. package/dist/{injected-evm-wallet-provider-BDYWjIOQ.js.map → injected-evm-wallet-provider-C6KC7pJ6.js.map} +1 -1
  39. package/dist/{injected-evm-wallet-provider-D06arDQD.js → injected-evm-wallet-provider-D1JA3cL4.js} +2 -2
  40. package/dist/{injected-evm-wallet-provider-D06arDQD.js.map → injected-evm-wallet-provider-D1JA3cL4.js.map} +1 -1
  41. package/dist/{injected-evm-wallet-provider-BQ_kG1vI.mjs → injected-evm-wallet-provider-D7rOyYdr.mjs} +2 -2
  42. package/dist/{injected-evm-wallet-provider-BQ_kG1vI.mjs.map → injected-evm-wallet-provider-D7rOyYdr.mjs.map} +1 -1
  43. package/dist/{injected-wallet-provider-Dj-F69gb.mjs → injected-wallet-provider-BLRrB2rb.mjs} +11 -5
  44. package/dist/{injected-wallet-provider-Dj-F69gb.mjs.map → injected-wallet-provider-BLRrB2rb.mjs.map} +1 -1
  45. package/dist/{injected-wallet-provider-B9jvzDM5.js → injected-wallet-provider-BXFicWTx.js} +11 -5
  46. package/dist/{injected-wallet-provider-B9jvzDM5.js.map → injected-wallet-provider-BXFicWTx.js.map} +1 -1
  47. package/dist/{injected-wallet-provider-Dqmk-m4V.js → injected-wallet-provider-BvlKZoVJ.js} +59 -34
  48. package/dist/injected-wallet-provider-BvlKZoVJ.js.map +1 -0
  49. package/dist/{injected-wallet-provider-DxPcYxP-.mjs → injected-wallet-provider-DruiX7GK.mjs} +59 -34
  50. package/dist/injected-wallet-provider-DruiX7GK.mjs.map +1 -0
  51. package/dist/venue-escrow.d.ts +113 -0
  52. package/package.json +2 -2
  53. package/dist/index-BAiLpNEQ.mjs.map +0 -1
  54. package/dist/index-BZ0X1Z9X.js.map +0 -1
  55. package/dist/index.native-DJSOqyKQ.js.map +0 -1
  56. package/dist/index.native-DcW2klyn.mjs.map +0 -1
  57. package/dist/injected-wallet-provider-Dqmk-m4V.js.map +0 -1
  58. package/dist/injected-wallet-provider-DxPcYxP-.mjs.map +0 -1
@@ -1,4 +1,4 @@
1
- import { getConfig, getActiveSessionManager, WebSessionManager, ReactNativeSessionManager, revokeSession, reconnectWithNewAuth, deriveUserIdentityFromIdToken, init as init$2, onSessionCleared, subscribe, getFreshAuthToken, getSessionGeneration, getIdToken as getIdToken$1, genAuthNonce, genSolanaMessage, createSessionWithSignature } from '@bounded-sh/core';
1
+ import { getConfig, getActiveSessionManager, WebSessionManager, ReactNativeSessionManager, revokeSession, reconnectWithNewAuth, deriveUserIdentityFromIdToken, init as init$2, onSessionCleared, subscribe, getFreshAuthToken, getSessionGeneration, getIdToken as getIdToken$1, getConfiguredAppId, setWithVenueGrant, writeNotAppliedPhase, waitForSetResult, reconcileSetResult, resolveVenueRpcUrl, genAuthNonce, genSolanaMessage, createSessionWithSignature } from '@bounded-sh/core';
2
2
  import * as React from 'react';
3
3
 
4
4
  function walletContextFromClaims(claims, baseUrl, expectedAppId, tenantOrigin) {
@@ -594,6 +594,37 @@ class OffchainAuthProvider {
594
594
  }
595
595
  }
596
596
 
597
+ const SELECTED_WALLET_UNAVAILABLE_ERR = 'The selected Solana wallet is unavailable. Select it again before continuing.';
598
+ /** Check login capabilities without connecting, signing, or loading a wallet SDK.
599
+ * This checks login only; it does not promise message or transaction signing. */
600
+ function supportsWalletSignIn(provider) {
601
+ if (typeof provider !== 'object' || provider === null)
602
+ return false;
603
+ const wallet = provider;
604
+ return typeof wallet.connect === 'function' && typeof wallet.signIn === 'function';
605
+ }
606
+ /**
607
+ * Default provider discovery: Phantom-first, then any Wallet-Standard
608
+ * `window.solana`. Kept tiny + synchronous (no heavy imports) so it works inside
609
+ * a user gesture and can be eagerly exported from the SDK entry. This names the
610
+ * default wallet even when it cannot sign in: login must refuse that wallet,
611
+ * never silently replace it with a different identity. Custom pickers can use
612
+ * supportsWalletSignIn() to decide which providers to offer for login.
613
+ */
614
+ function defaultInjectedProvider() {
615
+ var _a;
616
+ if (typeof window === 'undefined')
617
+ return null;
618
+ const w = window;
619
+ const phantom = (_a = w === null || w === void 0 ? void 0 : w.phantom) === null || _a === void 0 ? void 0 : _a.solana;
620
+ if (phantom && typeof phantom.signMessage === 'function')
621
+ return phantom;
622
+ const generic = w === null || w === void 0 ? void 0 : w.solana;
623
+ if (generic && typeof generic.signMessage === 'function')
624
+ return generic;
625
+ return null;
626
+ }
627
+
597
628
  // issuer-logout-bounce.ts - commit the top-level navigation that ends the hosted
598
629
  // issuer's browser session (the Better Auth cookie on auth.bounded.sh).
599
630
  //
@@ -4533,6 +4564,108 @@ async function openHiddenSignerFrame(page) {
4533
4564
  };
4534
4565
  }
4535
4566
 
4567
+ // turnkey-signer-window.ts - the top-level Bounded signer window: opening it, and reserving it
4568
+ // inside a click for an approval that is reached only after awaits.
4569
+ //
4570
+ // A cross-app Turnkey signature (the capability says `transport: 'popup'`) cannot run in the
4571
+ // in-app frame, so it opens in its own window, and a browser opens a window only inside the
4572
+ // user's click. The click handler therefore calls `reserveSignerPopup()` first, before any
4573
+ // `await`, and the exchange in turnkey-signer-bridge.ts navigates that window to the signer later.
4574
+ //
4575
+ // Kept out of the bridge on purpose: the bridge is loaded lazily as a whole module, so a bundler
4576
+ // keeps every one of its exports in every app that signs, while this reservation is needed only
4577
+ // by an app that funds an escrow.
4578
+ function openSignerWindow(url, w = 420, h = 620) {
4579
+ const left = window.screenX + Math.max(0, (window.outerWidth - w) / 2);
4580
+ const top = window.screenY + Math.max(0, (window.outerHeight - h) / 2);
4581
+ return window.open(url, 'bounded-turnkey-signer', `width=${w},height=${h},left=${left},top=${top}`);
4582
+ }
4583
+ // One slot: the next popup exchange takes it, and a new reservation replaces an unused earlier one.
4584
+ // A property of a const rather than a reassigned `let`, which a bundler would keep every assignment
4585
+ // to, dragging the reservation into apps that never reserve.
4586
+ const reserved = { popup: null };
4587
+ /** Write `text` into the window; false when the window is not ours to write (it still works: it is navigated to the signer next). */
4588
+ function paint(popup, text) {
4589
+ try {
4590
+ const { document: doc } = popup;
4591
+ doc.title = 'Bounded';
4592
+ doc.documentElement.style.colorScheme = 'light dark';
4593
+ doc.body.style.cssText = 'margin:0;padding:24px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;min-height:100vh;text-align:center;font:15px system-ui,sans-serif;background:Canvas;color:CanvasText';
4594
+ doc.body.textContent = text;
4595
+ return true;
4596
+ }
4597
+ catch (_a) {
4598
+ return false;
4599
+ }
4600
+ }
4601
+ /**
4602
+ * Open the signer window NOW, synchronously, showing a neutral "Preparing your approval..."
4603
+ * page (a blank document with local text, no remote content). Call it from a user gesture,
4604
+ * before any `await`, and `release()` it when the flow ends. A cross-app Turnkey signature
4605
+ * then runs in this window instead of needing a fresh gesture.
4606
+ * Returns null when there is no DOM or the browser blocked the window.
4607
+ */
4608
+ function reserveSignerPopup() {
4609
+ var _a;
4610
+ if (typeof window === 'undefined' || typeof document === 'undefined')
4611
+ return null;
4612
+ try {
4613
+ (_a = reserved.popup) === null || _a === void 0 ? void 0 : _a.close();
4614
+ }
4615
+ catch ( /* already closed */_b) { /* already closed */ }
4616
+ let popup = null;
4617
+ try {
4618
+ popup = openSignerWindow('');
4619
+ }
4620
+ catch ( /* a sandboxed page may throw instead of returning null */_c) { /* a sandboxed page may throw instead of returning null */ }
4621
+ reserved.popup = popup;
4622
+ if (!popup)
4623
+ return null;
4624
+ paint(popup, 'Preparing your approval...');
4625
+ return {
4626
+ release(message) {
4627
+ const unused = reserved.popup === popup;
4628
+ if (unused)
4629
+ reserved.popup = null;
4630
+ try {
4631
+ if (!message || !unused || popup.closed)
4632
+ return popup.close();
4633
+ const text = message.slice(0, 160);
4634
+ if (!paint(popup, text))
4635
+ return popup.close(); // not a window of ours to write on, so no message to linger on
4636
+ // Close it only while it still shows this text: a window that was reserved again or sent on to
4637
+ // the signer in the meantime is no longer ours to close.
4638
+ setTimeout(() => { try {
4639
+ if (popup.document.body.textContent === text)
4640
+ popup.close();
4641
+ }
4642
+ catch ( /* sent on to the signer */_a) { /* sent on to the signer */ } }, 1500);
4643
+ }
4644
+ catch ( /* already closed */_a) { /* already closed */ }
4645
+ },
4646
+ };
4647
+ }
4648
+ /** Hand the reserved window, if one is held, to an exchange: navigated to the signer page at `url`. */
4649
+ function takeReservedPopup(url) {
4650
+ const popup = reserved.popup;
4651
+ reserved.popup = null;
4652
+ if (!popup)
4653
+ return null;
4654
+ if (popup.closed)
4655
+ throw new Error('Wallet approval window was closed before it completed.');
4656
+ try {
4657
+ popup.location.replace(url);
4658
+ }
4659
+ catch (_a) {
4660
+ try {
4661
+ popup.close();
4662
+ }
4663
+ catch ( /* ignore */_b) { /* ignore */ }
4664
+ throw new Error('Wallet approval window could not open the signer - retry from a click.');
4665
+ }
4666
+ return popup;
4667
+ }
4668
+
4536
4669
  // turnkey-signing-capability.ts - the pure AS-02 (DS2-0112) signing-capability logic,
4537
4670
  // kept import-free (no DOM, no session, no @bounded-sh/core) so it is unit-testable.
4538
4671
  //
@@ -4544,9 +4677,10 @@ async function openHiddenSignerFrame(page) {
4544
4677
  // so a regression here (a dropped capability, a wrong route, a swallowed error) is
4545
4678
  // caught without a browser.
4546
4679
  // POST the Bounded id token + payload hash to the issuer's capability mint route and
4547
- // return the issuer-signed capability for exactly these bytes. Credential-free: identity
4548
- // is proven with the id token in the body (not an ambient cookie the cross-origin fetch
4549
- // would not carry). Throws with the same stable messages the bridge relied on inline.
4680
+ // return the issuer-signed capability for exactly these bytes, with the transport the
4681
+ // issuer requires for them. Credential-free: identity is proven with the id token in the
4682
+ // body (not an ambient cookie the cross-origin fetch would not carry). Throws with the same
4683
+ // stable messages the bridge relied on inline.
4550
4684
  async function requestTurnkeySigningCapability(opts) {
4551
4685
  const base = opts.baseUrl.replace(/\/$/, '');
4552
4686
  let res;
@@ -4576,7 +4710,7 @@ async function requestTurnkeySigningCapability(opts) {
4576
4710
  if (!d || typeof d.capability !== 'string' || !d.capability) {
4577
4711
  throw new Error('Turnkey signing capability was malformed.');
4578
4712
  }
4579
- return d.capability;
4713
+ return d.transport === 'popup' ? { capability: d.capability, transport: 'popup' } : { capability: d.capability };
4580
4714
  }
4581
4715
  // Assemble the `bounded:turnkey:sign` postMessage request, carrying the issuer-signed
4582
4716
  // capability for the same bytes. Without the capability the hosted signer refuses
@@ -4667,12 +4801,16 @@ function hasDOM$3() {
4667
4801
  // when we cannot embed (no DOM, or the frame never mounts/loads). Nothing in the
4668
4802
  // email-session flow needs a popup by preference: the code entry and the approval
4669
4803
  // click both run fine inside a cross-origin iframe on every engine (the old
4670
- // Safari popup preference existed only for in-iframe WebAuthn CREATE).
4804
+ // Safari popup preference existed only for in-iframe WebAuthn CREATE). The one
4805
+ // exception is a signature the issuer marks `transport: 'popup'` (a cross-app
4806
+ // write): the hosted signer refuses it inside any frame, so it never touches the widget.
4671
4807
  async function deliver(url, origin, ex) {
4672
4808
  var _a, _b;
4673
4809
  const popup = () => runPopup(url, origin, ex);
4674
4810
  (_a = ex.assertCurrent) === null || _a === void 0 ? void 0 : _a.call(ex);
4675
- const result = await runWidget(url, origin, { request: ex.request, onResult: ex.onResult, context: ex.context, assertCurrent: ex.assertCurrent }, popup);
4811
+ const result = ex.transport === 'popup'
4812
+ ? await popup()
4813
+ : await runWidget(url, origin, { request: ex.request, onResult: ex.onResult, context: ex.context, assertCurrent: ex.assertCurrent }, popup);
4676
4814
  (_b = ex.assertCurrent) === null || _b === void 0 ? void 0 : _b.call(ex);
4677
4815
  return result;
4678
4816
  }
@@ -4744,14 +4882,12 @@ function activeTurnkeyAddress() {
4744
4882
  : null;
4745
4883
  }
4746
4884
  let requestSeq = 0;
4747
- // Shared popup driver: open the signer page, do the ready/postMessage handshake, and
4748
- // resolve when `onResult` accepts a result message. Origin + source are pinned.
4885
+ // Shared popup driver: open the signer page (in the reserved window when one is held), do the
4886
+ // ready/postMessage handshake, and resolve when `onResult` accepts a result message. Origin +
4887
+ // source are pinned.
4749
4888
  async function runPopup(url, signerOrigin, ex) {
4750
- var _a, _b;
4751
- const w = (_a = ex.width) !== null && _a !== void 0 ? _a : 420, h = (_b = ex.height) !== null && _b !== void 0 ? _b : 620;
4752
- const left = window.screenX + Math.max(0, (window.outerWidth - w) / 2);
4753
- const top = window.screenY + Math.max(0, (window.outerHeight - h) / 2);
4754
- const popup = window.open(url, 'bounded-turnkey-signer', `width=${w},height=${h},left=${left},top=${top}`);
4889
+ var _a;
4890
+ const popup = (_a = takeReservedPopup(url)) !== null && _a !== void 0 ? _a : openSignerWindow(url, ex.width, ex.height);
4755
4891
  if (!popup) {
4756
4892
  throw new Error('Popup blocked - call this from a user gesture (e.g. a click handler) so the wallet approval window can open.');
4757
4893
  }
@@ -5001,7 +5137,7 @@ async function signSolanaMessageViaTurnkey(message) {
5001
5137
  const messageHex = toHex(message);
5002
5138
  // AS-02: obtain the issuer-signed capability for THESE exact bytes first; the signer will
5003
5139
  // refuse (capability_required) without it. Fetched per signature (each is single-payload).
5004
- const capability = await fetchSigningCapability(messageHex, context);
5140
+ const { capability, transport } = await fetchSigningCapability(messageHex, context);
5005
5141
  // Inline (authMode:"turnkey") sessions plant no Better Auth cookie on the issuer, so the
5006
5142
  // signer's same-origin status/create fetches need a bearer session proof: attach the
5007
5143
  // createWallet action authorization (it covers the sign flow's get-or-create too). Minted
@@ -5010,11 +5146,20 @@ async function signSolanaMessageViaTurnkey(message) {
5010
5146
  return await deliver(url, origin, {
5011
5147
  context: context.key, assertCurrent: context.assertCurrent,
5012
5148
  request: buildTurnkeySignRequest({ requestId, messageHex, capability, authorization }),
5149
+ transport,
5013
5150
  onResult: (d) => {
5014
5151
  if (d.ok && typeof d.signatureHex === 'string' && typeof d.address === 'string') {
5015
- setWalletSessionState(context.key, { status: 'ready', expiresAt: Number(d.signingSessionExpiresAt) });
5152
+ // A top-level popup keeps its signing session in the signer origin's own storage, which the
5153
+ // warm in-app frame (a partitioned context) cannot see, so it says nothing about that frame.
5154
+ if (transport !== 'popup')
5155
+ setWalletSessionState(context.key, { status: 'ready', expiresAt: Number(d.signingSessionExpiresAt) });
5016
5156
  return { done: true, value: { signature: fromHex(d.signatureHex), address: d.address, subOrgId: String(d.subOrgId || '') } };
5017
5157
  }
5158
+ // The hosted signer refuses a cross-app signature inside a frame. Never retry it from here:
5159
+ // the top-level window needs the user's own click.
5160
+ if (d.error === 'top_level_required') {
5161
+ return { error: 'top_level_required: an approval that writes to another app must open in its own window. Start it from a click handler.' };
5162
+ }
5018
5163
  return { error: String(d.error || 'Turnkey signing failed') };
5019
5164
  },
5020
5165
  });
@@ -6330,7 +6475,7 @@ async function getAuthProvider(config, fromStorage = false) {
6330
6475
  // manager as legacy email sessions. Human login should be started
6331
6476
  // with loginWithRedirect(); this provider is kept as the restore and
6332
6477
  // logout surface for those sessions.
6333
- currentAuthProvider = new (await import('./email-auth-provider-nDZjRDpj.mjs')).EmailAuthProvider();
6478
+ currentAuthProvider = new (await import('./email-auth-provider-ByNBWdfi.mjs')).EmailAuthProvider();
6334
6479
  break;
6335
6480
  case "phantom": {
6336
6481
  // First-class Solana WALLET LOGIN (the poof/TaroBase-style "connect
@@ -6372,7 +6517,7 @@ async function getAuthProvider(config, fromStorage = false) {
6372
6517
  // (bounded-login-widget.ts), so registration never counts as
6373
6518
  // evidence the user has a wallet.
6374
6519
  await ensureSolanaMobileWalletRegistered(config, configuredNetwork);
6375
- const { InjectedWalletProvider } = await import('./injected-wallet-provider-Dj-F69gb.mjs');
6520
+ const { InjectedWalletProvider } = await import('./injected-wallet-provider-BLRrB2rb.mjs');
6376
6521
  currentAuthProvider = new InjectedWalletProvider(resolveInjectedWalletConfig(config), rpcUrl, configuredNetwork);
6377
6522
  break;
6378
6523
  }
@@ -6385,7 +6530,7 @@ async function getAuthProvider(config, fromStorage = false) {
6385
6530
  // Selecting authMethod:'evm-wallet' IS the opt-in — pass evmWalletConfig
6386
6531
  // to point at a specific wallet or set chainId/domain.
6387
6532
  const evmWalletConfig = ((_a = config.evmWalletConfig) !== null && _a !== void 0 ? _a : {});
6388
- const { InjectedEvmWalletProvider } = await import('./injected-evm-wallet-provider-C4aKa2v1.mjs');
6533
+ const { InjectedEvmWalletProvider } = await import('./injected-evm-wallet-provider-C4vNOS4P.mjs');
6389
6534
  currentAuthProvider = new InjectedEvmWalletProvider(evmWalletConfig);
6390
6535
  break;
6391
6536
  }
@@ -6410,7 +6555,7 @@ async function getAuthProvider(config, fromStorage = false) {
6410
6555
  break;
6411
6556
  case "guest":
6412
6557
  // Anonymous auth: a device-local ed25519 keypair signs the challenge.
6413
- currentAuthProvider = new (await import('./guest-auth-provider-ejUTbjCC.mjs')).GuestAuthProvider();
6558
+ currentAuthProvider = new (await import('./guest-auth-provider-CGN4k_LG.mjs')).GuestAuthProvider();
6414
6559
  break;
6415
6560
  }
6416
6561
  if (!currentAuthProvider) {
@@ -6472,7 +6617,7 @@ async function signInAnonymously() {
6472
6617
  // Lazy-load the guest provider so its ed25519/web3 dependencies stay out of
6473
6618
  // the main bundle for data-only apps. Specifier is a static string literal
6474
6619
  // so bundle-splitting can see it.
6475
- const provider = new (await import('./guest-auth-provider-ejUTbjCC.mjs')).GuestAuthProvider();
6620
+ const provider = new (await import('./guest-auth-provider-CGN4k_LG.mjs')).GuestAuthProvider();
6476
6621
  setAuthLoading(true); // reflect "signing in…" while the guest keypair session is minted
6477
6622
  // adoptSessionProvider awaits only getConfig() (already resolved here) and then
6478
6623
  // runs every write - provider/method/config/marker/user - in one synchronous
@@ -6643,7 +6788,7 @@ function ensureSharedWalletLoginReady() {
6643
6788
  if (!sharedWalletReady) {
6644
6789
  sharedWalletReady = (async () => {
6645
6790
  await getConfig();
6646
- await import('./injected-wallet-provider-Dj-F69gb.mjs');
6791
+ await import('./injected-wallet-provider-BLRrB2rb.mjs');
6647
6792
  })().catch((error) => {
6648
6793
  sharedWalletReady = null;
6649
6794
  throw error;
@@ -6725,10 +6870,12 @@ async function loginWithWallet(options) {
6725
6870
  // one that yields nothing and then a wallet prepares the mobile registry
6726
6871
  // after the tap for a wallet it never uses.
6727
6872
  const pinnedProvider = (_b = (_a = injectedConfig.getProvider) === null || _a === void 0 ? void 0 : _a.call(injectedConfig)) !== null && _b !== void 0 ? _b : null;
6873
+ if (injectedConfig.getProvider && !pinnedProvider)
6874
+ throw new Error(SELECTED_WALLET_UNAVAILABLE_ERR);
6728
6875
  const attemptConfig = Object.assign(Object.assign({}, injectedConfig), {
6729
- // Still a fallthrough when it resolved nothing, exactly as before - the
6730
- // difference is that the answer is now fixed for this attempt.
6731
- getProvider: () => pinnedProvider });
6876
+ // An explicit choice stays pinned. With no getter, retain default
6877
+ // discovery rather than manufacturing an unavailable explicit choice.
6878
+ getProvider: injectedConfig.getProvider ? () => pinnedProvider : undefined });
6732
6879
  // Idempotent: a caller that prepared the lane (the widget, or an app that
6733
6880
  // awaited ensureWalletLoginReady before enabling its button) has already
6734
6881
  // paid for this, so nothing activation-sensitive happens after the tap. A
@@ -6737,16 +6884,16 @@ async function loginWithWallet(options) {
6737
6884
  //
6738
6885
  // "Pinned" is about the EFFECTIVE resolution, not whether a getter was
6739
6886
  // passed: a configured walletLogin.getProvider pins just as much as a
6740
- // per-call one, and a getter that returns nothing falls through to discovery
6741
- // (and so to the mobile wallet). With a real wallet in hand only the shared
6742
- // half is needed - re-attempting a failed mobile registration would be
6887
+ // per-call one. An unavailable explicit choice was refused above. With a
6888
+ // real wallet in hand only the shared half is needed - re-attempting a
6889
+ // failed mobile registration would be
6743
6890
  // exactly the work-after-the-tap this exists to avoid, for a wallet this
6744
6891
  // login is not even using.
6745
6892
  if (pinnedProvider)
6746
6893
  await ensureSharedWalletLoginReady();
6747
6894
  else
6748
6895
  await ensureWalletLoginReady();
6749
- const { InjectedWalletProvider } = await import('./injected-wallet-provider-Dj-F69gb.mjs');
6896
+ const { InjectedWalletProvider } = await import('./injected-wallet-provider-BLRrB2rb.mjs');
6750
6897
  // Keep the RAW wallet provider: the offchain wrapper forwards only a fixed
6751
6898
  // set of methods, so cleanup below must speak to the provider that actually
6752
6899
  // holds the config rather than to whatever is wrapping it.
@@ -7574,15 +7721,28 @@ function hasFeature(wallet, name) {
7574
7721
  function supportsSolana(wallet) {
7575
7722
  return wallet.chains.some((c) => c.startsWith("solana:"));
7576
7723
  }
7577
- /** A wallet is LISTED for Bounded login when it can connect + sign a message on a
7578
- * Solana chain. Login itself needs the `solana:signIn` feature (SEC-01); that is
7579
- * checked at login time in InjectedWalletProvider, where a wallet without it is
7580
- * refused with the reason spelled out rather than silently missing from the list.
7581
- * Transaction features are optional and checked lazily at call time. */
7582
- function isLoginCapable(wallet) {
7724
+ /** A Solana wallet the SDK can connect and use for message signing. */
7725
+ function isSolanaWallet(wallet) {
7726
+ var _a, _b;
7583
7727
  return (supportsSolana(wallet) &&
7584
- hasFeature(wallet, StandardConnect) &&
7585
- hasFeature(wallet, SolanaSignMessage));
7728
+ typeof ((_a = feature(wallet, StandardConnect)) === null || _a === void 0 ? void 0 : _a.connect) === "function" &&
7729
+ typeof ((_b = feature(wallet, SolanaSignMessage)) === null || _b === void 0 ? void 0 : _b.signMessage) === "function");
7730
+ }
7731
+ /** Login choices must support the same SIWS operation login() requires.
7732
+ * Transaction features remain optional and are checked at call time. */
7733
+ function isLoginCapable(wallet) {
7734
+ var _a, _b;
7735
+ return isSolanaWallet(wallet) && supportsWalletSignIn({
7736
+ connect: (_a = feature(wallet, StandardConnect)) === null || _a === void 0 ? void 0 : _a.connect,
7737
+ signIn: (_b = feature(wallet, SolanaSignIn)) === null || _b === void 0 ? void 0 : _b.signIn,
7738
+ });
7739
+ }
7740
+ /** Distinguish unsupported installed wallets from an empty registry in the UI. */
7741
+ function hasUnsupportedStandardWallets(configuredNetwork) {
7742
+ if (typeof window === "undefined")
7743
+ return false;
7744
+ const chain = configuredNetwork ? solanaChainOrNull(configuredNetwork) : null;
7745
+ return getWallets().get().some((wallet) => (isSolanaWallet(wallet) && (!chain || wallet.chains.includes(chain)) && !isLoginCapable(wallet)));
7586
7746
  }
7587
7747
  /** The Wallet-Standard chain id for a configured network, or null when it is
7588
7748
  * absent/unsupported. Ordering must never throw - failing closed on an
@@ -7611,6 +7771,7 @@ function feature(wallet, name) {
7611
7771
  * an unconfigured network fails closed at sign time rather than defaulting.
7612
7772
  */
7613
7773
  function standardWalletToInjectedProvider(wallet, configuredNetwork) {
7774
+ var _a;
7614
7775
  // The adapter holds NO account of its own: `wallet.accounts` is the Wallet
7615
7776
  // Standard's live authorized-account view, kept in sync by the wallet itself
7616
7777
  // (it emits standard:events 'change' when it moves). Reading it on every
@@ -7710,12 +7871,12 @@ function standardWalletToInjectedProvider(wallet, configuredNetwork) {
7710
7871
  const disconnect = feature(wallet, StandardDisconnect);
7711
7872
  if (disconnect)
7712
7873
  await disconnect.disconnect();
7713
- } }, (hasFeature(wallet, SolanaSignIn)
7874
+ } }, (typeof ((_a = feature(wallet, SolanaSignIn)) === null || _a === void 0 ? void 0 : _a.signIn) === "function"
7714
7875
  ? {
7715
7876
  async signIn(input) {
7716
7877
  var _a;
7717
7878
  const sign = feature(wallet, SolanaSignIn);
7718
- if (!sign)
7879
+ if (typeof (sign === null || sign === void 0 ? void 0 : sign.signIn) !== "function")
7719
7880
  throw new Error("Wallet does not support solana:signIn");
7720
7881
  const open = currentAccount();
7721
7882
  if (open && !accountSupports(open, SolanaSignIn))
@@ -8263,14 +8424,12 @@ function walletGlyph() {
8263
8424
  return svg;
8264
8425
  }
8265
8426
  function isInjectedProvider(v) {
8266
- return (typeof v === "object" &&
8267
- v !== null &&
8268
- typeof v.signMessage === "function");
8427
+ return supportsWalletSignIn(v);
8269
8428
  }
8270
8429
  // Enumerate native wallets via the Solana Wallet Standard registry (NOT a
8271
- // hardcoded name list) - every wallet that registered itself shows up with its
8272
- // real name + icon - and ALSO an older wallet that never registers and only
8273
- // exposes `window.solana`.
8430
+ // hardcoded name list) - wallets that support Bounded sign-in show up with
8431
+ // their real name + icon - and ALSO an eligible older wallet that never
8432
+ // registers and only exposes `window.solana`.
8274
8433
  //
8275
8434
  // The legacy `window.solana` probe fills in for a wallet too old to register
8276
8435
  // itself. The rule it has always encoded is "no BROWSER wallet registered", and
@@ -8305,7 +8464,11 @@ const BUSY_MSG = "A sign-in is already in progress - finish or cancel it first."
8305
8464
  // no wallet in this browser). A phone browser never sees installed wallet apps
8306
8465
  // as injected providers, so the honest advice there is a different browser,
8307
8466
  // not "install a wallet".
8308
- function noLaneCopy(mobile) {
8467
+ function noLaneCopy(mobile, unsupportedWallets) {
8468
+ if (unsupportedWallets) {
8469
+ return "The wallets detected in this browser cannot sign in to Bounded. " +
8470
+ "Use a wallet that supports Sign In With Solana, then reload this page.";
8471
+ }
8309
8472
  return mobile
8310
8473
  ? "No wallet is available in this browser. Open this page in your wallet app's " +
8311
8474
  "browser, or on a desktop browser with a wallet extension, then try again."
@@ -8503,6 +8666,9 @@ async function prepareAndOpen(opts, pending) {
8503
8666
  // button with no wallet behind it.
8504
8667
  if (wallets.length === 0)
8505
8668
  walletEnabled = false;
8669
+ const defaultWallet = defaultInjectedProvider();
8670
+ const unsupportedWallets = !lane.hardOff && lane.requested !== false && (hasUnsupportedStandardWallets(network) ||
8671
+ (defaultWallet !== null && !supportsWalletSignIn(defaultWallet)));
8506
8672
  const authMode = (_b = opts.authMode) !== null && _b !== void 0 ? _b : authApi.resolveAuthMode(initCfg);
8507
8673
  // Widget text: per-call options win, then init() loginWidget config, then the
8508
8674
  // defaults ("Sign in" / the Bounded subline; "" suppresses the subline).
@@ -8881,14 +9047,19 @@ async function prepareAndOpen(opts, pending) {
8881
9047
  // screen, and name the usual cause once in the console, where the
8882
9048
  // developer's own preview run will show it.
8883
9049
  if (!hasEmail && social.length === 0 && !walletEnabled) {
8884
- card.appendChild(el("p", "sub", noLaneCopy(detectMobile())));
9050
+ card.appendChild(el("p", "sub", noLaneCopy(detectMobile(), unsupportedWallets)));
8885
9051
  console.warn("[Bounded] openBoundedWidget has no sign-in lane to show: the app asked for " +
8886
- "no email or social method and no wallet is available in this browser. " +
8887
- (offerMobile
9052
+ "no email or social method and " +
9053
+ (unsupportedWallets
9054
+ ? "the detected wallets do not support Sign In With Solana. "
9055
+ : "no wallet is available in this browser. ") +
9056
+ (offerMobile && !unsupportedWallets
8888
9057
  ? "On Android the Solana Mobile wallet is offered only when the app installs " +
8889
9058
  "'@solana-mobile/wallet-standard-mobile' (see the warning above if registration failed); "
8890
9059
  : "") +
8891
- "Add a method, or make sure wallet login is enabled and the mobile adapter is installed.");
9060
+ (unsupportedWallets
9061
+ ? "Add another sign-in method, or use a wallet that supports Sign In With Solana."
9062
+ : "Add a method, or make sure wallet login is enabled and the mobile adapter is installed."));
8892
9063
  }
8893
9064
  card.appendChild(status);
8894
9065
  const foot = el("div", "foot");
@@ -10475,7 +10646,7 @@ async function onrampStatus(sinceMs) {
10475
10646
  function isSuccess(t) {
10476
10647
  return /SUCCESS|COMPLETED/i.test(t.status);
10477
10648
  }
10478
- function isPending(t) {
10649
+ function isPending$1(t) {
10479
10650
  return /PROGRESS|PENDING|CREATED/i.test(t.status);
10480
10651
  }
10481
10652
  async function verifyCompletion(openedAt, asset, timeoutMs) {
@@ -10489,7 +10660,7 @@ async function verifyCompletion(openedAt, asset, timeoutMs) {
10489
10660
  const done = txs.find((t) => isSuccess(t) && (t.asset === null || t.asset === asset));
10490
10661
  if (done)
10491
10662
  return done;
10492
- sawPending = txs.some(isPending);
10663
+ sawPending = txs.some(isPending$1);
10493
10664
  }
10494
10665
  catch ( /* transient - keep polling until the deadline */_a) { /* transient - keep polling until the deadline */ }
10495
10666
  // No completed fill and nothing in flight: one grace poll cycle still
@@ -10595,6 +10766,570 @@ async function onramp(options = {}) {
10595
10766
  return Object.assign(Object.assign({}, base), { status: 'closed' });
10596
10767
  }
10597
10768
 
10769
+ // venue-escrow.ts - fund and dispute a venue escrow from inside an OpenApps app (VENUE-GRANT-DESIGN.md).
10770
+ //
10771
+ // An OpenApps app's escrow lives in its venue (`agentescrows/<rootAppId>/e/<escrowId>`), and this
10772
+ // app's session cannot write another app's data. Bounded Auth therefore mints a 5 minute,
10773
+ // single-use GRANT for exactly one create (`POST {humanAuthApiUrl}/app-token/venue-grant`;
10774
+ // contract: packages/cdk/cloudflare/shared/venue-grant.ts, which the SDK cannot import because the
10775
+ // packages publish separately, so only what is needed is mirrored here), and the venue builds the
10776
+ // transaction for the wallet signed in here. The money's only authority is that wallet's
10777
+ // signature, checked onchain by the venue's own rule; the grant adds no power to the app.
10778
+ //
10779
+ // Funding moves money, so it keeps the recovery semantics oapps-fun's retired escrow page proved:
10780
+ // a pending record is saved BEFORE any network call and checked before ever funding again; the
10781
+ // escrow id is stable across retries; an uncertain broadcast is settled by its signature or the
10782
+ // public receipt and never re-sent; one tab funds at a time; and a row that does not match every
10783
+ // term is `taken`, never funded.
10784
+ /** Thrown by every venue escrow call. Branch on `code`; `error.name === 'VenueEscrowError'` also holds across bundled SDK copies. */
10785
+ class VenueEscrowError extends Error {
10786
+ constructor(code, message, details = {}) {
10787
+ super(message);
10788
+ this.name = 'VenueEscrowError';
10789
+ this.code = code;
10790
+ if (details.escrowId !== undefined)
10791
+ this.escrowId = details.escrowId;
10792
+ if (details.cause !== undefined)
10793
+ this.cause = details.cause;
10794
+ }
10795
+ }
10796
+ const ESCROW_SCHEMA = 'openapps.agent-escrow.v1';
10797
+ const STORAGE_PREFIX = 'bounded.venue-escrow-funding.v1';
10798
+ /** A saved funding that shows no row and no signature this long after its save can no longer land. */
10799
+ const ABANDONED_MS = 5 * 60000;
10800
+ const RECEIPT_POLL_MS = [0, 250, 500, 1000, 1500, 2500, 4000];
10801
+ const ADDRESS = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
10802
+ const APP_ID = /^[0-9a-f]{24}$/;
10803
+ const RECORD_ID = /^[0-9a-f]{32}$/;
10804
+ /**
10805
+ * Bounded Auth's own refusals of a grant mint, passed through as codes, with what each means to a
10806
+ * person: the error's message, and so what the reserved signer window shows before it closes.
10807
+ */
10808
+ const GRANT_REFUSALS = {
10809
+ invalid_request: 'The request was not accepted. Update the app and try again.',
10810
+ invalid_token: 'Your session expired. Sign in again.',
10811
+ origin_not_allowed: "This site isn't allowed to fund escrows for this app.",
10812
+ not_an_openapps_app: "This app can't fund escrows.",
10813
+ wallet_required: 'Sign in with a wallet to fund escrows.',
10814
+ agent_wallet_refused: "An agent's wallet can't fund escrows here.",
10815
+ rate_limited: 'Too many attempts. Try again in a minute.',
10816
+ venue_grant_unavailable: 'Escrows are unavailable right now. Try again shortly.',
10817
+ };
10818
+ const nowSeconds = () => Math.floor(Date.now() / 1000);
10819
+ /** A v0 dispute transaction stops fitting past about 513 reason bytes; this keeps a margin. */
10820
+ const MAX_DISPUTE_REASON_BYTES = 400;
10821
+ const isCount = (value) => typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
10822
+ const newRecordId = () => Array.from(getPlatform().getRandomBytes(16), (byte) => byte.toString(16).padStart(2, '0')).join('');
10823
+ const pause = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
10824
+ /** Mirrors `venueGrantPath` in shared/venue-grant.ts: the one path a grant of this kind may create. */
10825
+ function recordPath(kind, rootAppId, id) {
10826
+ return kind === 'escrow' ? `agentescrows/${rootAppId}/e/${id}` : `agentescrowdisputes/${rootAppId}/d/${id}`;
10827
+ }
10828
+ /** Who is signed in, read synchronously: the click handler must not await before it reserves the signer window. */
10829
+ function sessionIdentity() {
10830
+ const appId = getConfiguredAppId();
10831
+ let idToken = null;
10832
+ try {
10833
+ idToken = getActiveSessionManager().getIdToken();
10834
+ }
10835
+ catch ( /* no session store */_a) { /* no session store */ }
10836
+ if (!appId || !idToken)
10837
+ throw new VenueEscrowError('sign_in_required', 'Sign in before using venue escrows.');
10838
+ const wallet = deriveUserIdentityFromIdToken(idToken).address;
10839
+ if (!wallet)
10840
+ throw new VenueEscrowError('wallet_required', 'This session has no wallet to sign with.');
10841
+ return { appId, wallet };
10842
+ }
10843
+ async function mintGrant(kind, id, wallet) {
10844
+ var _a;
10845
+ let idToken = null;
10846
+ try {
10847
+ idToken = await getFreshAuthToken(false);
10848
+ }
10849
+ catch ( /* an expired session reads as signed out */_b) { /* an expired session reads as signed out */ }
10850
+ if (!idToken)
10851
+ throw new VenueEscrowError('sign_in_required', 'Your session expired. Sign in again.');
10852
+ if (deriveUserIdentityFromIdToken(idToken).address !== wallet) {
10853
+ throw new VenueEscrowError('wallet_changed', 'The signed-in wallet changed. Start again.');
10854
+ }
10855
+ const base = ((await getConfig()).humanAuthApiUrl || 'https://auth.bounded.sh').replace(/\/$/, '');
10856
+ let response;
10857
+ try {
10858
+ response = await fetch(`${base}/app-token/venue-grant`, {
10859
+ method: 'POST',
10860
+ headers: { 'content-type': 'application/json' },
10861
+ body: JSON.stringify({ idToken, kind, id, walletProtocol: 2 }),
10862
+ });
10863
+ }
10864
+ catch (cause) {
10865
+ throw new VenueEscrowError('venue_grant_unavailable', 'Could not reach Bounded Auth to authorize this write.', { cause });
10866
+ }
10867
+ const body = (await response.json().catch(() => null));
10868
+ if (!response.ok) {
10869
+ const error = typeof (body === null || body === void 0 ? void 0 : body.error) === 'string' ? body.error : '';
10870
+ const code = Object.keys(GRANT_REFUSALS).includes(error) ? error : response.status >= 500 ? 'venue_grant_unavailable' : 'venue_grant_refused';
10871
+ throw new VenueEscrowError(code, (_a = GRANT_REFUSALS[code]) !== null && _a !== void 0 ? _a : `Bounded Auth refused the venue grant (${error || response.status}).`);
10872
+ }
10873
+ const fields = body !== null && body !== void 0 ? body : {};
10874
+ const { grant, venueAppId, rootAppId, walletAddress, path } = fields;
10875
+ if (typeof grant !== 'string' || !grant || typeof venueAppId !== 'string' || !APP_ID.test(venueAppId)
10876
+ || typeof rootAppId !== 'string' || !APP_ID.test(rootAppId) || walletAddress !== wallet || path !== recordPath(kind, rootAppId, id)) {
10877
+ throw new VenueEscrowError('venue_grant_unavailable', 'Bounded Auth answered with a grant that does not match this write.');
10878
+ }
10879
+ return { grant, venueAppId, rootAppId, path };
10880
+ }
10881
+ /* ------------------------------- reading -------------------------------- */
10882
+ /**
10883
+ * Read one venue escrow from the public record: its terms and its state (`pending` until the
10884
+ * venue's hook completes, `failed` when it did not). Resolves null when no such escrow exists.
10885
+ * No sign-in is needed.
10886
+ */
10887
+ async function getVenueEscrow(input) {
10888
+ var _a;
10889
+ const { rootAppId, escrowId } = input !== null && input !== void 0 ? input : {};
10890
+ if (!APP_ID.test(String(rootAppId)) || !RECORD_ID.test(String(escrowId))) {
10891
+ throw new VenueEscrowError('invalid_input', 'getVenueEscrow needs a rootAppId (24 hex characters) and an escrowId (32 hex characters).');
10892
+ }
10893
+ const base = (_a = (await getConfig()).devApiUrl) === null || _a === void 0 ? void 0 : _a.replace(/\/$/, '');
10894
+ if (!base)
10895
+ throw new VenueEscrowError('read_unavailable', 'The Bounded developer API is not configured. Pass a Bounded network to init().');
10896
+ let response;
10897
+ try {
10898
+ // The 200 is cacheable for a minute, and a funding is polled through `pending`.
10899
+ response = await fetch(`${base}/public/oapp/${rootAppId}/escrows/${escrowId}`, { cache: 'no-store' });
10900
+ }
10901
+ catch (cause) {
10902
+ throw new VenueEscrowError('read_unavailable', 'Could not reach the Bounded developer API.', { cause });
10903
+ }
10904
+ if (response.status === 404)
10905
+ return null;
10906
+ const body = (await response.json().catch(() => null));
10907
+ if (!response.ok || (body === null || body === void 0 ? void 0 : body.ok) !== true || !body.escrow || typeof body.escrow !== 'object') {
10908
+ throw new VenueEscrowError('read_unavailable', `The escrow could not be read (${response.status}).`);
10909
+ }
10910
+ return body.escrow;
10911
+ }
10912
+ /**
10913
+ * The overrides that point a receipt's reconciliation at the venue it was issued for and the RPC of
10914
+ * the chain it ran on (the same one the write was broadcast through), with no credential.
10915
+ */
10916
+ async function venueReadOverrides(venueAppId, chain) {
10917
+ var _a;
10918
+ const config = await getConfig();
10919
+ const rpcUrl = (_a = resolveVenueRpcUrl(config, chain, defaultSolanaRpcUrl)) !== null && _a !== void 0 ? _a : config.rpcUrl;
10920
+ return { _config: Object.assign(Object.assign({}, config), { appId: venueAppId, rpcUrl }), _readOnly: true };
10921
+ }
10922
+ const TERM_KEYS = ['payee', 'amountUsdc', 'challengeSeconds', 'expiresAt', 'ref'];
10923
+ /** Every term the funder signed, which a row must carry in full to be this funding. */
10924
+ const ROW_KEYS = ['schemaVersion', 'funder', 'payee', 'amountUsdc', 'challengeSeconds', 'expiresAt', 'ref', 'at'];
10925
+ /** The first thing wrong with these terms, or null. Shapes only: the venue's rule owns every bound. */
10926
+ function termsProblem(terms, wallet) {
10927
+ if (!terms || typeof terms.payee !== 'string' || !ADDRESS.test(terms.payee))
10928
+ return 'payee must be a Solana address';
10929
+ if (terms.payee === wallet)
10930
+ return 'payee must not be the wallet that is funding';
10931
+ for (const key of ['amountUsdc', 'challengeSeconds', 'expiresAt']) {
10932
+ if (!isCount(terms[key]))
10933
+ return `${key} must be a non-negative integer`;
10934
+ }
10935
+ if (typeof terms.ref !== 'string' || terms.ref.length < 1 || terms.ref.length > 128)
10936
+ return 'ref must be 1 to 128 characters';
10937
+ return null;
10938
+ }
10939
+ function isSavedSubmission(value) {
10940
+ var _a, _b;
10941
+ const saved = value;
10942
+ return !!saved && saved.status === 'submitted' && typeof saved.appId === 'string' && typeof saved.chain === 'string'
10943
+ && typeof saved.transactionId === 'string' && saved.transactionId.length > 0
10944
+ && typeof saved.signedTransaction === 'string' && Array.isArray(saved.requestedDocuments)
10945
+ && typeof ((_a = saved.fence) === null || _a === void 0 ? void 0 : _a.blockhash) === 'string' && Number.isSafeInteger((_b = saved.fence) === null || _b === void 0 ? void 0 : _b.lastValidBlockHeight);
10946
+ }
10947
+ function isPending(value, wallet) {
10948
+ const doc = value === null || value === void 0 ? void 0 : value.document;
10949
+ const sent = (value === null || value === void 0 ? void 0 : value.path) !== undefined;
10950
+ return RECORD_ID.test(String(value === null || value === void 0 ? void 0 : value.escrowId)) && Number.isSafeInteger(value.savedAtMs) && value.savedAtMs > 0
10951
+ && !!doc && doc.schemaVersion === ESCROW_SCHEMA && doc.funder === wallet && termsProblem(doc, wallet) === null && isCount(doc.at)
10952
+ && [doc.approvedAt, doc.approvedKind, doc.approvalId, doc.disputedAt, doc.disputedBy, doc.settledAt, doc.settledKind, doc.settledBy].every((field) => field === null)
10953
+ && (!sent || (APP_ID.test(String(value.rootAppId)) && APP_ID.test(String(value.venueAppId)) && value.path === recordPath('escrow', value.rootAppId, value.escrowId)))
10954
+ && (value.submission === undefined || isSavedSubmission(value.submission));
10955
+ }
10956
+ function store() {
10957
+ const storage = getPlatform().storage;
10958
+ // A volatile fallback would forget a funding that may have landed, and the next click would send a second one.
10959
+ if (isVolatileStorage(storage))
10960
+ throw new VenueEscrowError('storage_unavailable', 'Venue escrow funding needs durable browser storage.');
10961
+ return storage;
10962
+ }
10963
+ function loadPending(key, wallet) {
10964
+ const storage = store();
10965
+ try {
10966
+ const raw = storage.getItem(key);
10967
+ if (!raw)
10968
+ return null;
10969
+ const value = JSON.parse(raw);
10970
+ if (!isPending(value, wallet))
10971
+ throw new Error('malformed');
10972
+ return value;
10973
+ }
10974
+ catch (_a) {
10975
+ throw new VenueEscrowError('storage_unavailable', 'The saved escrow funding could not be read, so another one will not be started.');
10976
+ }
10977
+ }
10978
+ function savePending(key, pending) {
10979
+ const storage = store();
10980
+ try {
10981
+ storage.setItem(key, JSON.stringify(pending));
10982
+ }
10983
+ catch (_a) {
10984
+ throw new VenueEscrowError('storage_unavailable', 'The escrow funding could not be saved, so it was not sent.');
10985
+ }
10986
+ }
10987
+ function clearPending(key, escrowId) {
10988
+ try {
10989
+ const raw = store().getItem(key);
10990
+ if (raw && JSON.parse(raw).escrowId === escrowId)
10991
+ store().removeItem(key);
10992
+ }
10993
+ catch ( /* unreadable: the next call refuses to fund over it */_a) { /* unreadable: the next call refuses to fund over it */ }
10994
+ }
10995
+ function rowVerdict(pending, row) {
10996
+ var _a, _b;
10997
+ if (!ROW_KEYS.every((key) => row[key] === pending.document[key]))
10998
+ return { state: 'taken' };
10999
+ if (row.state === 'failed')
11000
+ return { state: 'failed' };
11001
+ if (row.state === 'pending')
11002
+ return { state: 'pending' };
11003
+ return { state: 'completed', transactionId: (_b = (_a = pending.submission) === null || _a === void 0 ? void 0 : _a.transactionId) !== null && _b !== void 0 ? _b : null };
11004
+ }
11005
+ /** Settle a saved funding without sending anything: the public row first, then its signature, then its age. */
11006
+ async function checkPending(pending) {
11007
+ if (!pending.path)
11008
+ return { state: 'not_applied', reason: 'it was interrupted before the venue was asked.' };
11009
+ let row;
11010
+ try {
11011
+ row = await getVenueEscrow({ rootAppId: pending.rootAppId, escrowId: pending.escrowId });
11012
+ }
11013
+ catch (_a) {
11014
+ return { state: 'pending' };
11015
+ }
11016
+ if (row)
11017
+ return rowVerdict(pending, row);
11018
+ if (pending.submission) {
11019
+ try {
11020
+ const settled = await reconcileSetResult(pending.submission, { _overrides: await venueReadOverrides(pending.venueAppId, pending.submission.chain) });
11021
+ if (settled.status === 'confirmed')
11022
+ return { state: 'completed', transactionId: settled.transactionId };
11023
+ if (settled.status === 'expired_not_landed')
11024
+ return { state: 'not_applied', reason: 'it expired before it reached the chain.' };
11025
+ }
11026
+ catch (error) {
11027
+ if (writeNotAppliedPhase(error) !== null)
11028
+ return { state: 'not_applied', reason: 'the transaction failed onchain.' };
11029
+ }
11030
+ return { state: 'pending' };
11031
+ }
11032
+ return Date.now() - pending.savedAtMs >= ABANDONED_MS
11033
+ ? { state: 'not_applied', reason: 'no transaction was ever recorded for it, and it can no longer land.' }
11034
+ : { state: 'pending' };
11035
+ }
11036
+ /** Poll the public row until it settles: a direct poofnet commit is not funded until the venue's hook stamps it. */
11037
+ async function awaitRow(pending) {
11038
+ for (const delay of RECEIPT_POLL_MS) {
11039
+ if (delay)
11040
+ await pause(delay);
11041
+ let row = null;
11042
+ try {
11043
+ row = await getVenueEscrow({ rootAppId: pending.rootAppId, escrowId: pending.escrowId });
11044
+ }
11045
+ catch ( /* keep polling */_a) { /* keep polling */ }
11046
+ const verdict = row ? rowVerdict(pending, row) : null;
11047
+ if (verdict && verdict.state !== 'pending')
11048
+ return verdict;
11049
+ }
11050
+ return { state: 'pending' };
11051
+ }
11052
+ /** The one place a funding ends: return its result, or release the saved record and throw why not. */
11053
+ function conclude(key, pending, verdict, terms) {
11054
+ const { escrowId } = pending;
11055
+ if (verdict.state === 'pending') {
11056
+ throw new VenueEscrowError('pending', 'The funding is not confirmed yet. Call fundVenueEscrow again with the same terms to check it; do not start another.', { escrowId });
11057
+ }
11058
+ clearPending(key, escrowId);
11059
+ switch (verdict.state) {
11060
+ case 'completed':
11061
+ if (terms && !TERM_KEYS.every((term) => pending.document[term] === terms[term])) {
11062
+ throw new VenueEscrowError('funded_other_terms', `An earlier, interrupted funding with different terms landed as escrow ${escrowId}. Check it with getVenueEscrow before funding again.`, { escrowId });
11063
+ }
11064
+ return { escrowId, rootAppId: pending.rootAppId, venueAppId: pending.venueAppId, transactionId: verdict.transactionId };
11065
+ case 'taken':
11066
+ throw new VenueEscrowError('taken', 'A different record already holds this escrow id, so this funding did not land.', { escrowId });
11067
+ case 'failed':
11068
+ throw new VenueEscrowError('failed', 'The venue accepted the funding but its hook failed, so nothing moved. Try again.', { escrowId });
11069
+ default:
11070
+ throw new VenueEscrowError('not_applied', `The funding did not go through: ${verdict.reason} nothing moved. Try again.`, { escrowId });
11071
+ }
11072
+ }
11073
+ /**
11074
+ * Read a thrown write: what the SDK, the wallet or the venue said, as a code. The venue's own code
11075
+ * is read before its status, because a 403 is not always its rule: a grant outside its scope
11076
+ * (`venue_grant_scope`), a forbidden precondition or a signer that does not match the signing
11077
+ * request are not, and only a decline (or the program's own rule rejection) is `rule_refused`.
11078
+ */
11079
+ function mapWriteError(error) {
11080
+ var _a;
11081
+ if (error instanceof VenueEscrowError)
11082
+ return error;
11083
+ const e = (error !== null && error !== void 0 ? error : {});
11084
+ const text = typeof e.message === 'string' ? e.message : String(error);
11085
+ const code = e.code === 'chain_mismatch' || e.code === 'chain_not_configured' || e.code === 'sponsorship_refused' || e.code === 'sponsorship_unavailable' ? e.code
11086
+ : e.name === 'InsufficientBalanceError' ? 'insufficient_balance'
11087
+ : e.code === 'venue_grant_scope' || e.statusCode === 401 ? 'grant_rejected'
11088
+ : e.isBoundedDecline === true || e.boundedRuleRejection === true ? 'rule_refused'
11089
+ : e.statusCode === 429 ? 'rate_limited'
11090
+ : /^top_level_required/.test(text) ? 'top_level_required'
11091
+ : /popup blocked/i.test(text) ? 'popup_blocked'
11092
+ // The wallet's or the window's own words only: a venue answer that happens to say "denied" is not the user declining.
11093
+ : e.statusCode === undefined && /user rejected|rejected the request|declined|denied|cancel|window was closed/i.test(text) ? 'declined'
11094
+ : 'write_failed';
11095
+ const message = code === 'rule_refused' && typeof ((_a = e.decline) === null || _a === void 0 ? void 0 : _a.message) === 'string' ? e.decline.message
11096
+ : e.boundedRuleRejection === true ? 'The venue\'s onchain rules refused this write, usually because the approval took longer than the two minutes a write stays valid. Start again.'
11097
+ : text;
11098
+ return new VenueEscrowError(code, message, { cause: error });
11099
+ }
11100
+ /** What a write that returned, rather than threw, means for this funding. */
11101
+ async function settleResult(key, pending, result, terms) {
11102
+ var _a;
11103
+ let current = result;
11104
+ if (current.status === 'submitted') {
11105
+ try {
11106
+ current = await waitForSetResult(current, { _overrides: await venueReadOverrides(pending.venueAppId, current.chain), timeoutMs: 60000 });
11107
+ }
11108
+ catch (error) {
11109
+ if (writeNotAppliedPhase(error) !== null) {
11110
+ clearPending(key, pending.escrowId);
11111
+ throw mapWriteError(error);
11112
+ }
11113
+ }
11114
+ }
11115
+ switch (current.status) {
11116
+ case 'confirmed':
11117
+ return conclude(key, pending, { state: 'completed', transactionId: current.transactionId }, terms);
11118
+ case 'committed': {
11119
+ const verdict = await awaitRow(pending);
11120
+ return conclude(key, pending, verdict.state === 'completed' ? { state: 'completed', transactionId: (_a = current.transactionId) !== null && _a !== void 0 ? _a : verdict.transactionId } : verdict, terms);
11121
+ }
11122
+ case 'expired_not_landed':
11123
+ return conclude(key, pending, { state: 'not_applied', reason: 'it expired before it reached the chain.' }, terms);
11124
+ case 'signed':
11125
+ return conclude(key, pending, { state: 'not_applied', reason: 'it was signed but never sent.' }, terms);
11126
+ default:
11127
+ return conclude(key, pending, { state: 'pending' }, terms);
11128
+ }
11129
+ }
11130
+ async function fundOrCheck(key, wallet, terms) {
11131
+ const saved = loadPending(key, wallet);
11132
+ if (saved)
11133
+ return conclude(key, saved, await checkPending(saved), terms);
11134
+ let pending = {
11135
+ escrowId: newRecordId(),
11136
+ savedAtMs: Date.now(),
11137
+ document: {
11138
+ payee: terms.payee, amountUsdc: terms.amountUsdc, challengeSeconds: terms.challengeSeconds, expiresAt: terms.expiresAt, ref: terms.ref,
11139
+ schemaVersion: ESCROW_SCHEMA, funder: wallet, at: nowSeconds(),
11140
+ approvedAt: null, approvedKind: null, approvalId: null, disputedAt: null, disputedBy: null,
11141
+ settledAt: null, settledKind: null, settledBy: null,
11142
+ },
11143
+ };
11144
+ const { escrowId } = pending;
11145
+ savePending(key, pending); // before any network call: the id must survive a lost answer
11146
+ let minted;
11147
+ try {
11148
+ minted = await mintGrant('escrow', escrowId, wallet);
11149
+ // The venue's rule holds `at` within two minutes of the chain clock, and the venue bakes it into the
11150
+ // transaction it builds from this write, so it is taken as late as it can be: after the mint, in the save
11151
+ // that adds the venue path, right before the write. The id and document were already saved before any
11152
+ // network call, and nothing has reached the venue yet, so recovery is unchanged.
11153
+ pending = Object.assign(Object.assign({}, pending), { document: Object.assign(Object.assign({}, pending.document), { at: nowSeconds() }), rootAppId: minted.rootAppId, venueAppId: minted.venueAppId, path: minted.path });
11154
+ savePending(key, pending);
11155
+ }
11156
+ catch (error) {
11157
+ clearPending(key, escrowId); // the venue was never asked, so there is nothing to settle
11158
+ throw error;
11159
+ }
11160
+ let result;
11161
+ try {
11162
+ result = await setWithVenueGrant(minted.path, pending.document, {
11163
+ venueAppId: minted.venueAppId,
11164
+ grant: minted.grant,
11165
+ commitGrant: async () => (await mintGrant('escrow', escrowId, wallet)).grant,
11166
+ resolveRpcUrl: defaultSolanaRpcUrl,
11167
+ onBroadcast: (submission) => {
11168
+ const next = Object.assign(Object.assign({}, pending), { submission });
11169
+ savePending(key, next);
11170
+ pending = next;
11171
+ },
11172
+ });
11173
+ }
11174
+ catch (error) {
11175
+ if (writeNotAppliedPhase(error) !== null) {
11176
+ clearPending(key, escrowId);
11177
+ throw mapWriteError(error);
11178
+ }
11179
+ // Anything else may follow a commit or broadcast whose answer was lost: settle it by the public
11180
+ // row, then by the saved signature. Never send again.
11181
+ const verdict = await awaitRow(pending);
11182
+ return conclude(key, pending, verdict.state === 'pending' && pending.submission ? await checkPending(pending) : verdict, terms);
11183
+ }
11184
+ return settleResult(key, pending, result, terms);
11185
+ }
11186
+ /** Poll the escrow until it shows disputed: a direct poofnet commit is not a dispute until the venue's hook stamps it. */
11187
+ async function awaitDisputed(rootAppId, escrowId) {
11188
+ for (const delay of RECEIPT_POLL_MS) {
11189
+ if (delay)
11190
+ await pause(delay);
11191
+ const row = await getVenueEscrow({ rootAppId, escrowId }).catch(() => null);
11192
+ if (row && row.disputedAt !== null)
11193
+ return true;
11194
+ }
11195
+ return false;
11196
+ }
11197
+ async function dispute(wallet, escrowId, reason) {
11198
+ const disputeId = newRecordId();
11199
+ const minted = await mintGrant('dispute', disputeId, wallet);
11200
+ let result = null;
11201
+ try {
11202
+ result = await setWithVenueGrant(minted.path, { escrowId, reason, at: nowSeconds() }, {
11203
+ venueAppId: minted.venueAppId,
11204
+ grant: minted.grant,
11205
+ commitGrant: async () => (await mintGrant('dispute', disputeId, wallet)).grant,
11206
+ resolveRpcUrl: defaultSolanaRpcUrl,
11207
+ });
11208
+ if (result.status === 'submitted')
11209
+ result = await waitForSetResult(result, { _overrides: await venueReadOverrides(minted.venueAppId, result.chain), timeoutMs: 60000 });
11210
+ }
11211
+ catch (error) {
11212
+ if (writeNotAppliedPhase(error) !== null)
11213
+ throw mapWriteError(error);
11214
+ // Anything else may follow a commit or broadcast whose answer was lost: the escrow says.
11215
+ }
11216
+ const done = { disputeId, rootAppId: minted.rootAppId, venueAppId: minted.venueAppId };
11217
+ if ((result === null || result === void 0 ? void 0 : result.status) === 'confirmed')
11218
+ return Object.assign(Object.assign({}, done), { transactionId: result.transactionId });
11219
+ if ((result === null || result === void 0 ? void 0 : result.status) === 'expired_not_landed' || (result === null || result === void 0 ? void 0 : result.status) === 'signed') {
11220
+ throw new VenueEscrowError('not_applied', 'The dispute never reached the chain, so nothing was sent. Try again.', { escrowId });
11221
+ }
11222
+ if (await awaitDisputed(minted.rootAppId, escrowId)) {
11223
+ return Object.assign(Object.assign({}, done), { transactionId: (result === null || result === void 0 ? void 0 : result.status) === 'committed' ? result.transactionId : null });
11224
+ }
11225
+ throw new VenueEscrowError('pending', 'The dispute was sent but is not confirmed yet. Read the escrow with getVenueEscrow to see whether it shows as disputed.', { escrowId });
11226
+ }
11227
+ /* ----------------------------- one call at a time ------------------------------ */
11228
+ const flights = new Map();
11229
+ /**
11230
+ * Run `run` unless an identical call is already in flight (a double click shares its result) or a
11231
+ * different one is (refused, never silently answered with the other's result). A Turnkey session's
11232
+ * signer window is reserved here, synchronously, because this runs inside the click.
11233
+ */
11234
+ function startFlow(key, fingerprint, needsSigner, run) {
11235
+ let reservation = null;
11236
+ try {
11237
+ const current = flights.get(key);
11238
+ if (current) {
11239
+ if (current.fingerprint === fingerprint)
11240
+ return current.promise;
11241
+ throw new VenueEscrowError('in_progress', 'A different venue escrow request is already in progress for this wallet.');
11242
+ }
11243
+ if (hasTurnkeyWallet() && needsSigner()) {
11244
+ reservation = reserveSignerPopup();
11245
+ if (!reservation)
11246
+ throw new VenueEscrowError('popup_blocked', 'Call this from a click handler so the wallet approval window can open, and allow popups for this site.');
11247
+ }
11248
+ // A flow that fails before the signer loads (a grant the venue refuses, a rule) leaves the reserved
11249
+ // window to explain itself with the error's words for a moment; one that signed has closed it already.
11250
+ const settled = (error) => {
11251
+ var _a;
11252
+ if (((_a = flights.get(key)) === null || _a === void 0 ? void 0 : _a.promise) === promise)
11253
+ flights.delete(key);
11254
+ reservation === null || reservation === void 0 ? void 0 : reservation.release(error instanceof Error ? error.message : undefined);
11255
+ };
11256
+ const promise = run().then((value) => { settled(); return value; }, (error) => { settled(error); throw error; });
11257
+ flights.set(key, { fingerprint, promise });
11258
+ return promise;
11259
+ }
11260
+ catch (error) {
11261
+ reservation === null || reservation === void 0 ? void 0 : reservation.release(error instanceof Error ? error.message : undefined);
11262
+ return Promise.reject(error);
11263
+ }
11264
+ }
11265
+ /** One tab funds at a time: the saved record is shared by every tab of this browser. */
11266
+ function withLock(key, run) {
11267
+ var _a;
11268
+ const locks = (_a = globalThis.navigator) === null || _a === void 0 ? void 0 : _a.locks;
11269
+ if (!(locks === null || locks === void 0 ? void 0 : locks.request))
11270
+ return Promise.reject(new VenueEscrowError('lock_unavailable', 'Venue escrow funding needs the Web Locks API, so that one tab funds at a time.'));
11271
+ return locks.request(key, { ifAvailable: true }, async (lock) => {
11272
+ if (!lock)
11273
+ throw new VenueEscrowError('in_progress', 'This escrow is already being funded in another tab.');
11274
+ return run();
11275
+ });
11276
+ }
11277
+ /* --------------------------------- public API ---------------------------------- */
11278
+ /**
11279
+ * Lock USDC in the venue escrow for `terms.payee`, signed by the wallet signed in here.
11280
+ * MUST be called from a user click: an email (Turnkey) wallet's approval opens in its own Bounded
11281
+ * window, which a browser only allows inside the click (it is opened here, before anything is
11282
+ * awaited), and the approval shows the decoded terms. A Phantom or Wallet Standard wallet keeps
11283
+ * its own prompt. On a real-chain venue the transaction is broadcast on the VENUE's chain: through
11284
+ * the app's own `rpcUrl` when the app configured that same `chain` too (an `rpcUrl` alone does not
11285
+ * say which chain it speaks), otherwise through the platform's default RPC for the venue's chain, so
11286
+ * an app that never configured a chain just works. An app that configured a different `chain` is
11287
+ * refused (`chain_mismatch`) before anything is signed.
11288
+ *
11289
+ * Funding is made safe to retry: a funding that was interrupted (page closed, answer lost) is
11290
+ * saved before anything is sent, and the next call checks it instead of funding again, so pass
11291
+ * the same terms and it resolves to the same `escrowId`. Store `escrowId` on your own record.
11292
+ * See {@link VenueEscrowErrorCode} for the failures, and `pending` in particular.
11293
+ */
11294
+ function fundVenueEscrow(terms) {
11295
+ try {
11296
+ const { appId, wallet } = sessionIdentity();
11297
+ const problem = termsProblem(terms, wallet);
11298
+ if (problem)
11299
+ throw new VenueEscrowError('invalid_input', `fundVenueEscrow: ${problem}.`);
11300
+ const checked = {
11301
+ payee: terms.payee, amountUsdc: terms.amountUsdc, challengeSeconds: terms.challengeSeconds, expiresAt: terms.expiresAt, ref: terms.ref,
11302
+ };
11303
+ const key = `${STORAGE_PREFIX}:${appId}:${wallet}`;
11304
+ return startFlow(key, JSON.stringify(checked), () => !loadPending(key, wallet), () => withLock(key, () => fundOrCheck(key, wallet, checked)));
11305
+ }
11306
+ catch (error) {
11307
+ return Promise.reject(error);
11308
+ }
11309
+ }
11310
+ /**
11311
+ * Dispute a funded venue escrow as its funder (or payee), signed by the wallet signed in here.
11312
+ * MUST be called from a user click, for the same reason as {@link fundVenueEscrow}. `reason` is
11313
+ * 1 to 400 bytes of UTF-8: the venue allows 1000 characters, but a longer reason does not fit one
11314
+ * legacy-format transaction. Nothing is saved: a dispute that already landed makes the venue refuse
11315
+ * a second one (`rule_refused`).
11316
+ */
11317
+ function disputeVenueEscrow(input) {
11318
+ try {
11319
+ const { appId, wallet } = sessionIdentity();
11320
+ const { escrowId, reason } = input !== null && input !== void 0 ? input : {};
11321
+ if (!RECORD_ID.test(String(escrowId)))
11322
+ throw new VenueEscrowError('invalid_input', 'disputeVenueEscrow: escrowId must be 32 hex characters.');
11323
+ if (typeof reason !== 'string' || reason.length < 1 || new TextEncoder().encode(reason).length > MAX_DISPUTE_REASON_BYTES) {
11324
+ throw new VenueEscrowError('invalid_input', `disputeVenueEscrow: reason must be 1 to ${MAX_DISPUTE_REASON_BYTES} bytes.`);
11325
+ }
11326
+ return startFlow(`dispute:${appId}:${wallet}:${escrowId}`, reason, () => true, () => dispute(wallet, escrowId, reason));
11327
+ }
11328
+ catch (error) {
11329
+ return Promise.reject(error);
11330
+ }
11331
+ }
11332
+
10598
11333
  /**
10599
11334
  * DS3-0414: does the transaction already carry a REAL signer signature? A Solana
10600
11335
  * signature is computed over the compiled message, which INCLUDES recentBlockhash, so
@@ -10996,25 +11731,6 @@ class PrivyExpoProvider {
10996
11731
  }
10997
11732
  }
10998
11733
 
10999
- /**
11000
- * Default provider discovery: Phantom-first, then any Wallet-Standard
11001
- * `window.solana`. Kept tiny + synchronous (no heavy imports) so it works inside
11002
- * a user gesture and can be eagerly exported from the SDK entry.
11003
- */
11004
- function defaultInjectedProvider() {
11005
- var _a;
11006
- if (typeof window === 'undefined')
11007
- return null;
11008
- const w = window;
11009
- const phantom = (_a = w === null || w === void 0 ? void 0 : w.phantom) === null || _a === void 0 ? void 0 : _a.solana;
11010
- if (phantom && typeof phantom.signMessage === 'function')
11011
- return phantom;
11012
- const generic = w === null || w === void 0 ? void 0 : w.solana;
11013
- if (generic && typeof generic.signMessage === 'function')
11014
- return generic;
11015
- return null;
11016
- }
11017
-
11018
11734
  // injected-evm-wallet-types.ts — tiny, dependency-free surface for the EVM
11019
11735
  // WALLET LOGIN path (BYO wallet via SIWE). The EVM twin of
11020
11736
  // injected-wallet-types.ts: kept separate from injected-evm-wallet-provider.ts
@@ -11404,5 +12120,5 @@ function init(config = {}) {
11404
12120
  return init$1(resolved);
11405
12121
  }
11406
12122
 
11407
- export { onrampStatus as $, getAuthProvider as A, signInAnonymously as B, loginWithPrivy as C, loginWithWallet as D, ensureWalletLoginReady as E, ensureSharedWalletLoginReady as F, preloadWalletLogin as G, loginWithRedirect as H, completeLoginFromRedirect as I, getLoginReturnError as J, loginWithPopup as K, openBoundedWidget as L, ensureSignedIn as M, useAuth as N, useQuery as O, useBuildRun as P, apps as Q, signSolanaMessageViaTurnkey as R, getOrCreateTurnkeyWallet as S, openTurnkeyKeyExport as T, getTurnkeyWalletSessionState as U, getTurnkeyWalletRecoveryUrl as V, WalletConfigError as W, startTurnkeyEmailLogin as X, getIdToken as Y, onramp as Z, onrampQuote as _, signMessageWithTurnkey as a, setPlatform as a0, OffchainAuthProvider as a1, PrivyExpoProvider as a2, requestEip6963Providers as a3, connectBroadcast as a4, connectServiceSession as a5, builds as a6, BuildsApiError as a7, mediaAgentTools as a8, NON_TERMINAL_STATES as a9, TERMINAL_STATES as aa, RUN_STATES as ab, PARK_REASONS as ac, FAILURE_REASONS as ad, BUILD_REVIEW_CAPABILITY_SCHEMA as ae, BUILD_REVIEW_CAPABILITY_REFRESH_SCHEMA as af, BUILD_DELEGATED_REVIEW_CAPABILITY_SCHEMA as ag, signTransactionWithTurnkey as b, signTransactionV1WithTurnkey as c, signAndSubmitTransactionWithTurnkey as d, bs58 as e, defaultInjectedProvider as f, getPlatform as g, hasTurnkeyWallet as h, firstStandardWalletProvider as i, setAuthLoading as j, bufferExports as k, setStoredAuthMethod as l, confirmAndCheckTransaction as m, normalizeSolanaRpcUrl as n, defaultInjectedEvmProvider as o, init as p, getCurrentUser as q, resolveSolanaRpcUrl as r, setCurrentUser as s, transactionHasSignature as t, onAuthStateChanged as u, onAuthLoadingChanged as v, getAuthLoading as w, waitForAuthReady as x, login as y, logout as z };
11408
- //# sourceMappingURL=index-BAiLpNEQ.mjs.map
12123
+ export { onramp as $, logout as A, getAuthProvider as B, signInAnonymously as C, loginWithPrivy as D, loginWithWallet as E, ensureWalletLoginReady as F, ensureSharedWalletLoginReady as G, preloadWalletLogin as H, loginWithRedirect as I, completeLoginFromRedirect as J, getLoginReturnError as K, loginWithPopup as L, openBoundedWidget as M, ensureSignedIn as N, useAuth as O, useQuery as P, useBuildRun as Q, apps as R, SELECTED_WALLET_UNAVAILABLE_ERR as S, signSolanaMessageViaTurnkey as T, getOrCreateTurnkeyWallet as U, openTurnkeyKeyExport as V, WalletConfigError as W, getTurnkeyWalletSessionState as X, getTurnkeyWalletRecoveryUrl as Y, startTurnkeyEmailLogin as Z, getIdToken as _, signMessageWithTurnkey as a, onrampQuote as a0, onrampStatus as a1, fundVenueEscrow as a2, disputeVenueEscrow as a3, getVenueEscrow as a4, VenueEscrowError as a5, setPlatform as a6, OffchainAuthProvider as a7, PrivyExpoProvider as a8, requestEip6963Providers as a9, connectBroadcast as aa, connectServiceSession as ab, builds as ac, BuildsApiError as ad, mediaAgentTools as ae, NON_TERMINAL_STATES as af, TERMINAL_STATES as ag, RUN_STATES as ah, PARK_REASONS as ai, FAILURE_REASONS as aj, BUILD_REVIEW_CAPABILITY_SCHEMA as ak, BUILD_REVIEW_CAPABILITY_REFRESH_SCHEMA as al, BUILD_DELEGATED_REVIEW_CAPABILITY_SCHEMA as am, signTransactionWithTurnkey as b, signTransactionV1WithTurnkey as c, signAndSubmitTransactionWithTurnkey as d, bs58 as e, defaultInjectedProvider as f, getPlatform as g, hasTurnkeyWallet as h, firstStandardWalletProvider as i, setAuthLoading as j, supportsWalletSignIn as k, bufferExports as l, setStoredAuthMethod as m, normalizeSolanaRpcUrl as n, confirmAndCheckTransaction as o, defaultInjectedEvmProvider as p, init as q, resolveSolanaRpcUrl as r, setCurrentUser as s, transactionHasSignature as t, getCurrentUser as u, onAuthStateChanged as v, onAuthLoadingChanged as w, getAuthLoading as x, waitForAuthReady as y, login as z };
12124
+ //# sourceMappingURL=index-C63ceG_z.mjs.map