@bounded-sh/client 0.0.38 → 0.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/providers/injected-wallet-provider.d.ts +30 -0
- package/dist/auth/providers/injected-wallet-types.d.ts +53 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +384 -61
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +385 -63
- package/dist/index.mjs.map +1 -1
- package/dist/index.native.js +383 -61
- package/dist/index.native.js.map +1 -1
- package/dist/index.native.mjs +384 -62
- package/dist/index.native.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { getActiveSessionManager, genAuthNonce, genSolanaMessage, createSessionWithSignature, getConfig, WebSessionManager, ReactNativeSessionManager, revokeSession, init as init$1, reconnectWithNewAuth, deriveUserIdentityFromIdToken, subscribe, getIdToken as getIdToken$1
|
|
1
|
+
import { getActiveSessionManager, genAuthNonce, genSolanaMessage, createSessionWithSignature, getConfig, convertRemainingAccounts, buildSetDocumentsTransaction, WebSessionManager, ReactNativeSessionManager, revokeSession, init as init$1, reconnectWithNewAuth, deriveUserIdentityFromIdToken, subscribe, getIdToken as getIdToken$1 } from '@bounded-sh/core';
|
|
2
2
|
export * from '@bounded-sh/core';
|
|
3
3
|
export { BoundedDeclineError, DECLINE_EVENT_NAME, aggregate, count, deriveDecline, dispatchDeclineEvent, docId, get, getConfig, getFiles, getMany, queryAggregate, runExpression, runExpressionMany, runQuery, runQueryMany, search, set, setFile, setMany, signAndSubmitTransaction, signMessage, signTransaction, subscribe } from '@bounded-sh/core';
|
|
4
|
-
import
|
|
5
|
-
import { VersionedTransaction, Transaction, Connection, PublicKey } from '@solana/web3.js';
|
|
4
|
+
import { Connection, PublicKey, VersionedTransaction, Transaction } from '@solana/web3.js';
|
|
6
5
|
import * as anchor from '@coral-xyz/anchor';
|
|
6
|
+
import * as React from 'react';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Platform abstraction layer for React Native compatibility.
|
|
@@ -3906,6 +3906,306 @@ function resolveSolanaRpcUrl(explicitRpcUrl, network, context) {
|
|
|
3906
3906
|
throw new Error(`${context} requires an explicit Solana RPC URL. Pass config.rpcUrl before signing or submitting onchain transactions.`);
|
|
3907
3907
|
}
|
|
3908
3908
|
|
|
3909
|
+
/**
|
|
3910
|
+
* Extracts a human-readable error message from Solana transaction logs.
|
|
3911
|
+
*/
|
|
3912
|
+
function extractTransactionError(err, logMessages) {
|
|
3913
|
+
if (logMessages) {
|
|
3914
|
+
return JSON.stringify(logMessages);
|
|
3915
|
+
}
|
|
3916
|
+
if (err) {
|
|
3917
|
+
try {
|
|
3918
|
+
return JSON.stringify(err);
|
|
3919
|
+
}
|
|
3920
|
+
catch (_a) {
|
|
3921
|
+
return String(err);
|
|
3922
|
+
}
|
|
3923
|
+
}
|
|
3924
|
+
return 'Unknown transaction error';
|
|
3925
|
+
}
|
|
3926
|
+
/**
|
|
3927
|
+
* Polls getSignatureStatuses until the transaction is confirmed, then checks for errors.
|
|
3928
|
+
* Throws if the transaction failed on-chain. Returns parsed transaction info on success.
|
|
3929
|
+
*/
|
|
3930
|
+
async function confirmAndCheckTransaction(connection, signature) {
|
|
3931
|
+
var _a;
|
|
3932
|
+
const maxAttempts = 15;
|
|
3933
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
3934
|
+
const { value } = await connection.getSignatureStatuses([signature]);
|
|
3935
|
+
const status = value[0];
|
|
3936
|
+
if (status) {
|
|
3937
|
+
if (status.err) {
|
|
3938
|
+
const txInfo = await connection.getParsedTransaction(signature, {
|
|
3939
|
+
maxSupportedTransactionVersion: 0,
|
|
3940
|
+
commitment: 'confirmed'
|
|
3941
|
+
});
|
|
3942
|
+
const errorMessage = extractTransactionError(status.err, (_a = txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta) === null || _a === void 0 ? void 0 : _a.logMessages);
|
|
3943
|
+
throw new Error(`Transaction failed: ${errorMessage}`);
|
|
3944
|
+
}
|
|
3945
|
+
if (status.confirmationStatus === 'confirmed' || status.confirmationStatus === 'finalized') {
|
|
3946
|
+
return await connection.getParsedTransaction(signature, {
|
|
3947
|
+
maxSupportedTransactionVersion: 0,
|
|
3948
|
+
commitment: 'confirmed'
|
|
3949
|
+
});
|
|
3950
|
+
}
|
|
3951
|
+
}
|
|
3952
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
3953
|
+
}
|
|
3954
|
+
throw new Error('Transaction confirmation timeout');
|
|
3955
|
+
}
|
|
3956
|
+
|
|
3957
|
+
/**
|
|
3958
|
+
* Default provider discovery: Phantom-first, then any Wallet-Standard
|
|
3959
|
+
* `window.solana`. Kept tiny + synchronous (no heavy imports) so it works inside
|
|
3960
|
+
* a user gesture and can be eagerly exported from the SDK entry.
|
|
3961
|
+
*/
|
|
3962
|
+
function defaultInjectedProvider() {
|
|
3963
|
+
var _a;
|
|
3964
|
+
if (typeof window === 'undefined')
|
|
3965
|
+
return null;
|
|
3966
|
+
const w = window;
|
|
3967
|
+
const phantom = (_a = w === null || w === void 0 ? void 0 : w.phantom) === null || _a === void 0 ? void 0 : _a.solana;
|
|
3968
|
+
if (phantom && typeof phantom.signMessage === 'function')
|
|
3969
|
+
return phantom;
|
|
3970
|
+
const generic = w === null || w === void 0 ? void 0 : w.solana;
|
|
3971
|
+
if (generic && typeof generic.signMessage === 'function')
|
|
3972
|
+
return generic;
|
|
3973
|
+
return null;
|
|
3974
|
+
}
|
|
3975
|
+
|
|
3976
|
+
const STORED_AUTH_METHOD_KEY$2 = 'bounded_last_auth_method';
|
|
3977
|
+
const INJECTED_AUTH_METHOD = 'phantom';
|
|
3978
|
+
const NO_WALLET_ERR = 'No injected Solana wallet found. Install a wallet like Phantom (phantom.app) and try again, ' +
|
|
3979
|
+
'or pass config.injectedWalletConfig.getProvider to point at your wallet.';
|
|
3980
|
+
class InjectedWalletProvider {
|
|
3981
|
+
constructor(config = {}, networkUrl = null, configuredNetwork = null) {
|
|
3982
|
+
var _a, _b;
|
|
3983
|
+
if (typeof window === 'undefined') {
|
|
3984
|
+
throw new Error('InjectedWalletProvider can only be instantiated in a browser environment');
|
|
3985
|
+
}
|
|
3986
|
+
// Singleton so the SDK reuses one instance (mirrors the other providers).
|
|
3987
|
+
if (InjectedWalletProvider.instance) {
|
|
3988
|
+
InjectedWalletProvider.instance.config = Object.assign(Object.assign({}, InjectedWalletProvider.instance.config), config);
|
|
3989
|
+
return InjectedWalletProvider.instance;
|
|
3990
|
+
}
|
|
3991
|
+
this.config = config;
|
|
3992
|
+
this.networkUrl = (_a = config.rpcUrl) !== null && _a !== void 0 ? _a : networkUrl;
|
|
3993
|
+
this.configuredNetwork = (_b = config.network) !== null && _b !== void 0 ? _b : configuredNetwork;
|
|
3994
|
+
InjectedWalletProvider.instance = this;
|
|
3995
|
+
}
|
|
3996
|
+
resolveProvider() {
|
|
3997
|
+
var _a;
|
|
3998
|
+
const provider = (_a = (this.config.getProvider ? this.config.getProvider() : null)) !== null && _a !== void 0 ? _a : defaultInjectedProvider();
|
|
3999
|
+
if (!provider)
|
|
4000
|
+
throw new Error(NO_WALLET_ERR);
|
|
4001
|
+
return provider;
|
|
4002
|
+
}
|
|
4003
|
+
/** Connect the injected wallet (if needed) and return its Solana address. */
|
|
4004
|
+
async connectAddress(provider, onlyIfTrusted = false) {
|
|
4005
|
+
var _a, _b;
|
|
4006
|
+
// Already connected — reuse the pubkey.
|
|
4007
|
+
if (provider.publicKey && ((_a = provider.isConnected) !== null && _a !== void 0 ? _a : true)) {
|
|
4008
|
+
return provider.publicKey.toString();
|
|
4009
|
+
}
|
|
4010
|
+
const res = await provider.connect(onlyIfTrusted ? { onlyIfTrusted: true } : undefined);
|
|
4011
|
+
const pk = (_b = res === null || res === void 0 ? void 0 : res.publicKey) !== null && _b !== void 0 ? _b : provider.publicKey;
|
|
4012
|
+
if (!pk)
|
|
4013
|
+
throw new Error('Wallet did not return a public key on connect');
|
|
4014
|
+
return pk.toString();
|
|
4015
|
+
}
|
|
4016
|
+
async login() {
|
|
4017
|
+
var _a;
|
|
4018
|
+
setAuthLoading(true);
|
|
4019
|
+
try {
|
|
4020
|
+
const provider = this.resolveProvider();
|
|
4021
|
+
const address = await this.connectAddress(provider);
|
|
4022
|
+
// Reuse a still-valid session for THIS wallet.
|
|
4023
|
+
const existing = await getActiveSessionManager().getSession();
|
|
4024
|
+
if (existing && existing.address === address) {
|
|
4025
|
+
const user = { address, id: address, provider: this };
|
|
4026
|
+
setCurrentUser(user);
|
|
4027
|
+
this.markAuthMethod();
|
|
4028
|
+
return user;
|
|
4029
|
+
}
|
|
4030
|
+
// SIWS: nonce -> canonical prompt -> the wallet signs it locally.
|
|
4031
|
+
const nonce = await genAuthNonce();
|
|
4032
|
+
const message = await genSolanaMessage(address, nonce);
|
|
4033
|
+
const messageBytes = getPlatform().textEncode(message);
|
|
4034
|
+
const signResult = await provider.signMessage(messageBytes, 'utf8');
|
|
4035
|
+
const signatureBytes = (_a = signResult === null || signResult === void 0 ? void 0 : signResult.signature) !== null && _a !== void 0 ? _a : signResult;
|
|
4036
|
+
// base64 detached ed25519 signature — matches guest/privy providers and
|
|
4037
|
+
// the bounded-auth issuer's base64ToBytes() verify path.
|
|
4038
|
+
const signature = bufferExports.Buffer.from(signatureBytes).toString('base64');
|
|
4039
|
+
const result = await createSessionWithSignature(address, message, signature);
|
|
4040
|
+
await getActiveSessionManager().storeSession(address, result.accessToken, result.idToken, result.refreshToken);
|
|
4041
|
+
this.markAuthMethod();
|
|
4042
|
+
const user = { address, id: address, provider: this };
|
|
4043
|
+
setCurrentUser(user);
|
|
4044
|
+
return user;
|
|
4045
|
+
}
|
|
4046
|
+
finally {
|
|
4047
|
+
setAuthLoading(false);
|
|
4048
|
+
}
|
|
4049
|
+
}
|
|
4050
|
+
markAuthMethod() {
|
|
4051
|
+
// Mark the auth method so clearIncompatibleSession() doesn't wipe this
|
|
4052
|
+
// wallet session on the next init().
|
|
4053
|
+
try {
|
|
4054
|
+
getPlatform().storage.setItem(STORED_AUTH_METHOD_KEY$2, INJECTED_AUTH_METHOD);
|
|
4055
|
+
}
|
|
4056
|
+
catch ( /* no storage */_a) { /* no storage */ }
|
|
4057
|
+
}
|
|
4058
|
+
async restoreSession() {
|
|
4059
|
+
const session = await getActiveSessionManager().getSession();
|
|
4060
|
+
if (!session)
|
|
4061
|
+
return null;
|
|
4062
|
+
const user = { address: session.address, id: session.address, provider: this };
|
|
4063
|
+
setCurrentUser(user);
|
|
4064
|
+
return user;
|
|
4065
|
+
}
|
|
4066
|
+
async logout() {
|
|
4067
|
+
// Clear the Bounded session; best-effort disconnect the wallet.
|
|
4068
|
+
getActiveSessionManager().clearSession();
|
|
4069
|
+
try {
|
|
4070
|
+
const provider = this.config.getProvider ? this.config.getProvider() : defaultInjectedProvider();
|
|
4071
|
+
if (provider && typeof provider.disconnect === 'function')
|
|
4072
|
+
await provider.disconnect();
|
|
4073
|
+
}
|
|
4074
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
4075
|
+
setCurrentUser(null);
|
|
4076
|
+
}
|
|
4077
|
+
// --- Full local-keypair signing surface (the wallet's OWN methods) --------
|
|
4078
|
+
async signMessage(message) {
|
|
4079
|
+
var _a;
|
|
4080
|
+
const provider = this.resolveProvider();
|
|
4081
|
+
await this.connectAddress(provider, true).catch(() => this.connectAddress(provider));
|
|
4082
|
+
const messageBytes = getPlatform().textEncode(message);
|
|
4083
|
+
const res = await provider.signMessage(messageBytes, 'utf8');
|
|
4084
|
+
const signatureBytes = (_a = res === null || res === void 0 ? void 0 : res.signature) !== null && _a !== void 0 ? _a : res;
|
|
4085
|
+
// base58 is the standard Solana signature encoding for app-facing signMessage.
|
|
4086
|
+
return bs58.encode(signatureBytes instanceof Uint8Array ? signatureBytes : new Uint8Array(signatureBytes));
|
|
4087
|
+
}
|
|
4088
|
+
async signTransaction(transaction) {
|
|
4089
|
+
const provider = this.resolveProvider();
|
|
4090
|
+
await this.connectAddress(provider, true).catch(() => this.connectAddress(provider));
|
|
4091
|
+
return provider.signTransaction(transaction);
|
|
4092
|
+
}
|
|
4093
|
+
async signAndSubmitTransaction(transaction, _feePayer) {
|
|
4094
|
+
const provider = this.resolveProvider();
|
|
4095
|
+
const address = await this.connectAddress(provider, true).catch(() => this.connectAddress(provider));
|
|
4096
|
+
const rpcUrl = this.getRpcUrl();
|
|
4097
|
+
const connection = new Connection(rpcUrl, 'confirmed');
|
|
4098
|
+
const isSurfnet = rpcUrl === SURFNET_RPC_URL;
|
|
4099
|
+
// Set a fresh blockhash on the tx (mirrors the other providers).
|
|
4100
|
+
const { blockhash } = await connection.getLatestBlockhash('confirmed');
|
|
4101
|
+
const isLegacy = 'recentBlockhash' in transaction &&
|
|
4102
|
+
!('message' in transaction && 'staticAccountKeys' in transaction.message);
|
|
4103
|
+
if (isLegacy) {
|
|
4104
|
+
const legacy = transaction;
|
|
4105
|
+
legacy.recentBlockhash = blockhash;
|
|
4106
|
+
if (!legacy.feePayer)
|
|
4107
|
+
legacy.feePayer = new PublicKey(address);
|
|
4108
|
+
}
|
|
4109
|
+
else {
|
|
4110
|
+
transaction.message.recentBlockhash = blockhash;
|
|
4111
|
+
}
|
|
4112
|
+
// Prefer the wallet's native signAndSend on live networks; fall back to
|
|
4113
|
+
// sign + manual submit (needed for surfnet / wallets without send).
|
|
4114
|
+
if (!isSurfnet && typeof provider.signAndSendTransaction === 'function') {
|
|
4115
|
+
const res = await provider.signAndSendTransaction(transaction);
|
|
4116
|
+
const signature = res.signature;
|
|
4117
|
+
await confirmAndCheckTransaction(connection, signature);
|
|
4118
|
+
return signature;
|
|
4119
|
+
}
|
|
4120
|
+
const signed = await provider.signTransaction(transaction);
|
|
4121
|
+
const raw = signed.serialize();
|
|
4122
|
+
const signature = await connection.sendRawTransaction(raw);
|
|
4123
|
+
await confirmAndCheckTransaction(connection, signature);
|
|
4124
|
+
return signature;
|
|
4125
|
+
}
|
|
4126
|
+
/**
|
|
4127
|
+
* Onchain write path (mirrors the other wallet providers): build the Bounded
|
|
4128
|
+
* set-documents transaction with the injected wallet as payer, then sign +
|
|
4129
|
+
* submit with the wallet's own keypair.
|
|
4130
|
+
*/
|
|
4131
|
+
async runTransaction(_evmTransactionData, solTransactionData, options) {
|
|
4132
|
+
var _a, _b;
|
|
4133
|
+
if (!solTransactionData) {
|
|
4134
|
+
throw new Error('Solana transaction data is required for wallet login');
|
|
4135
|
+
}
|
|
4136
|
+
const provider = this.resolveProvider();
|
|
4137
|
+
const address = await this.connectAddress(provider, true).catch(() => this.connectAddress(provider));
|
|
4138
|
+
const publicKey = new PublicKey(address);
|
|
4139
|
+
const rpcUrl = this.getRpcUrl(solTransactionData.network);
|
|
4140
|
+
const connection = new Connection(rpcUrl, 'confirmed');
|
|
4141
|
+
const isSurfnet = rpcUrl === SURFNET_RPC_URL;
|
|
4142
|
+
const app_id = solTransactionData.appId;
|
|
4143
|
+
if (!app_id)
|
|
4144
|
+
throw new Error('App ID is required');
|
|
4145
|
+
const walletAdapter = {
|
|
4146
|
+
publicKey,
|
|
4147
|
+
signTransaction: async (tx) => provider.signTransaction(tx),
|
|
4148
|
+
signAllTransactions: async (txs) => provider.signAllTransactions
|
|
4149
|
+
? provider.signAllTransactions(txs)
|
|
4150
|
+
: Promise.all(txs.map((t) => provider.signTransaction(t))),
|
|
4151
|
+
};
|
|
4152
|
+
const anchorProvider = new anchor.AnchorProvider(connection, walletAdapter, anchor.AnchorProvider.defaultOptions());
|
|
4153
|
+
const remainingAccounts = convertRemainingAccounts(solTransactionData.txArgs[0].remainingAccounts);
|
|
4154
|
+
const finalDeduped = [];
|
|
4155
|
+
for (const acc of remainingAccounts) {
|
|
4156
|
+
const existing = finalDeduped.find((d) => d.pubkey.equals(acc.pubkey));
|
|
4157
|
+
if (existing) {
|
|
4158
|
+
existing.isSigner = existing.isSigner || acc.isSigner;
|
|
4159
|
+
existing.isWritable = existing.isWritable || acc.isWritable;
|
|
4160
|
+
}
|
|
4161
|
+
else {
|
|
4162
|
+
finalDeduped.push(acc);
|
|
4163
|
+
}
|
|
4164
|
+
}
|
|
4165
|
+
let tx;
|
|
4166
|
+
if (solTransactionData.signedTransaction) {
|
|
4167
|
+
// Server co-signed (CPI attestation) — just add the wallet signature.
|
|
4168
|
+
tx = VersionedTransaction.deserialize(bufferExports.Buffer.from(solTransactionData.signedTransaction, 'base64'));
|
|
4169
|
+
}
|
|
4170
|
+
else {
|
|
4171
|
+
const result = await buildSetDocumentsTransaction(connection, solTransactionData.txArgs[0].idl, anchorProvider, publicKey, {
|
|
4172
|
+
app_id,
|
|
4173
|
+
documents: solTransactionData.txArgs[0].setDocumentData,
|
|
4174
|
+
delete_paths: solTransactionData.txArgs[0].deletePaths,
|
|
4175
|
+
txData: solTransactionData.txArgs[0].txData,
|
|
4176
|
+
}, finalDeduped, solTransactionData.lutKey, solTransactionData.preInstructions, false, solTransactionData.additionalLutAddresses);
|
|
4177
|
+
tx = result.tx;
|
|
4178
|
+
}
|
|
4179
|
+
if ((options === null || options === void 0 ? void 0 : options.shouldSubmitTx) === false) {
|
|
4180
|
+
const signedTx = await walletAdapter.signTransaction(tx);
|
|
4181
|
+
return { signedTransaction: signedTx, blockNumber: 0, gasUsed: '0', data: '' };
|
|
4182
|
+
}
|
|
4183
|
+
let signature;
|
|
4184
|
+
if (!isSurfnet && typeof provider.signAndSendTransaction === 'function') {
|
|
4185
|
+
const res = await provider.signAndSendTransaction(tx);
|
|
4186
|
+
signature = res.signature;
|
|
4187
|
+
}
|
|
4188
|
+
else {
|
|
4189
|
+
const signedTx = await walletAdapter.signTransaction(tx);
|
|
4190
|
+
signature = await connection.sendRawTransaction(signedTx.serialize());
|
|
4191
|
+
}
|
|
4192
|
+
const txInfo = await confirmAndCheckTransaction(connection, signature);
|
|
4193
|
+
return {
|
|
4194
|
+
transactionSignature: signature,
|
|
4195
|
+
blockNumber: (txInfo === null || txInfo === void 0 ? void 0 : txInfo.slot) || 0,
|
|
4196
|
+
gasUsed: ((_b = (_a = txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta) === null || _a === void 0 ? void 0 : _a.fee) === null || _b === void 0 ? void 0 : _b.toString()) || '0',
|
|
4197
|
+
data: txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta,
|
|
4198
|
+
};
|
|
4199
|
+
}
|
|
4200
|
+
async getNativeMethods() {
|
|
4201
|
+
return this.resolveProvider();
|
|
4202
|
+
}
|
|
4203
|
+
getRpcUrl(network) {
|
|
4204
|
+
return resolveSolanaRpcUrl(this.networkUrl, network !== null && network !== void 0 ? network : this.configuredNetwork, 'Wallet-login Solana transaction');
|
|
4205
|
+
}
|
|
4206
|
+
}
|
|
4207
|
+
InjectedWalletProvider.instance = null;
|
|
4208
|
+
|
|
3909
4209
|
// Same message the email provider uses when a hosted (OIDC) login has no
|
|
3910
4210
|
// embedded wallet — enable `auth.wallets` in policy to get one.
|
|
3911
4211
|
const OIDC_NO_WALLET = 'This login has no embedded wallet. Enable `"auth": { "wallets": true }` in ' +
|
|
@@ -4397,7 +4697,7 @@ function stableConfigValue(value, seen = new WeakSet()) {
|
|
|
4397
4697
|
return String(value);
|
|
4398
4698
|
}
|
|
4399
4699
|
function authProviderConfigKey(config) {
|
|
4400
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
4700
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
4401
4701
|
return JSON.stringify({
|
|
4402
4702
|
authMethod: (_a = config.authMethod) !== null && _a !== void 0 ? _a : null,
|
|
4403
4703
|
chain: (_b = config.chain) !== null && _b !== void 0 ? _b : null,
|
|
@@ -4405,9 +4705,11 @@ function authProviderConfigKey(config) {
|
|
|
4405
4705
|
name: (_c = config.name) !== null && _c !== void 0 ? _c : null,
|
|
4406
4706
|
logoUrl: (_d = config.logoUrl) !== null && _d !== void 0 ? _d : null,
|
|
4407
4707
|
phantomConfig: stableConfigValue((_e = config.phantomConfig) !== null && _e !== void 0 ? _e : null),
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4708
|
+
walletLogin: stableConfigValue((_f = config.walletLogin) !== null && _f !== void 0 ? _f : null),
|
|
4709
|
+
injectedWalletConfig: stableConfigValue((_g = config.injectedWalletConfig) !== null && _g !== void 0 ? _g : null),
|
|
4710
|
+
privyConfig: stableConfigValue((_h = config.privyConfig) !== null && _h !== void 0 ? _h : null),
|
|
4711
|
+
mobileWalletConfig: stableConfigValue((_j = config.mobileWalletConfig) !== null && _j !== void 0 ? _j : null),
|
|
4712
|
+
privyExpoProvider: objectIdentityKey((_k = config.privyExpoProvider) !== null && _k !== void 0 ? _k : null),
|
|
4411
4713
|
});
|
|
4412
4714
|
}
|
|
4413
4715
|
/**
|
|
@@ -4440,6 +4742,47 @@ function getConfiguredSolanaNetwork(config) {
|
|
|
4440
4742
|
return null;
|
|
4441
4743
|
return chain;
|
|
4442
4744
|
}
|
|
4745
|
+
// Error thrown when an app tries wallet login WITHOUT opting in at init().
|
|
4746
|
+
// Wallet login is OFF by default — most apps never support wallets, so the
|
|
4747
|
+
// wallet choice is only usable when the developer explicitly asked for it.
|
|
4748
|
+
function walletLoginNotEnabledError(method) {
|
|
4749
|
+
return new Error(`Bounded: Solana wallet login (authMethod:"${method}") is OFF by default and not enabled for this app. ` +
|
|
4750
|
+
`Wallet login is opt-in — pass \`walletLogin: true\` (or a \`walletLogin\` / \`injectedWalletConfig\` object) ` +
|
|
4751
|
+
`to init() to enable the "connect wallet" choice. Most apps don't need it; use hosted login ` +
|
|
4752
|
+
`loginWithRedirect(...) for email/social, or signInAnonymously() for zero-friction guests.`);
|
|
4753
|
+
}
|
|
4754
|
+
/**
|
|
4755
|
+
* Whether the app opted into Solana WALLET LOGIN at init(). OPT-IN, default OFF:
|
|
4756
|
+
* enabled only when the developer explicitly passes `walletLogin: true` (or a
|
|
4757
|
+
* `walletLogin` / `injectedWalletConfig` object). This gate is what keeps wallet
|
|
4758
|
+
* login from being usable (or advertised) by the vast majority of apps that
|
|
4759
|
+
* never want it — existing apps that don't opt in see ZERO behavior change.
|
|
4760
|
+
*/
|
|
4761
|
+
function isWalletLoginEnabled(config) {
|
|
4762
|
+
const wl = config.walletLogin;
|
|
4763
|
+
if (wl === true)
|
|
4764
|
+
return true;
|
|
4765
|
+
if (wl && typeof wl === 'object')
|
|
4766
|
+
return true;
|
|
4767
|
+
if (config.injectedWalletConfig && typeof config.injectedWalletConfig === 'object')
|
|
4768
|
+
return true;
|
|
4769
|
+
return false;
|
|
4770
|
+
}
|
|
4771
|
+
/**
|
|
4772
|
+
* Resolve the injected-wallet-config the provider should use, merging the
|
|
4773
|
+
* `walletLogin` object form (if the app passed one) over `injectedWalletConfig`.
|
|
4774
|
+
* `walletLogin: true` (bare boolean) enables login with default provider
|
|
4775
|
+
* discovery (Phantom-first) and no RPC override.
|
|
4776
|
+
*/
|
|
4777
|
+
function resolveInjectedWalletConfig(config) {
|
|
4778
|
+
const base = (config.injectedWalletConfig && typeof config.injectedWalletConfig === 'object')
|
|
4779
|
+
? config.injectedWalletConfig
|
|
4780
|
+
: {};
|
|
4781
|
+
const wl = config.walletLogin;
|
|
4782
|
+
if (wl && typeof wl === 'object')
|
|
4783
|
+
return Object.assign(Object.assign({}, base), wl);
|
|
4784
|
+
return base;
|
|
4785
|
+
}
|
|
4443
4786
|
function optionalProviderError(method) {
|
|
4444
4787
|
return new Error(`Bounded authMethod "${method}" uses an optional wallet/provider SDK that is no longer ` +
|
|
4445
4788
|
`pulled into the default @bounded-sh/client entry. Use hosted login ` +
|
|
@@ -4462,8 +4805,8 @@ async function getAuthProvider(config) {
|
|
|
4462
4805
|
}
|
|
4463
4806
|
initConfig = config;
|
|
4464
4807
|
const authMethod = (_a = config.authMethod) !== null && _a !== void 0 ? _a : "email";
|
|
4465
|
-
normalizeSolanaRpcUrl(config.rpcUrl);
|
|
4466
|
-
getConfiguredSolanaNetwork(config);
|
|
4808
|
+
const rpcUrl = normalizeSolanaRpcUrl(config.rpcUrl);
|
|
4809
|
+
const configuredNetwork = getConfiguredSolanaNetwork(config);
|
|
4467
4810
|
currentAuthMethod = authMethod;
|
|
4468
4811
|
// Clear, actionable error when the BROWSER build (`bounded-sh`) is loaded in a
|
|
4469
4812
|
// non-browser (Node) runtime. The wallet providers below need `window`; without
|
|
@@ -4471,7 +4814,7 @@ async function getAuthProvider(config) {
|
|
|
4471
4814
|
// browser environment" deep in init(). The server build (`bounded-sh/server`)
|
|
4472
4815
|
// never resolves these methods (it signs with a keypair), so this can't fire for
|
|
4473
4816
|
// it — it only converts the cryptic browser-in-Node crash into a useful message.
|
|
4474
|
-
const browserWalletMethods = ['phantom', 'rainbowkit', 'coinbase-smart-wallet', 'onboard', 'mobile-wallet-adapter', 'privy'];
|
|
4817
|
+
const browserWalletMethods = ['phantom', 'wallet', 'rainbowkit', 'coinbase-smart-wallet', 'onboard', 'mobile-wallet-adapter', 'privy'];
|
|
4475
4818
|
if (typeof window === 'undefined' && browserWalletMethods.includes(authMethod)) {
|
|
4476
4819
|
throw new Error(`bounded-sh: '${authMethod}' auth requires a browser, but no \`window\` was found ` +
|
|
4477
4820
|
`(you're likely running in Node). In server/Node code, import from 'bounded-sh/server' ` +
|
|
@@ -4487,14 +4830,28 @@ async function getAuthProvider(config) {
|
|
|
4487
4830
|
currentAuthProvider = new EmailAuthProvider();
|
|
4488
4831
|
break;
|
|
4489
4832
|
case "wallet":
|
|
4490
|
-
|
|
4833
|
+
case "phantom": {
|
|
4834
|
+
// First-class Solana WALLET LOGIN (the poof/TaroBase-style "connect
|
|
4835
|
+
// wallet" choice). Slim path: rides the injected Solana provider a
|
|
4836
|
+
// browser wallet exposes (Phantom's window.phantom.solana, or any
|
|
4837
|
+
// Wallet-Standard window.solana). The user's REAL wallet becomes
|
|
4838
|
+
// @user.address; login = SIWS; full local signing surface. No React
|
|
4839
|
+
// and no heavy wallet-SDK peer dep. 'wallet' is an alias for the same
|
|
4840
|
+
// path.
|
|
4841
|
+
//
|
|
4842
|
+
// OPT-IN, DEFAULT OFF: only usable when the app explicitly enabled it
|
|
4843
|
+
// at init() (walletLogin: true). Otherwise throw a clear, actionable
|
|
4844
|
+
// error — most apps never support wallets, so we never construct the
|
|
4845
|
+
// provider (or pay its lazy chunk) for them.
|
|
4846
|
+
if (!isWalletLoginEnabled(config)) {
|
|
4847
|
+
throw walletLoginNotEnabledError(authMethod);
|
|
4848
|
+
}
|
|
4849
|
+
currentAuthProvider = new InjectedWalletProvider(resolveInjectedWalletConfig(config), rpcUrl, configuredNetwork);
|
|
4491
4850
|
break;
|
|
4851
|
+
}
|
|
4492
4852
|
case "rainbowkit":
|
|
4493
4853
|
console.warn("Rainbow Kit auth is not yet supported.");
|
|
4494
4854
|
break;
|
|
4495
|
-
case "phantom": {
|
|
4496
|
-
throw optionalProviderError("phantom");
|
|
4497
|
-
}
|
|
4498
4855
|
case "privy": {
|
|
4499
4856
|
throw optionalProviderError("privy");
|
|
4500
4857
|
}
|
|
@@ -4661,6 +5018,19 @@ function getCurrentAuthMethod() {
|
|
|
4661
5018
|
}
|
|
4662
5019
|
async function logout$1() {
|
|
4663
5020
|
var _a;
|
|
5021
|
+
// Re-initialize the provider if it was cleared by a prior logout — the exact mirror
|
|
5022
|
+
// of login()'s self-heal above. A hosted popup/redirect login (loginWithPopup /
|
|
5023
|
+
// completeLoginFromRedirect) establishes a session WITHOUT touching the provider
|
|
5024
|
+
// singleton, so after a logout → hosted re-login cycle the provider is still null
|
|
5025
|
+
// and logging out the NEW session would otherwise throw "not initialized" at the
|
|
5026
|
+
// user. Rebuilding from initConfig is idempotent and cheap (same config key).
|
|
5027
|
+
if (!currentAuthProvider && initConfig) {
|
|
5028
|
+
currentAuthProvider = await getAuthProvider(initConfig);
|
|
5029
|
+
const coreConfig = await getConfig();
|
|
5030
|
+
coreConfig.authProvider = currentAuthProvider;
|
|
5031
|
+
coreConfig.authMethod = currentAuthMethod;
|
|
5032
|
+
setAuthProviderInstance(currentAuthProvider);
|
|
5033
|
+
}
|
|
4664
5034
|
if (!currentAuthProvider) {
|
|
4665
5035
|
throw new Error("Auth provider not initialized. Please call init() first.");
|
|
4666
5036
|
}
|
|
@@ -5000,54 +5370,6 @@ async function getIdToken() {
|
|
|
5000
5370
|
return getIdToken$1(false);
|
|
5001
5371
|
}
|
|
5002
5372
|
|
|
5003
|
-
/**
|
|
5004
|
-
* Extracts a human-readable error message from Solana transaction logs.
|
|
5005
|
-
*/
|
|
5006
|
-
function extractTransactionError(err, logMessages) {
|
|
5007
|
-
if (logMessages) {
|
|
5008
|
-
return JSON.stringify(logMessages);
|
|
5009
|
-
}
|
|
5010
|
-
if (err) {
|
|
5011
|
-
try {
|
|
5012
|
-
return JSON.stringify(err);
|
|
5013
|
-
}
|
|
5014
|
-
catch (_a) {
|
|
5015
|
-
return String(err);
|
|
5016
|
-
}
|
|
5017
|
-
}
|
|
5018
|
-
return 'Unknown transaction error';
|
|
5019
|
-
}
|
|
5020
|
-
/**
|
|
5021
|
-
* Polls getSignatureStatuses until the transaction is confirmed, then checks for errors.
|
|
5022
|
-
* Throws if the transaction failed on-chain. Returns parsed transaction info on success.
|
|
5023
|
-
*/
|
|
5024
|
-
async function confirmAndCheckTransaction(connection, signature) {
|
|
5025
|
-
var _a;
|
|
5026
|
-
const maxAttempts = 15;
|
|
5027
|
-
for (let i = 0; i < maxAttempts; i++) {
|
|
5028
|
-
const { value } = await connection.getSignatureStatuses([signature]);
|
|
5029
|
-
const status = value[0];
|
|
5030
|
-
if (status) {
|
|
5031
|
-
if (status.err) {
|
|
5032
|
-
const txInfo = await connection.getParsedTransaction(signature, {
|
|
5033
|
-
maxSupportedTransactionVersion: 0,
|
|
5034
|
-
commitment: 'confirmed'
|
|
5035
|
-
});
|
|
5036
|
-
const errorMessage = extractTransactionError(status.err, (_a = txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta) === null || _a === void 0 ? void 0 : _a.logMessages);
|
|
5037
|
-
throw new Error(`Transaction failed: ${errorMessage}`);
|
|
5038
|
-
}
|
|
5039
|
-
if (status.confirmationStatus === 'confirmed' || status.confirmationStatus === 'finalized') {
|
|
5040
|
-
return await connection.getParsedTransaction(signature, {
|
|
5041
|
-
maxSupportedTransactionVersion: 0,
|
|
5042
|
-
commitment: 'confirmed'
|
|
5043
|
-
});
|
|
5044
|
-
}
|
|
5045
|
-
}
|
|
5046
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
5047
|
-
}
|
|
5048
|
-
throw new Error('Transaction confirmation timeout');
|
|
5049
|
-
}
|
|
5050
|
-
|
|
5051
5373
|
/**
|
|
5052
5374
|
* Privy Expo Auth Provider — React Native implementation of AuthProvider.
|
|
5053
5375
|
*
|
|
@@ -5388,5 +5710,5 @@ class PrivyExpoProvider {
|
|
|
5388
5710
|
}
|
|
5389
5711
|
}
|
|
5390
5712
|
|
|
5391
|
-
export { OffchainAuthProvider, PrivyExpoProvider, completeLoginFromRedirect, completeLoginInPopup, deserializeTransaction, getAuthLoading, getAuthProvider, getCurrentUser, getIdToken, getPlatform, init, login, loginWithPopup, loginWithPrivy, loginWithRedirect, logout, onAuthLoadingChanged, onAuthStateChanged, setPlatform, signInAnonymously, useAuth, useQuery };
|
|
5713
|
+
export { OffchainAuthProvider, PrivyExpoProvider, completeLoginFromRedirect, completeLoginInPopup, defaultInjectedProvider, deserializeTransaction, getAuthLoading, getAuthProvider, getCurrentUser, getIdToken, getPlatform, init, login, loginWithPopup, loginWithPrivy, loginWithRedirect, logout, onAuthLoadingChanged, onAuthStateChanged, setPlatform, signInAnonymously, useAuth, useQuery };
|
|
5392
5714
|
//# sourceMappingURL=index.mjs.map
|