@bounded-sh/client 0.0.32 → 0.0.34
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/REACT_NATIVE.md +3 -3
- package/dist/auth/index.d.ts +1 -40
- package/dist/auth/oidc-auth.d.ts +2 -16
- package/dist/auth/providers/email-auth-provider.d.ts +0 -34
- package/dist/index.d.ts +2 -2
- package/dist/index.js +8 -572
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +10 -568
- package/dist/index.mjs.map +1 -1
- package/dist/index.native.d.ts +2 -2
- package/dist/index.native.js +8 -572
- package/dist/index.native.js.map +1 -1
- package/dist/index.native.mjs +10 -568
- package/dist/index.native.mjs.map +1 -1
- package/package.json +5 -3
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getActiveSessionManager, genAuthNonce, genSolanaMessage, createSessionWithSignature, getConfig,
|
|
1
|
+
import { getActiveSessionManager, genAuthNonce, genSolanaMessage, createSessionWithSignature, getConfig, WebSessionManager, ReactNativeSessionManager, revokeSession, init as init$1, reconnectWithNewAuth, deriveUserIdentityFromIdToken, subscribe, getIdToken as getIdToken$1, convertRemainingAccounts, buildSetDocumentsTransaction } from '@bounded-sh/core';
|
|
2
2
|
export * from '@bounded-sh/core';
|
|
3
3
|
export { aggregate, count, docId, get, getConfig, getFiles, getMany, queryAggregate, runExpression, runExpressionMany, runQuery, runQueryMany, search, set, setFile, setMany, signAndSubmitTransaction, signMessage, signTransaction, subscribe } from '@bounded-sh/core';
|
|
4
4
|
import * as React from 'react';
|
|
@@ -3578,7 +3578,7 @@ class GuestAuthProvider {
|
|
|
3578
3578
|
// ReactNativeSessionManager. getActiveSessionManager() picks the right one by
|
|
3579
3579
|
// whether the RN manager was configured (NOT `typeof window`, which is truthy on
|
|
3580
3580
|
// RN too and would wrongly route to localStorage). Same selector the core
|
|
3581
|
-
// request path uses, so
|
|
3581
|
+
// request path uses, so hosted Bounded Auth sessions persist + authenticate on BOTH.
|
|
3582
3582
|
const sessionManager$1 = getActiveSessionManager;
|
|
3583
3583
|
const NO_WALLET = 'Email login is offchain — it has no Solana wallet and cannot sign/submit ' +
|
|
3584
3584
|
'transactions. Use a wallet provider for onchain actions, or link a wallet later.';
|
|
@@ -3607,191 +3607,13 @@ function userFromIdToken$1(idToken, fallbackEmail) {
|
|
|
3607
3607
|
// Email logins have no wallet — address is null (the User type allows it).
|
|
3608
3608
|
return { id, address: (c['custom:walletAddress'] || null), email, provider: emailProviderSingleton };
|
|
3609
3609
|
}
|
|
3610
|
-
async function humanAuthBase() {
|
|
3611
|
-
const cfg = await getConfig();
|
|
3612
|
-
const base = cfg.humanAuthApiUrl || 'https://auth.bounded.sh';
|
|
3613
|
-
return base.replace(/\/$/, '');
|
|
3614
|
-
}
|
|
3615
|
-
async function post(path, body) {
|
|
3616
|
-
const base = await humanAuthBase();
|
|
3617
|
-
let res;
|
|
3618
|
-
try {
|
|
3619
|
-
// Credential-free + no custom header: /email and /verify are open-CORS
|
|
3620
|
-
// (ACAO:*) public OTP routes, so this works inline from ANY app origin (no
|
|
3621
|
-
// popup, no redirect). The OTP is the body secret; the token returns in the
|
|
3622
|
-
// body. Adding credentials or a custom header would break the open-CORS
|
|
3623
|
-
// preflight — keep this a simple JSON POST.
|
|
3624
|
-
res = await fetch(base + path, {
|
|
3625
|
-
method: 'POST',
|
|
3626
|
-
headers: { 'content-type': 'application/json' },
|
|
3627
|
-
body: JSON.stringify(body),
|
|
3628
|
-
});
|
|
3629
|
-
}
|
|
3630
|
-
catch (err) {
|
|
3631
|
-
throw new Error(`Bounded auth request to ${path} failed: ${(err === null || err === void 0 ? void 0 : err.message) || err}`);
|
|
3632
|
-
}
|
|
3633
|
-
let data = null;
|
|
3634
|
-
try {
|
|
3635
|
-
data = await res.json();
|
|
3636
|
-
}
|
|
3637
|
-
catch ( /* non-JSON */_a) { /* non-JSON */ }
|
|
3638
|
-
if (!res.ok) {
|
|
3639
|
-
const msg = (data && (data.error || data.message)) || `HTTP ${res.status}`;
|
|
3640
|
-
throw new Error(String(msg));
|
|
3641
|
-
}
|
|
3642
|
-
return data || {};
|
|
3643
|
-
}
|
|
3644
|
-
// ---------------------------------------------------------------------------
|
|
3645
|
-
// headless primitives (used by the modal AND exported for custom UIs)
|
|
3646
|
-
// ---------------------------------------------------------------------------
|
|
3647
|
-
function normalizePhoneNumber(value) {
|
|
3648
|
-
const compact = String(value || '').trim().replace(/[()\s.-]/g, '');
|
|
3649
|
-
return compact.startsWith('00') ? `+${compact.slice(2)}` : compact;
|
|
3650
|
-
}
|
|
3651
|
-
function assertPhoneNumber(value) {
|
|
3652
|
-
const phoneNumber = normalizePhoneNumber(value);
|
|
3653
|
-
if (!/^\+[1-9]\d{7,14}$/.test(phoneNumber)) {
|
|
3654
|
-
throw new Error('phoneNumber must be in E.164 format, e.g. +14155550132');
|
|
3655
|
-
}
|
|
3656
|
-
return phoneNumber;
|
|
3657
|
-
}
|
|
3658
|
-
/** Send a login code to `email`. Step 1 of the inline email-OTP flow. */
|
|
3659
|
-
async function sendEmailOtp$1(email) {
|
|
3660
|
-
const cfg = await getConfig();
|
|
3661
|
-
const e = (email || '').trim().toLowerCase();
|
|
3662
|
-
if (!e)
|
|
3663
|
-
throw new Error('email is required');
|
|
3664
|
-
const data = await post('/email', { email: e, appId: cfg.appId });
|
|
3665
|
-
return { ok: true, expiresInSeconds: data === null || data === void 0 ? void 0 : data.expiresInSeconds };
|
|
3666
|
-
}
|
|
3667
|
-
/** Send a login code by text message. Requires the Bounded issuer to have text OTP explicitly enabled and SMS configured. */
|
|
3668
|
-
async function sendTextOtp$1(phoneNumber) {
|
|
3669
|
-
const cfg = await getConfig();
|
|
3670
|
-
const phone = assertPhoneNumber(phoneNumber);
|
|
3671
|
-
const data = await post('/text', { phoneNumber: phone, appId: cfg.appId });
|
|
3672
|
-
return { ok: true, expiresInSeconds: data === null || data === void 0 ? void 0 : data.expiresInSeconds };
|
|
3673
|
-
}
|
|
3674
|
-
/**
|
|
3675
|
-
* Verify the code for `email` and establish the session. Step 2 of the flow.
|
|
3676
|
-
* Stores the Bounded id token (the realtime bearer) and sets the current user.
|
|
3677
|
-
*/
|
|
3678
|
-
async function verifyEmailOtp$1(email, otp) {
|
|
3679
|
-
setAuthLoading(true);
|
|
3680
|
-
try {
|
|
3681
|
-
const cfg = await getConfig();
|
|
3682
|
-
const e = (email || '').trim().toLowerCase();
|
|
3683
|
-
const code = (otp || '').trim();
|
|
3684
|
-
if (!e || !code)
|
|
3685
|
-
throw new Error('email and code are required');
|
|
3686
|
-
const data = await post('/verify', { email: e, appId: cfg.appId, otp: code });
|
|
3687
|
-
const idToken = data === null || data === void 0 ? void 0 : data.idToken;
|
|
3688
|
-
if (!idToken)
|
|
3689
|
-
throw new Error('No token returned from verification.');
|
|
3690
|
-
const user = userFromIdToken$1(idToken, e);
|
|
3691
|
-
// Store the idToken as BOTH id + access (it is the JWT the realtime worker
|
|
3692
|
-
// verifies and carries `exp`, so the session-manager expiry check works).
|
|
3693
|
-
// address is "" for email (no wallet); the realtime bearer is the idToken.
|
|
3694
|
-
// Persist the rotating refresh token + the issuer base (humanAuthApiUrl) so the
|
|
3695
|
-
// session manager can silently renew via {issuer}/session/refresh — sessions now
|
|
3696
|
-
// live as long as the 30d refresh token instead of dying at the access TTL.
|
|
3697
|
-
const refreshToken = typeof (data === null || data === void 0 ? void 0 : data.refreshToken) === 'string' ? data.refreshToken : '';
|
|
3698
|
-
const issuer = (cfg.humanAuthApiUrl || '').replace(/\/$/, '');
|
|
3699
|
-
await sessionManager$1().storeSession(String(user.address || ''), idToken, idToken, refreshToken, issuer);
|
|
3700
|
-
setCurrentUser(user);
|
|
3701
|
-
return user;
|
|
3702
|
-
}
|
|
3703
|
-
finally {
|
|
3704
|
-
setAuthLoading(false);
|
|
3705
|
-
}
|
|
3706
|
-
}
|
|
3707
|
-
/**
|
|
3708
|
-
* Verify the text-message code for `phoneNumber` and establish the session.
|
|
3709
|
-
* Phone-only users have `user.email === null`; use `user.id` for ownership.
|
|
3710
|
-
*/
|
|
3711
|
-
async function verifyTextOtp$1(phoneNumber, otp) {
|
|
3712
|
-
setAuthLoading(true);
|
|
3713
|
-
try {
|
|
3714
|
-
const cfg = await getConfig();
|
|
3715
|
-
const phone = assertPhoneNumber(phoneNumber);
|
|
3716
|
-
const code = (otp || '').trim();
|
|
3717
|
-
if (!code)
|
|
3718
|
-
throw new Error('code is required');
|
|
3719
|
-
const data = await post('/text/verify', { phoneNumber: phone, appId: cfg.appId, otp: code });
|
|
3720
|
-
const idToken = data === null || data === void 0 ? void 0 : data.idToken;
|
|
3721
|
-
if (!idToken)
|
|
3722
|
-
throw new Error('No token returned from verification.');
|
|
3723
|
-
const user = userFromIdToken$1(idToken);
|
|
3724
|
-
const refreshToken = typeof (data === null || data === void 0 ? void 0 : data.refreshToken) === 'string' ? data.refreshToken : '';
|
|
3725
|
-
const issuer = (cfg.humanAuthApiUrl || '').replace(/\/$/, '');
|
|
3726
|
-
await sessionManager$1().storeSession(String(user.address || ''), idToken, idToken, refreshToken, issuer);
|
|
3727
|
-
setCurrentUser(user);
|
|
3728
|
-
return user;
|
|
3729
|
-
}
|
|
3730
|
-
finally {
|
|
3731
|
-
setAuthLoading(false);
|
|
3732
|
-
}
|
|
3733
|
-
}
|
|
3734
|
-
/**
|
|
3735
|
-
* UPGRADE an anonymous (guest) session by LINKING an email credential — Firebase
|
|
3736
|
-
* `linkWithCredential` parity. The guest's `guestToken` is sent to the auth issuer
|
|
3737
|
-
* which, IF the email is brand-new, makes the new account ADOPT the guest's id so
|
|
3738
|
-
* `@user.id` is preserved and the guest's data carries over. If the email already
|
|
3739
|
-
* exists, the user just signs into it (stays separate; `linked:false`). On success
|
|
3740
|
-
* the upgraded session replaces the guest session and the user is no longer
|
|
3741
|
-
* anonymous. `guestToken` is captured by the caller BEFORE switching auth methods.
|
|
3742
|
-
*/
|
|
3743
|
-
async function linkEmailWithGuest(email, otp, guestToken) {
|
|
3744
|
-
var _a;
|
|
3745
|
-
setAuthLoading(true);
|
|
3746
|
-
try {
|
|
3747
|
-
const cfg = await getConfig();
|
|
3748
|
-
const e = (email || '').trim().toLowerCase();
|
|
3749
|
-
const code = (otp || '').trim();
|
|
3750
|
-
if (!e || !code)
|
|
3751
|
-
throw new Error('email and code are required');
|
|
3752
|
-
if (!guestToken)
|
|
3753
|
-
throw new Error('an active anonymous session is required to link an email');
|
|
3754
|
-
// Capture the OLD guest session's refresh token + issuer BEFORE it's overwritten,
|
|
3755
|
-
// so we can revoke the guest refresh family after the upgrade. Otherwise a stolen
|
|
3756
|
-
// guest refresh token would keep minting access to the now-upgraded identity.
|
|
3757
|
-
const oldRefreshToken = sessionManager$1().getRefreshToken();
|
|
3758
|
-
const oldIssuer = (_a = sessionManager$1().getIssuer()) !== null && _a !== void 0 ? _a : undefined;
|
|
3759
|
-
const data = await post('/link/email', { email: e, appId: cfg.appId, otp: code, guestToken });
|
|
3760
|
-
const idToken = data === null || data === void 0 ? void 0 : data.idToken;
|
|
3761
|
-
if (!idToken)
|
|
3762
|
-
throw new Error('No token returned from link.');
|
|
3763
|
-
const user = userFromIdToken$1(idToken, e);
|
|
3764
|
-
// Persist the REAL rotating refresh token + human issuer so the upgraded session
|
|
3765
|
-
// silently renews (was previously stored as '' -> upgraded users couldn't refresh).
|
|
3766
|
-
const refreshToken = typeof (data === null || data === void 0 ? void 0 : data.refreshToken) === 'string' ? data.refreshToken : '';
|
|
3767
|
-
const issuer = (cfg.humanAuthApiUrl || '').replace(/\/$/, '');
|
|
3768
|
-
await sessionManager$1().storeSession(String(user.address || ''), idToken, idToken, refreshToken, issuer);
|
|
3769
|
-
setCurrentUser(user);
|
|
3770
|
-
// Best-effort revoke of the old guest refresh family (upgrade is already committed;
|
|
3771
|
-
// a revoke failure must not break the new session).
|
|
3772
|
-
if (oldRefreshToken && oldRefreshToken !== refreshToken) {
|
|
3773
|
-
try {
|
|
3774
|
-
await revokeSession(oldRefreshToken, oldIssuer);
|
|
3775
|
-
}
|
|
3776
|
-
catch ( /* best-effort */_b) { /* best-effort */ }
|
|
3777
|
-
}
|
|
3778
|
-
return { user, linked: !!(data === null || data === void 0 ? void 0 : data.linked), isNewAccount: !!(data === null || data === void 0 ? void 0 : data.isNewAccount) };
|
|
3779
|
-
}
|
|
3780
|
-
finally {
|
|
3781
|
-
setAuthLoading(false);
|
|
3782
|
-
}
|
|
3783
|
-
}
|
|
3784
3610
|
// ---------------------------------------------------------------------------
|
|
3785
3611
|
// provider
|
|
3786
3612
|
// ---------------------------------------------------------------------------
|
|
3787
3613
|
class EmailAuthProvider {
|
|
3788
3614
|
async login() {
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
"sendEmailOtp(email) then verifyEmailOtp(email, code), or, when text OTP is enabled, " +
|
|
3792
|
-
"sendTextOtp(phone) then verifyTextOtp(phone, code). Render your own OTP inputs. The built-in modal is web-only.");
|
|
3793
|
-
}
|
|
3794
|
-
return openEmailModal();
|
|
3615
|
+
throw new Error('login() no longer opens inline email OTP. Use loginWithRedirect({ redirectUri }) ' +
|
|
3616
|
+
'or loginWithPopup({ redirectUri }) for hosted Bounded Auth.');
|
|
3795
3617
|
}
|
|
3796
3618
|
async restoreSession() {
|
|
3797
3619
|
const sm = sessionManager$1();
|
|
@@ -3816,283 +3638,6 @@ class EmailAuthProvider {
|
|
|
3816
3638
|
async getNativeMethods() { return {}; }
|
|
3817
3639
|
}
|
|
3818
3640
|
const emailProviderSingleton = new EmailAuthProvider();
|
|
3819
|
-
// ---------------------------------------------------------------------------
|
|
3820
|
-
// inline modal (web only) — mobile-first, no popup, no redirect
|
|
3821
|
-
// ---------------------------------------------------------------------------
|
|
3822
|
-
function openEmailModal() {
|
|
3823
|
-
return new Promise((resolve) => {
|
|
3824
|
-
var _a;
|
|
3825
|
-
const root = createEmailModalTree();
|
|
3826
|
-
const style = document.createElement('style');
|
|
3827
|
-
style.textContent = MODAL_CSS;
|
|
3828
|
-
root.appendChild(style);
|
|
3829
|
-
document.body.appendChild(root);
|
|
3830
|
-
const $ = (id) => root.querySelector('#' + id);
|
|
3831
|
-
const emailStep = $('ba-email-step');
|
|
3832
|
-
const otpStep = $('ba-otp-step');
|
|
3833
|
-
const emailInput = $('ba-email');
|
|
3834
|
-
const otpInput = $('ba-otp');
|
|
3835
|
-
const sentTo = $('ba-sent-to');
|
|
3836
|
-
const msg = $('ba-msg');
|
|
3837
|
-
const emailBtn = $('ba-email-btn');
|
|
3838
|
-
const otpBtn = $('ba-otp-btn');
|
|
3839
|
-
let email = '';
|
|
3840
|
-
let done = false;
|
|
3841
|
-
const setMsg = (t, err = false) => { msg.textContent = t; msg.className = 'ba-msg' + (err ? ' err' : ''); };
|
|
3842
|
-
const close = (user) => {
|
|
3843
|
-
var _a;
|
|
3844
|
-
if (done)
|
|
3845
|
-
return;
|
|
3846
|
-
done = true;
|
|
3847
|
-
document.removeEventListener('keydown', onEsc);
|
|
3848
|
-
(_a = root.querySelector('.ba-overlay')) === null || _a === void 0 ? void 0 : _a.classList.add('out');
|
|
3849
|
-
setTimeout(() => root.remove(), 160);
|
|
3850
|
-
resolve(user);
|
|
3851
|
-
};
|
|
3852
|
-
const onEsc = (e) => { if (e.key === 'Escape')
|
|
3853
|
-
close(null); };
|
|
3854
|
-
document.addEventListener('keydown', onEsc);
|
|
3855
|
-
(_a = root.querySelector('.ba-overlay')) === null || _a === void 0 ? void 0 : _a.addEventListener('click', (e) => {
|
|
3856
|
-
if (e.target.classList.contains('ba-overlay'))
|
|
3857
|
-
close(null);
|
|
3858
|
-
});
|
|
3859
|
-
$('ba-close').addEventListener('click', () => close(null));
|
|
3860
|
-
requestAnimationFrame(() => emailInput.focus());
|
|
3861
|
-
emailBtn.addEventListener('click', async () => {
|
|
3862
|
-
email = emailInput.value.trim();
|
|
3863
|
-
if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email)) {
|
|
3864
|
-
setMsg('Enter a valid email.', true);
|
|
3865
|
-
return;
|
|
3866
|
-
}
|
|
3867
|
-
emailBtn.disabled = true;
|
|
3868
|
-
setMsg('Sending code…');
|
|
3869
|
-
try {
|
|
3870
|
-
await sendEmailOtp$1(email);
|
|
3871
|
-
sentTo.textContent = email;
|
|
3872
|
-
emailStep.classList.add('hidden');
|
|
3873
|
-
otpStep.classList.remove('hidden');
|
|
3874
|
-
setMsg('');
|
|
3875
|
-
otpInput.focus();
|
|
3876
|
-
}
|
|
3877
|
-
catch (err) {
|
|
3878
|
-
setMsg((err === null || err === void 0 ? void 0 : err.message) || 'Could not send the code.', true);
|
|
3879
|
-
}
|
|
3880
|
-
finally {
|
|
3881
|
-
emailBtn.disabled = false;
|
|
3882
|
-
}
|
|
3883
|
-
});
|
|
3884
|
-
emailInput.addEventListener('keydown', (e) => { if (e.key === 'Enter')
|
|
3885
|
-
emailBtn.click(); });
|
|
3886
|
-
otpBtn.addEventListener('click', async () => {
|
|
3887
|
-
const code = otpInput.value.trim();
|
|
3888
|
-
if (!/^\d{4,8}$/.test(code)) {
|
|
3889
|
-
setMsg('Enter the code from your email.', true);
|
|
3890
|
-
return;
|
|
3891
|
-
}
|
|
3892
|
-
otpBtn.disabled = true;
|
|
3893
|
-
setMsg('Verifying…');
|
|
3894
|
-
try {
|
|
3895
|
-
const user = await verifyEmailOtp$1(email, code);
|
|
3896
|
-
close(user);
|
|
3897
|
-
}
|
|
3898
|
-
catch (err) {
|
|
3899
|
-
setMsg((err === null || err === void 0 ? void 0 : err.message) || 'That code did not work.', true);
|
|
3900
|
-
otpBtn.disabled = false;
|
|
3901
|
-
}
|
|
3902
|
-
});
|
|
3903
|
-
otpInput.addEventListener('keydown', (e) => { if (e.key === 'Enter')
|
|
3904
|
-
otpBtn.click(); });
|
|
3905
|
-
$('ba-back').addEventListener('click', () => {
|
|
3906
|
-
otpStep.classList.add('hidden');
|
|
3907
|
-
emailStep.classList.remove('hidden');
|
|
3908
|
-
setMsg('');
|
|
3909
|
-
emailInput.focus();
|
|
3910
|
-
});
|
|
3911
|
-
});
|
|
3912
|
-
}
|
|
3913
|
-
function createEmailModalTree() {
|
|
3914
|
-
const root = document.createElement('div');
|
|
3915
|
-
root.id = 'bounded-auth-modal';
|
|
3916
|
-
const overlay = document.createElement('div');
|
|
3917
|
-
overlay.className = 'ba-overlay';
|
|
3918
|
-
root.appendChild(overlay);
|
|
3919
|
-
const card = document.createElement('div');
|
|
3920
|
-
card.className = 'ba-card';
|
|
3921
|
-
card.setAttribute('role', 'dialog');
|
|
3922
|
-
card.setAttribute('aria-modal', 'true');
|
|
3923
|
-
card.setAttribute('aria-label', 'Sign in');
|
|
3924
|
-
overlay.appendChild(card);
|
|
3925
|
-
const close = document.createElement('button');
|
|
3926
|
-
close.id = 'ba-close';
|
|
3927
|
-
close.className = 'ba-x';
|
|
3928
|
-
close.setAttribute('aria-label', 'Close');
|
|
3929
|
-
close.type = 'button';
|
|
3930
|
-
close.textContent = '×';
|
|
3931
|
-
card.appendChild(close);
|
|
3932
|
-
// Brand row — the real Bounded mark (same geometry as bounded.sh) + wordmark.
|
|
3933
|
-
const brand = document.createElement('div');
|
|
3934
|
-
brand.className = 'ba-brand';
|
|
3935
|
-
const mark = document.createElement('span');
|
|
3936
|
-
mark.className = 'ba-mark';
|
|
3937
|
-
mark.setAttribute('aria-hidden', 'true');
|
|
3938
|
-
const svgNs = 'http://www.w3.org/2000/svg';
|
|
3939
|
-
const markSvg = document.createElementNS(svgNs, 'svg');
|
|
3940
|
-
markSvg.setAttribute('width', '24');
|
|
3941
|
-
markSvg.setAttribute('height', '24');
|
|
3942
|
-
markSvg.setAttribute('viewBox', '0 0 32 32');
|
|
3943
|
-
markSvg.setAttribute('fill', 'none');
|
|
3944
|
-
for (const [className, d] of [
|
|
3945
|
-
['ba-c ba-c1', 'M16 5 H5 V16'],
|
|
3946
|
-
['ba-c ba-c2', 'M16 5 H27 V16'],
|
|
3947
|
-
['ba-c ba-c3', 'M5 16 V27 H16'],
|
|
3948
|
-
['ba-c ba-c4', 'M27 16 V27 H16'],
|
|
3949
|
-
]) {
|
|
3950
|
-
const path = document.createElementNS(svgNs, 'path');
|
|
3951
|
-
path.setAttribute('class', className);
|
|
3952
|
-
path.setAttribute('d', d);
|
|
3953
|
-
markSvg.appendChild(path);
|
|
3954
|
-
}
|
|
3955
|
-
mark.appendChild(markSvg);
|
|
3956
|
-
brand.appendChild(mark);
|
|
3957
|
-
const word = document.createElement('span');
|
|
3958
|
-
word.className = 'ba-word';
|
|
3959
|
-
word.textContent = 'bounded';
|
|
3960
|
-
brand.appendChild(word);
|
|
3961
|
-
card.appendChild(brand);
|
|
3962
|
-
const title = document.createElement('h1');
|
|
3963
|
-
title.className = 'ba-title';
|
|
3964
|
-
title.textContent = 'Sign in';
|
|
3965
|
-
card.appendChild(title);
|
|
3966
|
-
const sub = document.createElement('p');
|
|
3967
|
-
sub.className = 'ba-subtitle';
|
|
3968
|
-
sub.textContent = 'Continue with your email — no wallet needed.';
|
|
3969
|
-
card.appendChild(sub);
|
|
3970
|
-
const emailStep = document.createElement('div');
|
|
3971
|
-
emailStep.id = 'ba-email-step';
|
|
3972
|
-
card.appendChild(emailStep);
|
|
3973
|
-
const emailLabel = document.createElement('label');
|
|
3974
|
-
emailLabel.className = 'ba-label';
|
|
3975
|
-
emailLabel.htmlFor = 'ba-email';
|
|
3976
|
-
emailLabel.textContent = 'Email';
|
|
3977
|
-
emailStep.appendChild(emailLabel);
|
|
3978
|
-
const emailInput = document.createElement('input');
|
|
3979
|
-
emailInput.id = 'ba-email';
|
|
3980
|
-
emailInput.className = 'ba-input';
|
|
3981
|
-
emailInput.type = 'email';
|
|
3982
|
-
emailInput.inputMode = 'email';
|
|
3983
|
-
emailInput.autocomplete = 'email';
|
|
3984
|
-
emailInput.placeholder = 'you@example.com';
|
|
3985
|
-
emailStep.appendChild(emailInput);
|
|
3986
|
-
const emailButton = document.createElement('button');
|
|
3987
|
-
emailButton.id = 'ba-email-btn';
|
|
3988
|
-
emailButton.className = 'ba-btn';
|
|
3989
|
-
emailButton.type = 'button';
|
|
3990
|
-
emailButton.textContent = 'Continue with email';
|
|
3991
|
-
emailStep.appendChild(emailButton);
|
|
3992
|
-
const otpStep = document.createElement('div');
|
|
3993
|
-
otpStep.id = 'ba-otp-step';
|
|
3994
|
-
otpStep.className = 'hidden';
|
|
3995
|
-
card.appendChild(otpStep);
|
|
3996
|
-
const otpLabel = document.createElement('label');
|
|
3997
|
-
otpLabel.className = 'ba-label';
|
|
3998
|
-
otpLabel.htmlFor = 'ba-otp';
|
|
3999
|
-
otpLabel.appendChild(document.createTextNode('Enter the code sent to '));
|
|
4000
|
-
const sentTo = document.createElement('span');
|
|
4001
|
-
sentTo.id = 'ba-sent-to';
|
|
4002
|
-
sentTo.className = 'ba-em';
|
|
4003
|
-
otpLabel.appendChild(sentTo);
|
|
4004
|
-
otpStep.appendChild(otpLabel);
|
|
4005
|
-
const otpInput = document.createElement('input');
|
|
4006
|
-
otpInput.id = 'ba-otp';
|
|
4007
|
-
otpInput.className = 'ba-input ba-code';
|
|
4008
|
-
otpInput.inputMode = 'numeric';
|
|
4009
|
-
otpInput.autocomplete = 'one-time-code';
|
|
4010
|
-
otpInput.maxLength = 8;
|
|
4011
|
-
otpInput.placeholder = '······';
|
|
4012
|
-
otpStep.appendChild(otpInput);
|
|
4013
|
-
const otpButton = document.createElement('button');
|
|
4014
|
-
otpButton.id = 'ba-otp-btn';
|
|
4015
|
-
otpButton.className = 'ba-btn';
|
|
4016
|
-
otpButton.type = 'button';
|
|
4017
|
-
otpButton.textContent = 'Verify & continue';
|
|
4018
|
-
otpStep.appendChild(otpButton);
|
|
4019
|
-
const backButton = document.createElement('button');
|
|
4020
|
-
backButton.id = 'ba-back';
|
|
4021
|
-
backButton.className = 'ba-link';
|
|
4022
|
-
backButton.type = 'button';
|
|
4023
|
-
backButton.textContent = 'Use a different email';
|
|
4024
|
-
otpStep.appendChild(backButton);
|
|
4025
|
-
const msg = document.createElement('div');
|
|
4026
|
-
msg.id = 'ba-msg';
|
|
4027
|
-
msg.className = 'ba-msg';
|
|
4028
|
-
card.appendChild(msg);
|
|
4029
|
-
const foot = document.createElement('div');
|
|
4030
|
-
foot.className = 'ba-foot';
|
|
4031
|
-
foot.textContent = 'Secured by Bounded';
|
|
4032
|
-
card.appendChild(foot);
|
|
4033
|
-
return root;
|
|
4034
|
-
}
|
|
4035
|
-
// Design language matches the hosted Bounded login (auth.bounded.sh) and bounded.sh:
|
|
4036
|
-
// dark editorial panel, green accent, Schibsted Grotesk / Newsreader / JetBrains Mono,
|
|
4037
|
-
// the Bounded mark drawing itself in. Fonts load best-effort (scoped @import); every
|
|
4038
|
-
// rule has a system fallback so the modal looks right even if Google Fonts is blocked.
|
|
4039
|
-
// All selectors are scoped under #bounded-auth-modal so we never leak into the host page.
|
|
4040
|
-
const MODAL_CSS = `
|
|
4041
|
-
@import url('https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght@6..72,400;6..72,500&family=Schibsted+Grotesk:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap');
|
|
4042
|
-
#bounded-auth-modal{--ba-bg:#0a0a0b;--ba-panel:#0e0f11;--ba-inset:#060607;--ba-raise:#131416;
|
|
4043
|
-
--ba-line:rgba(232,230,222,.08);--ba-line-strong:rgba(232,230,222,.16);
|
|
4044
|
-
--ba-text:#e8e6de;--ba-dim:#9b9991;--ba-faint:#85837c;--ba-green:#58c98f;
|
|
4045
|
-
--ba-green-bg:rgba(88,201,143,.09);--ba-green-line:rgba(88,201,143,.28);--ba-red:#ec8488;
|
|
4046
|
-
--ba-body:'Schibsted Grotesk',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
|
|
4047
|
-
--ba-display:'Newsreader','Iowan Old Style',Georgia,serif;
|
|
4048
|
-
--ba-mono:'JetBrains Mono',ui-monospace,'SF Mono',Menlo,monospace;}
|
|
4049
|
-
#bounded-auth-modal .ba-overlay{position:fixed;inset:0;background:rgba(6,6,7,.66);backdrop-filter:blur(4px);
|
|
4050
|
-
display:flex;align-items:center;justify-content:center;z-index:2147483000;opacity:1;transition:opacity .16s ease;
|
|
4051
|
-
font-family:var(--ba-body);padding:16px;}
|
|
4052
|
-
#bounded-auth-modal .ba-overlay.out{opacity:0;}
|
|
4053
|
-
#bounded-auth-modal *{box-sizing:border-box;}
|
|
4054
|
-
#bounded-auth-modal .ba-card{width:100%;max-width:372px;background:var(--ba-panel);color:var(--ba-text);
|
|
4055
|
-
border:1px solid var(--ba-line);border-radius:12px;padding:28px 28px 22px;position:relative;
|
|
4056
|
-
box-shadow:0 1px 0 rgba(232,230,222,.03) inset,0 30px 80px -40px rgba(0,0,0,.8);animation:ba-in .18s ease;}
|
|
4057
|
-
@keyframes ba-in{from{transform:translateY(8px);opacity:.5}to{transform:translateY(0);opacity:1}}
|
|
4058
|
-
#bounded-auth-modal .ba-x{position:absolute;top:14px;right:14px;width:28px;height:28px;border:1px solid var(--ba-line);
|
|
4059
|
-
background:var(--ba-raise);color:var(--ba-faint);border-radius:7px;font-size:18px;line-height:1;cursor:pointer;
|
|
4060
|
-
transition:color .15s,border-color .15s;}
|
|
4061
|
-
#bounded-auth-modal .ba-x:hover{color:var(--ba-text);border-color:var(--ba-faint);}
|
|
4062
|
-
#bounded-auth-modal .ba-brand{display:flex;align-items:center;gap:10px;margin:0 0 24px;}
|
|
4063
|
-
#bounded-auth-modal .ba-mark{display:flex;color:var(--ba-text);}
|
|
4064
|
-
#bounded-auth-modal .ba-mark svg{overflow:visible;display:block;}
|
|
4065
|
-
#bounded-auth-modal .ba-c{stroke:currentColor;stroke-width:2.4;fill:none;}
|
|
4066
|
-
@media (prefers-reduced-motion:no-preference){
|
|
4067
|
-
#bounded-auth-modal .ba-c{stroke-dasharray:23;stroke-dashoffset:23;animation:ba-draw .4s cubic-bezier(.45,0,.2,1) forwards;}
|
|
4068
|
-
#bounded-auth-modal .ba-c1{animation-delay:.1s}#bounded-auth-modal .ba-c2{animation-delay:.38s}
|
|
4069
|
-
#bounded-auth-modal .ba-c3{animation-delay:.66s}#bounded-auth-modal .ba-c4{animation-delay:.94s}}
|
|
4070
|
-
@keyframes ba-draw{to{stroke-dashoffset:0}}
|
|
4071
|
-
#bounded-auth-modal .ba-word{font-family:var(--ba-body);font-weight:500;font-size:15px;letter-spacing:.2px;color:var(--ba-text);}
|
|
4072
|
-
#bounded-auth-modal .ba-title{font-family:var(--ba-display);font-weight:400;font-size:25px;letter-spacing:-.01em;margin:0 0 5px;}
|
|
4073
|
-
#bounded-auth-modal .ba-subtitle{color:var(--ba-dim);font-size:14px;margin:0 0 22px;}
|
|
4074
|
-
#bounded-auth-modal .ba-label{display:block;font-size:12px;color:var(--ba-dim);margin:0 0 7px;}
|
|
4075
|
-
#bounded-auth-modal .ba-em{color:var(--ba-text);font-weight:600;}
|
|
4076
|
-
#bounded-auth-modal .ba-input{width:100%;background:var(--ba-inset);border:1px solid var(--ba-line-strong);color:var(--ba-text);
|
|
4077
|
-
border-radius:6px;padding:11px 13px;font-family:var(--ba-body);font-size:15px;outline:none;transition:border-color .15s,box-shadow .15s;}
|
|
4078
|
-
#bounded-auth-modal .ba-input::placeholder{color:var(--ba-faint);}
|
|
4079
|
-
#bounded-auth-modal .ba-input:focus{border-color:var(--ba-green-line);box-shadow:0 0 0 3px var(--ba-green-bg);}
|
|
4080
|
-
#bounded-auth-modal .ba-code{font-family:var(--ba-mono);letter-spacing:8px;text-align:center;font-size:21px;padding-left:8px;}
|
|
4081
|
-
#bounded-auth-modal .ba-btn{width:100%;margin-top:16px;background:var(--ba-text);color:var(--ba-bg);
|
|
4082
|
-
border:0;border-radius:6px;padding:12px;font-family:var(--ba-body);font-size:14px;font-weight:600;cursor:pointer;
|
|
4083
|
-
transition:opacity .15s,transform .04s;}
|
|
4084
|
-
#bounded-auth-modal .ba-btn:hover{opacity:.9;}
|
|
4085
|
-
#bounded-auth-modal .ba-btn:active{transform:translateY(.5px);}
|
|
4086
|
-
#bounded-auth-modal .ba-btn:disabled{opacity:.45;cursor:default;}
|
|
4087
|
-
#bounded-auth-modal .ba-link{width:100%;margin-top:14px;background:none;border:none;color:var(--ba-dim);
|
|
4088
|
-
font-family:var(--ba-body);font-size:12.5px;cursor:pointer;}
|
|
4089
|
-
#bounded-auth-modal .ba-link:hover{color:var(--ba-text);}
|
|
4090
|
-
#bounded-auth-modal .ba-msg{min-height:16px;margin-top:16px;font-size:12.5px;color:var(--ba-dim);text-align:center;}
|
|
4091
|
-
#bounded-auth-modal .ba-msg.err{color:var(--ba-red);}
|
|
4092
|
-
#bounded-auth-modal .ba-foot{margin-top:26px;padding-top:16px;border-top:1px solid var(--ba-line);
|
|
4093
|
-
text-align:center;font-size:11px;color:var(--ba-faint);}
|
|
4094
|
-
#bounded-auth-modal .hidden{display:none;}
|
|
4095
|
-
@media (max-width:480px){#bounded-auth-modal .ba-card{max-width:none;}}`;
|
|
4096
3641
|
|
|
4097
3642
|
const SURFNET_RPC_URL = "https://surfpool.fly.dev";
|
|
4098
3643
|
const SUPPORTED_SOLANA_NETWORKS = new Set([
|
|
@@ -4226,7 +3771,7 @@ function appendHostedLoginHints(params, opts) {
|
|
|
4226
3771
|
// native (expo-web-browser) path. The caller decides where the PkceState lives
|
|
4227
3772
|
// (web → sessionStorage across the full-page redirect; native → in-memory across
|
|
4228
3773
|
// the awaited browser session).
|
|
4229
|
-
async function buildAuthorize(opts
|
|
3774
|
+
async function buildAuthorize(opts) {
|
|
4230
3775
|
const cfg = await getConfig();
|
|
4231
3776
|
if (!cfg.appId)
|
|
4232
3777
|
throw new Error('appId is not configured (init the SDK with your appId)');
|
|
@@ -4243,12 +3788,6 @@ async function buildAuthorize(opts, guestHint) {
|
|
|
4243
3788
|
code_challenge: challenge, code_challenge_method: 'S256', state,
|
|
4244
3789
|
});
|
|
4245
3790
|
appendHostedLoginHints(params, opts);
|
|
4246
|
-
// Anonymous→real UPGRADE (linkWithRedirect): carry the guest's signed id-token THROUGH
|
|
4247
|
-
// the authorize request as a hint. The issuer signature-verifies it and binds it to this
|
|
4248
|
-
// request's PKCE code_challenge, so the link is completed single-use during the normal
|
|
4249
|
-
// code→token exchange — no retired /link/social, and the appId stays bound to client_id.
|
|
4250
|
-
if (guestHint)
|
|
4251
|
-
params.set('bounded_guest_hint', guestHint);
|
|
4252
3791
|
return { url: `${base}/api/auth/oauth2/authorize?${params.toString()}`, pkce: { verifier, state, redirectUri } };
|
|
4253
3792
|
}
|
|
4254
3793
|
// Are we on React Native (no DOM)? OIDC dispatch uses this to choose the native
|
|
@@ -4300,9 +3839,9 @@ function parseCallbackParams(callbackUrl) {
|
|
|
4300
3839
|
// universal-link callback, verify state, and run the SAME PKCE code→token exchange
|
|
4301
3840
|
// as web. Returns the signed-in User (native completes inline — there's no separate
|
|
4302
3841
|
// completeLoginFromRedirect() round-trip the way the web full-page redirect needs).
|
|
4303
|
-
async function runNativeLogin(opts
|
|
3842
|
+
async function runNativeLogin(opts) {
|
|
4304
3843
|
var _a, _b;
|
|
4305
|
-
const { url, pkce } = await buildAuthorize(opts
|
|
3844
|
+
const { url, pkce } = await buildAuthorize(opts);
|
|
4306
3845
|
const WebBrowser = await loadExpoWebBrowser();
|
|
4307
3846
|
const openAuthSession = WebBrowser.openAuthSessionAsync || ((_a = WebBrowser.default) === null || _a === void 0 ? void 0 : _a.openAuthSessionAsync);
|
|
4308
3847
|
if (typeof openAuthSession !== 'function') {
|
|
@@ -4355,37 +3894,12 @@ async function loginWithRedirect(opts) {
|
|
|
4355
3894
|
setAuthLoading(true); // reflect "signing in…" right up to navigation; the return page's
|
|
4356
3895
|
window.location.href = url; // completeLoginFromRedirect() keeps it true until the user resolves.
|
|
4357
3896
|
}
|
|
4358
|
-
/** UPGRADE the current anonymous (guest) session by linking a SOCIAL/redirect login
|
|
4359
|
-
* (e.g. Google) — Firebase `linkWithPopup`/redirect parity. Carries the guest's signed
|
|
4360
|
-
* id-token THROUGH the OIDC authorize request (as a single-use hint bound to the PKCE
|
|
4361
|
-
* challenge), then runs the normal redirect login. The issuer completes the link during
|
|
4362
|
-
* the standard code→token exchange: if the chosen account is brand-new the guest's
|
|
4363
|
-
* `@user.id` is preserved (the returned id_token is minted under it), else the account
|
|
4364
|
-
* stays separate (guest id discarded). Requires an active guest session.
|
|
4365
|
-
*
|
|
4366
|
-
* Works on WEB (navigates, finish with completeLoginFromRedirect) and REACT NATIVE
|
|
4367
|
-
* (opens expo-web-browser and resolves with the upgraded User inline). */
|
|
4368
|
-
async function linkWithRedirect(opts) {
|
|
4369
|
-
const guestToken = sessionManager().getIdToken();
|
|
4370
|
-
if (!guestToken)
|
|
4371
|
-
throw new Error('linkWithRedirect requires an active anonymous session — call signInAnonymously() first.');
|
|
4372
|
-
if (isNative())
|
|
4373
|
-
return runNativeLogin(opts, guestToken);
|
|
4374
|
-
if (!hasDOM())
|
|
4375
|
-
throw new Error('linkWithRedirect requires a browser or a configured React Native platform');
|
|
4376
|
-
const { url, pkce } = await buildAuthorize(opts, guestToken);
|
|
4377
|
-
sessionStorage.setItem(PKCE_STORE_KEY, JSON.stringify(pkce));
|
|
4378
|
-
window.location.href = url;
|
|
4379
|
-
}
|
|
4380
3897
|
/** Finish login on the redirect_uri page (WEB ONLY): exchange ?code= for a token (PKCE-verified),
|
|
4381
3898
|
* store the session, and return the User. Idempotent: returns null if there's no ?code= in the URL.
|
|
4382
|
-
* When the redirect was a guest UPGRADE (linkWithRedirect) and the issuer adopted the guest
|
|
4383
|
-
* id, the exchanged id_token already carries the preserved `@user.id`, so the returned User
|
|
4384
|
-
* reflects it automatically (no extra round-trip).
|
|
4385
3899
|
*
|
|
4386
3900
|
* On REACT NATIVE this returns null and is a no-op: native login completes INLINE inside
|
|
4387
|
-
* loginWithRedirect()
|
|
4388
|
-
*
|
|
3901
|
+
* loginWithRedirect() (which resolves with the User), so there is no separate redirect
|
|
3902
|
+
* page to finish from. Calling it on RN is harmless. */
|
|
4389
3903
|
async function completeLoginFromRedirect() {
|
|
4390
3904
|
if (!hasDOM())
|
|
4391
3905
|
return null;
|
|
@@ -4838,78 +4352,6 @@ async function loginWithPrivy(options) {
|
|
|
4838
4352
|
const result = await provider.login();
|
|
4839
4353
|
return result ? Object.assign(Object.assign({}, result), { provider }) : null;
|
|
4840
4354
|
}
|
|
4841
|
-
// Activate the inline email provider (method=email so reload-restore + logout work),
|
|
4842
|
-
// mirroring signInAnonymously. Used by verifyEmailOtp/verifyTextOtp/linkEmail.
|
|
4843
|
-
async function activateEmailProvider() {
|
|
4844
|
-
const provider = new EmailAuthProvider();
|
|
4845
|
-
currentAuthProvider = provider;
|
|
4846
|
-
currentAuthMethod = 'email';
|
|
4847
|
-
currentAuthProviderConfigKey = 'direct:email';
|
|
4848
|
-
const coreConfig = await getConfig();
|
|
4849
|
-
coreConfig.authProvider = provider;
|
|
4850
|
-
coreConfig.authMethod = 'email';
|
|
4851
|
-
setAuthProviderInstance(provider);
|
|
4852
|
-
setStoredAuthMethod('email');
|
|
4853
|
-
return provider;
|
|
4854
|
-
}
|
|
4855
|
-
/**
|
|
4856
|
-
* Send a 6-digit login code to `email` (Bounded Better Auth). Step 1 of the
|
|
4857
|
-
* inline email flow — build your own email/code UI for full control over the
|
|
4858
|
-
* look, or just call `login()` for the built-in modal. Works on web AND React
|
|
4859
|
-
* Native (no DOM needed). Prefer `loginWithRedirect()`/`loginWithPopup()` if you
|
|
4860
|
-
* want the credential entered on Bounded's hosted page instead.
|
|
4861
|
-
*/
|
|
4862
|
-
async function sendEmailOtp(email) {
|
|
4863
|
-
assertBrowserAuthEnv('sendEmailOtp');
|
|
4864
|
-
return sendEmailOtp$1(email);
|
|
4865
|
-
}
|
|
4866
|
-
/**
|
|
4867
|
-
* Send a 6-digit login code by text message. Requires the configured Bounded
|
|
4868
|
-
* auth issuer to have text OTP explicitly enabled and SMS delivery configured.
|
|
4869
|
-
* Works on web AND React Native.
|
|
4870
|
-
*/
|
|
4871
|
-
async function sendTextOtp(phoneNumber) {
|
|
4872
|
-
assertBrowserAuthEnv('sendTextOtp');
|
|
4873
|
-
return sendTextOtp$1(phoneNumber);
|
|
4874
|
-
}
|
|
4875
|
-
/**
|
|
4876
|
-
* Verify the `code` for `email`, establish the session, and return the user.
|
|
4877
|
-
* Step 2 of the inline email flow. Coexists with signInAnonymously()/wallets.
|
|
4878
|
-
*/
|
|
4879
|
-
async function verifyEmailOtp(email, code) {
|
|
4880
|
-
assertBrowserAuthEnv('verifyEmailOtp');
|
|
4881
|
-
await activateEmailProvider();
|
|
4882
|
-
return verifyEmailOtp$1(email, code);
|
|
4883
|
-
}
|
|
4884
|
-
/**
|
|
4885
|
-
* Verify the text-message `code`, establish the session, and return the user.
|
|
4886
|
-
* Phone-only users have no `user.email`; use `user.id` for app identity.
|
|
4887
|
-
*/
|
|
4888
|
-
async function verifyTextOtp(phoneNumber, code) {
|
|
4889
|
-
assertBrowserAuthEnv('verifyTextOtp');
|
|
4890
|
-
await activateEmailProvider();
|
|
4891
|
-
return verifyTextOtp$1(phoneNumber, code);
|
|
4892
|
-
}
|
|
4893
|
-
/**
|
|
4894
|
-
* UPGRADE the current anonymous (guest) session by linking an email — Firebase
|
|
4895
|
-
* `linkWithCredential` parity. Send the code first with `sendEmailOtp(email)`,
|
|
4896
|
-
* then call `linkEmail(email, code)`. If the email is brand-new the guest's
|
|
4897
|
-
* `@user.id` (and its data) is preserved; if the email already exists the user
|
|
4898
|
-
* just signs into it (no merge). Requires an active guest session, and the issuer
|
|
4899
|
-
* refuses if the wallet is already linked. Browser/React-Native only.
|
|
4900
|
-
*/
|
|
4901
|
-
async function linkEmail(email, code) {
|
|
4902
|
-
assertBrowserAuthEnv('linkEmail');
|
|
4903
|
-
// Capture the GUEST token BEFORE switching auth methods — the issuer needs it
|
|
4904
|
-
// to prove guest ownership and adopt its id into the new email account.
|
|
4905
|
-
const guestToken = getActiveSessionManager().getIdToken();
|
|
4906
|
-
if (!guestToken) {
|
|
4907
|
-
throw new Error('linkEmail requires an active anonymous session — call signInAnonymously() first.');
|
|
4908
|
-
}
|
|
4909
|
-
await activateEmailProvider(); // method=email so the upgraded user is no longer anonymous
|
|
4910
|
-
const { user } = await linkEmailWithGuest(email, code, guestToken);
|
|
4911
|
-
return user;
|
|
4912
|
-
}
|
|
4913
4355
|
async function login$1(options) {
|
|
4914
4356
|
// Re-initialize provider if it was cleared by logout
|
|
4915
4357
|
if (!currentAuthProvider && initConfig) {
|
|
@@ -5687,5 +5129,5 @@ class PrivyExpoProvider {
|
|
|
5687
5129
|
}
|
|
5688
5130
|
}
|
|
5689
5131
|
|
|
5690
|
-
export { OffchainAuthProvider, PrivyExpoProvider, completeLoginFromRedirect, completeLoginInPopup, deserializeTransaction, getAuthLoading, getAuthProvider, getCurrentUser, getIdToken, getPlatform, init,
|
|
5132
|
+
export { OffchainAuthProvider, PrivyExpoProvider, completeLoginFromRedirect, completeLoginInPopup, deserializeTransaction, getAuthLoading, getAuthProvider, getCurrentUser, getIdToken, getPlatform, init, login, loginWithPopup, loginWithPrivy, loginWithRedirect, logout, onAuthLoadingChanged, onAuthStateChanged, setPlatform, signInAnonymously, useAuth, useQuery };
|
|
5691
5133
|
//# sourceMappingURL=index.mjs.map
|