@bounded-sh/client 0.0.59 → 0.0.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{email-auth-provider-N-dfsNnE.js → email-auth-provider-9BwSziWj.js} +2 -2
- package/dist/{email-auth-provider-N-dfsNnE.js.map → email-auth-provider-9BwSziWj.js.map} +1 -1
- package/dist/{email-auth-provider-DhAMOILG.mjs → email-auth-provider-B3XaJw-G.mjs} +2 -2
- package/dist/{email-auth-provider-deB_ADc5.mjs.map → email-auth-provider-B3XaJw-G.mjs.map} +1 -1
- package/dist/{email-auth-provider-BSw9FRjg.js → email-auth-provider-BttT2sZK.js} +2 -2
- package/dist/{email-auth-provider-BSw9FRjg.js.map → email-auth-provider-BttT2sZK.js.map} +1 -1
- package/dist/{email-auth-provider-deB_ADc5.mjs → email-auth-provider-Cb4VKA1E.mjs} +2 -2
- package/dist/{email-auth-provider-DhAMOILG.mjs.map → email-auth-provider-Cb4VKA1E.mjs.map} +1 -1
- package/dist/{guest-auth-provider-D9wbogwi.mjs → guest-auth-provider-BBPpydtM.mjs} +2 -2
- package/dist/{guest-auth-provider-B78Ugfar.mjs.map → guest-auth-provider-BBPpydtM.mjs.map} +1 -1
- package/dist/{guest-auth-provider-B78Ugfar.mjs → guest-auth-provider-BBSFawAr.mjs} +2 -2
- package/dist/{guest-auth-provider-D9wbogwi.mjs.map → guest-auth-provider-BBSFawAr.mjs.map} +1 -1
- package/dist/{guest-auth-provider-Czl48mOP.js → guest-auth-provider-BcR-MQ0g.js} +2 -2
- package/dist/{guest-auth-provider-Czl48mOP.js.map → guest-auth-provider-BcR-MQ0g.js.map} +1 -1
- package/dist/{guest-auth-provider-BFodq9Rc.js → guest-auth-provider-Di0TRg-z.js} +2 -2
- package/dist/{guest-auth-provider-BFodq9Rc.js.map → guest-auth-provider-Di0TRg-z.js.map} +1 -1
- package/dist/{index-uu8hKP-p.js → index-C_L497w1.js} +191 -51
- package/dist/index-C_L497w1.js.map +1 -0
- package/dist/{index-SHt4VZZV.mjs → index-L2R6C5Vl.mjs} +190 -52
- package/dist/index-L2R6C5Vl.mjs.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{index.native-D-8IAEy-.mjs → index.native-BIUs8t7F.mjs} +182 -51
- package/dist/index.native-BIUs8t7F.mjs.map +1 -0
- package/dist/{index.native-D48QQ0-q.js → index.native-BSheiGj2.js} +183 -50
- package/dist/index.native-BSheiGj2.js.map +1 -0
- package/dist/index.native.d.ts +2 -2
- package/dist/index.native.js +3 -1
- package/dist/index.native.js.map +1 -1
- package/dist/index.native.mjs +1 -1
- package/dist/{injected-evm-wallet-provider-HQMOL_mZ.js → injected-evm-wallet-provider-7XawIUdJ.js} +2 -2
- package/dist/{injected-evm-wallet-provider-HQMOL_mZ.js.map → injected-evm-wallet-provider-7XawIUdJ.js.map} +1 -1
- package/dist/{injected-evm-wallet-provider-UWvcy-LO.mjs → injected-evm-wallet-provider-DSFDC8fh.mjs} +2 -2
- package/dist/{injected-evm-wallet-provider-UWvcy-LO.mjs.map → injected-evm-wallet-provider-DSFDC8fh.mjs.map} +1 -1
- package/dist/{injected-evm-wallet-provider-CItxws1D.js → injected-evm-wallet-provider-DgWUaVtt.js} +2 -2
- package/dist/{injected-evm-wallet-provider-CItxws1D.js.map → injected-evm-wallet-provider-DgWUaVtt.js.map} +1 -1
- package/dist/{injected-evm-wallet-provider-CJsLX16m.mjs → injected-evm-wallet-provider-DnOrVMDX.mjs} +2 -2
- package/dist/{injected-evm-wallet-provider-CJsLX16m.mjs.map → injected-evm-wallet-provider-DnOrVMDX.mjs.map} +1 -1
- package/dist/{injected-wallet-provider-CmXqreEE.js → injected-wallet-provider-BMDJntMD.js} +2 -2
- package/dist/{injected-wallet-provider-CmXqreEE.js.map → injected-wallet-provider-BMDJntMD.js.map} +1 -1
- package/dist/{injected-wallet-provider-BihII94U.mjs → injected-wallet-provider-DfJvN3sV.mjs} +2 -2
- package/dist/{injected-wallet-provider-BihII94U.mjs.map → injected-wallet-provider-DfJvN3sV.mjs.map} +1 -1
- package/dist/{injected-wallet-provider-CNYAynIB.mjs → injected-wallet-provider-ZkPzVj5W.mjs} +2 -2
- package/dist/{injected-wallet-provider-CNYAynIB.mjs.map → injected-wallet-provider-ZkPzVj5W.mjs.map} +1 -1
- package/dist/{injected-wallet-provider-CVeZgfEt.js → injected-wallet-provider-oCRGuls5.js} +2 -2
- package/dist/{injected-wallet-provider-CVeZgfEt.js.map → injected-wallet-provider-oCRGuls5.js.map} +1 -1
- package/dist/onramp.d.ts +51 -9
- package/package.json +2 -2
- package/dist/index-SHt4VZZV.mjs.map +0 -1
- package/dist/index-uu8hKP-p.js.map +0 -1
- package/dist/index.native-D-8IAEy-.mjs.map +0 -1
- package/dist/index.native-D48QQ0-q.js.map +0 -1
|
@@ -3686,6 +3686,7 @@ const OIDC_NO_WALLET = 'This login has no embedded wallet. Enable `"auth": { "wa
|
|
|
3686
3686
|
'then sign from a user gesture.';
|
|
3687
3687
|
const PKCE_STORE_KEY = 'bounded.oidc.pkce';
|
|
3688
3688
|
const STORED_AUTH_METHOD_KEY$1 = 'bounded_last_auth_method';
|
|
3689
|
+
const ISSUER_SESSION_KIND_KEY$1 = 'bounded_issuer_session_kind';
|
|
3689
3690
|
// Active session store (Web on web, RN on React Native) — selected by config,
|
|
3690
3691
|
// not by `typeof window` (truthy on RN). OIDC redirect/popup is web-only, but the
|
|
3691
3692
|
// session it mints is read back through this same selector everywhere.
|
|
@@ -4174,6 +4175,13 @@ async function establishInlineSession(data) {
|
|
|
4174
4175
|
getPlatform().storage.setItem(STORED_AUTH_METHOD_KEY$1, 'email');
|
|
4175
4176
|
}
|
|
4176
4177
|
catch ( /* storage unavailable */_a) { /* storage unavailable */ }
|
|
4178
|
+
// Turnkey-native OTP mints an app session directly. It does not establish a
|
|
4179
|
+
// Better Auth browser cookie on the issuer, so logout must not navigate
|
|
4180
|
+
// through the issuer's cookie-clearing /logout endpoint.
|
|
4181
|
+
try {
|
|
4182
|
+
getPlatform().storage.setItem(ISSUER_SESSION_KIND_KEY$1, 'inline');
|
|
4183
|
+
}
|
|
4184
|
+
catch ( /* storage unavailable */_b) { /* storage unavailable */ }
|
|
4177
4185
|
setCurrentUser(user);
|
|
4178
4186
|
setAuthProviderInstance(oidcProviderSingleton);
|
|
4179
4187
|
return user;
|
|
@@ -4220,6 +4228,13 @@ async function exchangeCode(code, verifier, redirectUri) {
|
|
|
4220
4228
|
getPlatform().storage.setItem(STORED_AUTH_METHOD_KEY$1, 'email');
|
|
4221
4229
|
}
|
|
4222
4230
|
catch ( /* storage unavailable */_b) { /* storage unavailable */ }
|
|
4231
|
+
// OIDC login does establish the issuer's Better Auth browser cookie. Record
|
|
4232
|
+
// that fact separately from the provider name so logout clears the cookie
|
|
4233
|
+
// and returns through the registered app origin.
|
|
4234
|
+
try {
|
|
4235
|
+
getPlatform().storage.setItem(ISSUER_SESSION_KIND_KEY$1, 'hosted');
|
|
4236
|
+
}
|
|
4237
|
+
catch ( /* storage unavailable */_c) { /* storage unavailable */ }
|
|
4223
4238
|
setCurrentUser(user);
|
|
4224
4239
|
setAuthProviderInstance(oidcProviderSingleton);
|
|
4225
4240
|
return user;
|
|
@@ -4236,6 +4251,7 @@ const objectIdentityKeys = new WeakMap();
|
|
|
4236
4251
|
let nextObjectIdentityKey = 1;
|
|
4237
4252
|
// --- localStorage helpers: track which auth method created the active session ---
|
|
4238
4253
|
const STORED_AUTH_METHOD_KEY = 'bounded_last_auth_method';
|
|
4254
|
+
const ISSUER_SESSION_KIND_KEY = 'bounded_issuer_session_kind';
|
|
4239
4255
|
function getStoredAuthMethod() {
|
|
4240
4256
|
try {
|
|
4241
4257
|
return getPlatform().storage.getItem(STORED_AUTH_METHOD_KEY);
|
|
@@ -4252,11 +4268,25 @@ function setStoredAuthMethod(method) {
|
|
|
4252
4268
|
else {
|
|
4253
4269
|
getPlatform().storage.removeItem(STORED_AUTH_METHOD_KEY);
|
|
4254
4270
|
}
|
|
4271
|
+
// Non-email providers cannot own a Better Auth browser session. Clear
|
|
4272
|
+
// any prior hosted/inline classification when the active provider is
|
|
4273
|
+
// replaced or the session is removed.
|
|
4274
|
+
if (method !== 'email') {
|
|
4275
|
+
getPlatform().storage.removeItem(ISSUER_SESSION_KIND_KEY);
|
|
4276
|
+
}
|
|
4255
4277
|
}
|
|
4256
4278
|
catch (_a) {
|
|
4257
4279
|
// storage might not be available
|
|
4258
4280
|
}
|
|
4259
4281
|
}
|
|
4282
|
+
function getIssuerSessionKind() {
|
|
4283
|
+
try {
|
|
4284
|
+
return getPlatform().storage.getItem(ISSUER_SESSION_KIND_KEY);
|
|
4285
|
+
}
|
|
4286
|
+
catch (_a) {
|
|
4287
|
+
return null;
|
|
4288
|
+
}
|
|
4289
|
+
}
|
|
4260
4290
|
function getStoredIdToken() {
|
|
4261
4291
|
try {
|
|
4262
4292
|
return getActiveSessionManager().getIdToken();
|
|
@@ -4515,7 +4545,7 @@ async function getAuthProvider(config) {
|
|
|
4515
4545
|
// manager as legacy email sessions. Human login should be started
|
|
4516
4546
|
// with loginWithRedirect(); this provider is kept as the restore and
|
|
4517
4547
|
// logout surface for those sessions.
|
|
4518
|
-
currentAuthProvider = new (await import('./email-auth-provider-
|
|
4548
|
+
currentAuthProvider = new (await import('./email-auth-provider-B3XaJw-G.mjs')).EmailAuthProvider();
|
|
4519
4549
|
break;
|
|
4520
4550
|
case "wallet":
|
|
4521
4551
|
case "phantom": {
|
|
@@ -4534,7 +4564,7 @@ async function getAuthProvider(config) {
|
|
|
4534
4564
|
if (!isWalletLoginEnabled(config)) {
|
|
4535
4565
|
throw walletLoginNotEnabledError(authMethod);
|
|
4536
4566
|
}
|
|
4537
|
-
const { InjectedWalletProvider } = await import('./injected-wallet-provider-
|
|
4567
|
+
const { InjectedWalletProvider } = await import('./injected-wallet-provider-DfJvN3sV.mjs');
|
|
4538
4568
|
currentAuthProvider = new InjectedWalletProvider(resolveInjectedWalletConfig(config), rpcUrl, configuredNetwork);
|
|
4539
4569
|
break;
|
|
4540
4570
|
}
|
|
@@ -4547,7 +4577,7 @@ async function getAuthProvider(config) {
|
|
|
4547
4577
|
// Selecting authMethod:'evm-wallet' IS the opt-in — pass evmWalletConfig
|
|
4548
4578
|
// to point at a specific wallet or set chainId/domain.
|
|
4549
4579
|
const evmWalletConfig = ((_a = config.evmWalletConfig) !== null && _a !== void 0 ? _a : {});
|
|
4550
|
-
const { InjectedEvmWalletProvider } = await import('./injected-evm-wallet-provider-
|
|
4580
|
+
const { InjectedEvmWalletProvider } = await import('./injected-evm-wallet-provider-DSFDC8fh.mjs');
|
|
4551
4581
|
currentAuthProvider = new InjectedEvmWalletProvider(evmWalletConfig);
|
|
4552
4582
|
break;
|
|
4553
4583
|
}
|
|
@@ -4575,7 +4605,7 @@ async function getAuthProvider(config) {
|
|
|
4575
4605
|
break;
|
|
4576
4606
|
case "guest":
|
|
4577
4607
|
// Anonymous auth: a device-local ed25519 keypair signs the challenge.
|
|
4578
|
-
currentAuthProvider = new (await import('./guest-auth-provider-
|
|
4608
|
+
currentAuthProvider = new (await import('./guest-auth-provider-BBSFawAr.mjs')).GuestAuthProvider();
|
|
4579
4609
|
break;
|
|
4580
4610
|
}
|
|
4581
4611
|
if (!currentAuthProvider) {
|
|
@@ -4631,7 +4661,7 @@ async function signInAnonymously() {
|
|
|
4631
4661
|
// Lazy-load the guest provider so its ed25519/web3 dependencies stay out of
|
|
4632
4662
|
// the main bundle for data-only apps. Specifier is a static string literal
|
|
4633
4663
|
// so bundle-splitting can see it.
|
|
4634
|
-
const provider = new (await import('./guest-auth-provider-
|
|
4664
|
+
const provider = new (await import('./guest-auth-provider-BBSFawAr.mjs')).GuestAuthProvider();
|
|
4635
4665
|
setAuthLoading(true); // reflect "signing in…" while the guest keypair session is minted
|
|
4636
4666
|
const commit = (user) => {
|
|
4637
4667
|
// No await/interleaving inside this block: provider/method/config/marker
|
|
@@ -4782,7 +4812,7 @@ async function loginWithWallet(options) {
|
|
|
4782
4812
|
? Object.assign(Object.assign({}, base), { getProvider: options.getProvider }) : base;
|
|
4783
4813
|
const rpcUrl = normalizeSolanaRpcUrl(cfg.rpcUrl);
|
|
4784
4814
|
const network = getConfiguredSolanaNetwork(cfg);
|
|
4785
|
-
const { InjectedWalletProvider } = await import('./injected-wallet-provider-
|
|
4815
|
+
const { InjectedWalletProvider } = await import('./injected-wallet-provider-DfJvN3sV.mjs');
|
|
4786
4816
|
let provider = new InjectedWalletProvider(injectedConfig, rpcUrl, network);
|
|
4787
4817
|
if (coreConfig.chain === 'offchain')
|
|
4788
4818
|
provider = new OffchainAuthProvider(provider);
|
|
@@ -4854,7 +4884,7 @@ function getCurrentAuthMethod() {
|
|
|
4854
4884
|
// allowlist here: on a trusted origin we end the issuer session with a
|
|
4855
4885
|
// top-level bounce; anywhere else (custom domains, http dev) we keep the
|
|
4856
4886
|
// local-only logout instead of stranding the user on the issuer origin.
|
|
4857
|
-
function issuerLogoutBounceUrl(issuerBase) {
|
|
4887
|
+
function issuerLogoutBounceUrl(issuerBase, idTokenHint) {
|
|
4858
4888
|
if (typeof window === 'undefined' || typeof document === 'undefined')
|
|
4859
4889
|
return null; // RN/Node: no shared cookie jar to clear this way
|
|
4860
4890
|
try {
|
|
@@ -4877,12 +4907,27 @@ function issuerLogoutBounceUrl(issuerBase) {
|
|
|
4877
4907
|
if (!trusted)
|
|
4878
4908
|
return null;
|
|
4879
4909
|
const base = issuerBase.replace(/\/$/, '');
|
|
4880
|
-
|
|
4910
|
+
// #228: send the id_token_hint so the issuer can bind the post-logout redirect to this
|
|
4911
|
+
// session + app + registered origin. Without it the issuer safely falls back to its own
|
|
4912
|
+
// origin (it no longer trusts a bare suffix match), so the return-to-app bounce is a no-op.
|
|
4913
|
+
const hint = idTokenHint ? `&id_token_hint=${encodeURIComponent(idTokenHint)}` : '';
|
|
4914
|
+
return `${base}/logout?redirect_uri=${encodeURIComponent(here.href)}${hint}`;
|
|
4881
4915
|
}
|
|
4882
4916
|
catch (_b) {
|
|
4883
4917
|
return null;
|
|
4884
4918
|
}
|
|
4885
4919
|
}
|
|
4920
|
+
// #228 helper, deliberately OUTSIDE logout(): the logout body is source-guarded
|
|
4921
|
+
// against any `catch` so a revokeSession failure can never be swallowed, and a
|
|
4922
|
+
// missing id token is the one benign absence worth tolerating here.
|
|
4923
|
+
function idTokenHintOrNull(sm) {
|
|
4924
|
+
try {
|
|
4925
|
+
return sm.getIdToken();
|
|
4926
|
+
}
|
|
4927
|
+
catch (_a) {
|
|
4928
|
+
return null; /* no id token to hint with */
|
|
4929
|
+
}
|
|
4930
|
+
}
|
|
4886
4931
|
async function logout$1(options) {
|
|
4887
4932
|
// Re-initialize the provider if it was cleared by a prior logout — the exact mirror
|
|
4888
4933
|
// of login()'s self-heal above. A hosted popup/redirect login (loginWithPopup /
|
|
@@ -4907,17 +4952,20 @@ async function logout$1(options) {
|
|
|
4907
4952
|
const sm = getActiveSessionManager();
|
|
4908
4953
|
const refreshToken = sm.getRefreshToken();
|
|
4909
4954
|
const sessionIssuer = sm.getIssuer();
|
|
4955
|
+
// #228: capture the id token NOW, before currentAuthProvider.logout() clears the session, so we
|
|
4956
|
+
// can hand it to the issuer /logout as an id_token_hint (which binds the post-logout redirect).
|
|
4957
|
+
const idTokenHint = idTokenHintOrNull(sm);
|
|
4910
4958
|
if (refreshToken)
|
|
4911
4959
|
await revokeSession(refreshToken, sessionIssuer !== null && sessionIssuer !== void 0 ? sessionIssuer : undefined);
|
|
4912
|
-
//
|
|
4913
|
-
//
|
|
4914
|
-
//
|
|
4915
|
-
//
|
|
4916
|
-
//
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4960
|
+
// Only OIDC-hosted sessions own an issuer browser cookie. Turnkey-native
|
|
4961
|
+
// email OTP is also an email auth method, but it mints the app session
|
|
4962
|
+
// inline and has no issuer cookie to clear. Use the explicit session-kind
|
|
4963
|
+
// marker when present. The auth-method fallback preserves correct logout
|
|
4964
|
+
// behavior for hosted sessions created by older SDK versions.
|
|
4965
|
+
const issuerSessionKind = getIssuerSessionKind();
|
|
4966
|
+
const wasHosted = issuerSessionKind === 'hosted'
|
|
4967
|
+
|| (issuerSessionKind === null
|
|
4968
|
+
&& (currentAuthMethod === 'email' || getStoredAuthMethod() === 'email'));
|
|
4921
4969
|
await currentAuthProvider.logout();
|
|
4922
4970
|
setStoredAuthMethod(null);
|
|
4923
4971
|
currentAuthProvider = null;
|
|
@@ -4927,7 +4975,7 @@ async function logout$1(options) {
|
|
|
4927
4975
|
const issuerBase = sessionIssuer
|
|
4928
4976
|
|| (await getConfig()).humanAuthApiUrl
|
|
4929
4977
|
|| 'https://auth.bounded.sh';
|
|
4930
|
-
const bounce = issuerLogoutBounceUrl(issuerBase);
|
|
4978
|
+
const bounce = issuerLogoutBounceUrl(issuerBase, idTokenHint);
|
|
4931
4979
|
// Local state is already cleared, so even if the navigation is stopped
|
|
4932
4980
|
// (tab close, extension) the app-side logout has fully happened.
|
|
4933
4981
|
if (bounce)
|
|
@@ -7363,30 +7411,117 @@ async function signSolanaMessageViaTurnkey(message) {
|
|
|
7363
7411
|
// session is bound server-side to the caller's verified Bounded JWT, and the
|
|
7364
7412
|
// destination defaults to that user's embedded wallet.
|
|
7365
7413
|
//
|
|
7414
|
+
// Amount semantics:
|
|
7415
|
+
// amountUsd - exact fiat in; the fee/output breakdown comes back as `quote`.
|
|
7416
|
+
// minAmountOut - a FLOOR on crypto received. The platform quotes Coinbase's
|
|
7417
|
+
// worst-fee payment method (card) and pads by `slippagePad` (default 1%),
|
|
7418
|
+
// so cheaper methods overshoot the floor rather than undershooting it. The
|
|
7419
|
+
// floor holds unless the market moves more than the pad while the user sits
|
|
7420
|
+
// on the checkout screen - which is why completion is VERIFIED: after the
|
|
7421
|
+
// popup closes we poll the platform's status leg and resolve with the
|
|
7422
|
+
// actual filled amount when Coinbase reports it.
|
|
7423
|
+
//
|
|
7366
7424
|
// Works on Bounded-served origins (<app>.bounded.page / custom domains). On a
|
|
7367
7425
|
// local dev origin the session endpoint does not exist; we fail with a clear
|
|
7368
7426
|
// error rather than guessing a host.
|
|
7369
7427
|
function hasDOM() {
|
|
7370
7428
|
return typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
7371
7429
|
}
|
|
7430
|
+
async function authedFetch(path, init) {
|
|
7431
|
+
const idToken = await getIdToken();
|
|
7432
|
+
if (!idToken)
|
|
7433
|
+
throw new Error('onramp: no active session - call login() first');
|
|
7434
|
+
return fetch(`${window.location.origin}${path}`, Object.assign(Object.assign({}, init), { headers: Object.assign(Object.assign({}, init === null || init === void 0 ? void 0 : init.headers), { Authorization: `Bearer ${idToken}` }) }));
|
|
7435
|
+
}
|
|
7436
|
+
async function readError(res) {
|
|
7437
|
+
var _a;
|
|
7438
|
+
try {
|
|
7439
|
+
return (_a = (await res.json()).error) !== null && _a !== void 0 ? _a : '';
|
|
7440
|
+
}
|
|
7441
|
+
catch (_b) {
|
|
7442
|
+
return '';
|
|
7443
|
+
}
|
|
7444
|
+
}
|
|
7445
|
+
function sessionBody(options, extra) {
|
|
7446
|
+
return JSON.stringify(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (options.asset ? { asset: options.asset } : {})), (options.address ? { address: options.address } : {})), (options.amountUsd !== undefined ? { amountUsd: options.amountUsd } : {})), (options.minAmountOut !== undefined ? { minAmountOut: options.minAmountOut } : {})), (options.slippagePad !== undefined ? { slippagePad: options.slippagePad } : {})), extra));
|
|
7447
|
+
}
|
|
7448
|
+
function resolveAddress(options) {
|
|
7449
|
+
var _a, _b;
|
|
7450
|
+
const user = getCurrentUser();
|
|
7451
|
+
const address = (_b = (_a = options.address) !== null && _a !== void 0 ? _a : user === null || user === void 0 ? void 0 : user.address) !== null && _b !== void 0 ? _b : undefined;
|
|
7452
|
+
if (!address) {
|
|
7453
|
+
throw new Error(user
|
|
7454
|
+
? 'onramp: the signed-in account has no wallet address - pass { address } explicitly'
|
|
7455
|
+
: 'onramp: no signed-in user - call login() first or pass { address }');
|
|
7456
|
+
}
|
|
7457
|
+
return address;
|
|
7458
|
+
}
|
|
7372
7459
|
/**
|
|
7373
|
-
*
|
|
7460
|
+
* Preview a quote (fees + exact/floor output) WITHOUT opening any window or
|
|
7461
|
+
* consuming a session. Show this to the user, then call onramp() to check out.
|
|
7462
|
+
*/
|
|
7463
|
+
async function onrampQuote(options = {}) {
|
|
7464
|
+
if (!hasDOM())
|
|
7465
|
+
throw new Error('onrampQuote is web-only');
|
|
7466
|
+
resolveAddress(options);
|
|
7467
|
+
const res = await authedFetch('/__bounded/onramp/session', {
|
|
7468
|
+
method: 'POST',
|
|
7469
|
+
headers: { 'content-type': 'application/json' },
|
|
7470
|
+
body: sessionBody(options, { quoteOnly: true }),
|
|
7471
|
+
});
|
|
7472
|
+
if (!res.ok)
|
|
7473
|
+
throw new Error(`onrampQuote: failed (${res.status}${await readError(res).then((e) => (e ? `: ${e}` : ''))})`);
|
|
7474
|
+
return (await res.json());
|
|
7475
|
+
}
|
|
7476
|
+
/** The signed-in user's recent onramp transactions (newest first). */
|
|
7477
|
+
async function onrampStatus(sinceMs) {
|
|
7478
|
+
if (!hasDOM())
|
|
7479
|
+
throw new Error('onrampStatus is web-only');
|
|
7480
|
+
const res = await authedFetch(`/__bounded/onramp/status${sinceMs ? `?since=${Math.floor(sinceMs)}` : ''}`);
|
|
7481
|
+
if (!res.ok)
|
|
7482
|
+
throw new Error(`onrampStatus: failed (${res.status})`);
|
|
7483
|
+
return (await res.json()).transactions;
|
|
7484
|
+
}
|
|
7485
|
+
function isSuccess(t) {
|
|
7486
|
+
return /SUCCESS|COMPLETED/i.test(t.status);
|
|
7487
|
+
}
|
|
7488
|
+
function isPending(t) {
|
|
7489
|
+
return /PROGRESS|PENDING|CREATED/i.test(t.status);
|
|
7490
|
+
}
|
|
7491
|
+
async function verifyCompletion(openedAt, asset, timeoutMs) {
|
|
7492
|
+
const deadline = Date.now() + timeoutMs;
|
|
7493
|
+
// 60s of clock-skew slack on `since`: Coinbase stamps server-side.
|
|
7494
|
+
const since = openedAt - 60000;
|
|
7495
|
+
for (;;) {
|
|
7496
|
+
let sawPending = false;
|
|
7497
|
+
try {
|
|
7498
|
+
const txs = await onrampStatus(since);
|
|
7499
|
+
const done = txs.find((t) => isSuccess(t) && (t.asset === null || t.asset === asset));
|
|
7500
|
+
if (done)
|
|
7501
|
+
return done;
|
|
7502
|
+
sawPending = txs.some(isPending);
|
|
7503
|
+
}
|
|
7504
|
+
catch ( /* transient - keep polling until the deadline */_a) { /* transient - keep polling until the deadline */ }
|
|
7505
|
+
// No completed fill and nothing in flight: one grace poll cycle still
|
|
7506
|
+
// runs (Coinbase's record can lag the redirect), but don't burn the
|
|
7507
|
+
// full window when the user plainly abandoned checkout.
|
|
7508
|
+
if (Date.now() >= deadline)
|
|
7509
|
+
return null;
|
|
7510
|
+
if (!sawPending && Date.now() >= openedAt + 12000 && Date.now() - openedAt > timeoutMs / 2)
|
|
7511
|
+
return null;
|
|
7512
|
+
await new Promise((r) => setTimeout(r, 3000));
|
|
7513
|
+
}
|
|
7514
|
+
}
|
|
7515
|
+
/**
|
|
7516
|
+
* Open Coinbase Onramp for the signed-in user. Resolves after the window
|
|
7517
|
+
* closes, with completion VERIFIED against Coinbase when possible.
|
|
7374
7518
|
* Call from a click handler - popup blockers require user activation.
|
|
7375
7519
|
*/
|
|
7376
7520
|
async function onramp(options = {}) {
|
|
7377
|
-
var _a
|
|
7521
|
+
var _a;
|
|
7378
7522
|
if (!hasDOM())
|
|
7379
7523
|
throw new Error('onramp() is web-only');
|
|
7380
|
-
|
|
7381
|
-
const address = (_b = (_a = options.address) !== null && _a !== void 0 ? _a : user === null || user === void 0 ? void 0 : user.address) !== null && _b !== void 0 ? _b : undefined;
|
|
7382
|
-
if (!address) {
|
|
7383
|
-
throw new Error(user
|
|
7384
|
-
? 'onramp(): the signed-in account has no wallet address - pass { address } explicitly'
|
|
7385
|
-
: 'onramp(): no signed-in user - call login() first or pass { address }');
|
|
7386
|
-
}
|
|
7387
|
-
const idToken = await getIdToken();
|
|
7388
|
-
if (!idToken)
|
|
7389
|
-
throw new Error('onramp(): no active session - call login() first');
|
|
7524
|
+
resolveAddress(options);
|
|
7390
7525
|
// Open the window synchronously so the click's user-activation window is not
|
|
7391
7526
|
// consumed by the fetch below (same hard-won pattern as loginWithPopup).
|
|
7392
7527
|
let popup = null;
|
|
@@ -7399,21 +7534,17 @@ async function onramp(options = {}) {
|
|
|
7399
7534
|
}
|
|
7400
7535
|
let session;
|
|
7401
7536
|
try {
|
|
7402
|
-
const res = await
|
|
7537
|
+
const res = await authedFetch('/__bounded/onramp/session', {
|
|
7403
7538
|
method: 'POST',
|
|
7404
|
-
headers: {
|
|
7405
|
-
body:
|
|
7539
|
+
headers: { 'content-type': 'application/json' },
|
|
7540
|
+
body: sessionBody(options),
|
|
7406
7541
|
});
|
|
7407
7542
|
if (!res.ok) {
|
|
7408
|
-
|
|
7409
|
-
try {
|
|
7410
|
-
detail = (_c = (await res.json()).error) !== null && _c !== void 0 ? _c : '';
|
|
7411
|
-
}
|
|
7412
|
-
catch ( /* keep status only */_d) { /* keep status only */ }
|
|
7543
|
+
const detail = await readError(res);
|
|
7413
7544
|
if (res.status === 404) {
|
|
7414
|
-
throw new Error('onramp
|
|
7545
|
+
throw new Error('onramp: session endpoint not found - onramp works on Bounded-served origins (your deployed app URL), not local dev servers');
|
|
7415
7546
|
}
|
|
7416
|
-
throw new Error(`onramp
|
|
7547
|
+
throw new Error(`onramp: session mint failed (${res.status}${detail ? `: ${detail}` : ''})`);
|
|
7417
7548
|
}
|
|
7418
7549
|
session = (await res.json());
|
|
7419
7550
|
}
|
|
@@ -7421,40 +7552,47 @@ async function onramp(options = {}) {
|
|
|
7421
7552
|
try {
|
|
7422
7553
|
popup === null || popup === void 0 ? void 0 : popup.close();
|
|
7423
7554
|
}
|
|
7424
|
-
catch ( /* ignore */
|
|
7555
|
+
catch ( /* ignore */_b) { /* ignore */ }
|
|
7425
7556
|
throw error;
|
|
7426
7557
|
}
|
|
7558
|
+
const openedAt = Date.now();
|
|
7559
|
+
const base = Object.assign({ address: session.address, asset: session.asset }, (session.quote ? { quote: session.quote } : {}));
|
|
7427
7560
|
if (popup) {
|
|
7428
7561
|
try {
|
|
7429
7562
|
popup.location.replace(session.url);
|
|
7430
7563
|
}
|
|
7431
|
-
catch (
|
|
7564
|
+
catch (_c) {
|
|
7432
7565
|
try {
|
|
7433
7566
|
popup.location.href = session.url;
|
|
7434
7567
|
}
|
|
7435
|
-
catch (
|
|
7568
|
+
catch (_d) {
|
|
7436
7569
|
try {
|
|
7437
7570
|
popup.close();
|
|
7438
7571
|
}
|
|
7439
|
-
catch ( /* ignore */
|
|
7440
|
-
throw new Error('onramp
|
|
7572
|
+
catch ( /* ignore */_e) { /* ignore */ }
|
|
7573
|
+
throw new Error('onramp: popup failed to navigate - retry with { newTab: true }');
|
|
7441
7574
|
}
|
|
7442
7575
|
}
|
|
7443
|
-
|
|
7576
|
+
await new Promise((resolve) => {
|
|
7444
7577
|
const timer = setInterval(() => {
|
|
7445
7578
|
if (popup.closed) {
|
|
7446
7579
|
clearInterval(timer);
|
|
7447
|
-
resolve(
|
|
7580
|
+
resolve();
|
|
7448
7581
|
}
|
|
7449
7582
|
}, 500);
|
|
7450
7583
|
});
|
|
7584
|
+
const fill = await verifyCompletion(openedAt, session.asset, (_a = options.completionTimeoutMs) !== null && _a !== void 0 ? _a : 24000);
|
|
7585
|
+
if (fill) {
|
|
7586
|
+
return Object.assign(Object.assign(Object.assign(Object.assign({}, base), { status: 'completed' }), (fill.amountOut !== null ? { actualOut: fill.amountOut } : {})), (fill.txHash ? { txHash: fill.txHash } : {}));
|
|
7587
|
+
}
|
|
7588
|
+
return Object.assign(Object.assign({}, base), { status: 'closed' });
|
|
7451
7589
|
}
|
|
7452
7590
|
// New-tab path (popup was blocked or explicitly requested): cross-origin tab
|
|
7453
|
-
// close is not observable, so resolve immediately.
|
|
7591
|
+
// close is not observable, so resolve immediately; verify via onrampStatus().
|
|
7454
7592
|
const tab = window.open(session.url, '_blank');
|
|
7455
7593
|
if (!tab)
|
|
7456
|
-
throw new Error('onramp
|
|
7457
|
-
return { status: 'opened'
|
|
7594
|
+
throw new Error('onramp: window.open was blocked - call onramp() from a click handler');
|
|
7595
|
+
return Object.assign(Object.assign({}, base), { status: 'opened' });
|
|
7458
7596
|
}
|
|
7459
7597
|
|
|
7460
7598
|
/**
|
|
@@ -7925,5 +8063,5 @@ function defaultInjectedEvmProvider() {
|
|
|
7925
8063
|
return null;
|
|
7926
8064
|
}
|
|
7927
8065
|
|
|
7928
|
-
export {
|
|
7929
|
-
//# sourceMappingURL=index-
|
|
8066
|
+
export { FAILURE_REASONS as $, completeLoginFromRedirect as A, loginWithPopup as B, completeLoginInPopup as C, openBoundedWidget as D, EMBEDDED_WALLET_UNSUPPORTED as E, useAuth as F, useQuery as G, useBuildRun as H, apps as I, deserializeTransaction as J, signSolanaMessageViaTurnkey as K, getOrCreateTurnkeyWallet as L, startTurnkeyEmailLogin as M, getIdToken as N, onramp as O, onrampQuote as P, onrampStatus as Q, setPlatform as R, OffchainAuthProvider as S, PrivyExpoProvider as T, requestEip6963Providers as U, builds as V, BuildsApiError as W, NON_TERMINAL_STATES as X, TERMINAL_STATES as Y, RUN_STATES as Z, PARK_REASONS as _, hasEmbeddedEvmWallet as a, BUILD_REVIEW_CAPABILITY_SCHEMA as a0, BUILD_REVIEW_CAPABILITY_REFRESH_SCHEMA as a1, BUILD_DELEGATED_REVIEW_CAPABILITY_SCHEMA as a2, embeddedSignAndSubmit as b, setAuthLoading as c, defaultInjectedProvider as d, embeddedRunEvmTransaction as e, bufferExports as f, getPlatform as g, hasEmbeddedWallet as h, bs58 as i, confirmAndCheckTransaction as j, defaultInjectedEvmProvider as k, init as l, getCurrentUser as m, normalizeSolanaRpcUrl as n, onAuthStateChanged as o, onAuthLoadingChanged as p, getAuthLoading as q, resolveSolanaRpcUrl as r, setCurrentUser as s, login as t, logout as u, getAuthProvider as v, signInAnonymously as w, loginWithPrivy as x, loginWithWallet as y, loginWithRedirect as z };
|
|
8067
|
+
//# sourceMappingURL=index-L2R6C5Vl.mjs.map
|