@bounded-sh/client 0.0.25 → 0.0.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/REACT_NATIVE.md +144 -0
  2. package/README.md +24 -18
  3. package/dist/auth/index.d.ts +18 -21
  4. package/dist/auth/oidc-auth.d.ts +7 -0
  5. package/dist/auth/providers/email-auth-provider.d.ts +8 -19
  6. package/dist/auth/providers/privy-expo-provider.d.ts +1 -1
  7. package/dist/global.d.ts +2 -2
  8. package/dist/index.d.ts +0 -3
  9. package/dist/index.js +88 -4617
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.mjs +98 -4621
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/index.native.d.ts +2 -2
  14. package/dist/index.native.js +5184 -78
  15. package/dist/index.native.js.map +1 -1
  16. package/dist/index.native.mjs +5095 -4
  17. package/dist/index.native.mjs.map +1 -1
  18. package/dist/platform.d.ts +1 -1
  19. package/package.json +8 -4
  20. package/dist/index.native-CcpKp_mg.mjs +0 -5738
  21. package/dist/index.native-CcpKp_mg.mjs.map +0 -1
  22. package/dist/index.native-DIw0cB5C.js +0 -5798
  23. package/dist/index.native-DIw0cB5C.js.map +0 -1
  24. package/dist/phantom-wallet-provider-Cagl3roP.js +0 -1452
  25. package/dist/phantom-wallet-provider-Cagl3roP.js.map +0 -1
  26. package/dist/phantom-wallet-provider-CyMav6HM.mjs +0 -1431
  27. package/dist/phantom-wallet-provider-CyMav6HM.mjs.map +0 -1
  28. package/dist/privy-wallet-provider-Cb1GUmOi.js +0 -949
  29. package/dist/privy-wallet-provider-Cb1GUmOi.js.map +0 -1
  30. package/dist/privy-wallet-provider-YR9Eisgl.mjs +0 -926
  31. package/dist/privy-wallet-provider-YR9Eisgl.mjs.map +0 -1
  32. package/dist/solana-mobile-wallet-provider-BEpjk4Sz.js +0 -1492
  33. package/dist/solana-mobile-wallet-provider-BEpjk4Sz.js.map +0 -1
  34. package/dist/solana-mobile-wallet-provider-DOSBGM8C.mjs +0 -1471
  35. package/dist/solana-mobile-wallet-provider-DOSBGM8C.mjs.map +0 -1
@@ -1,949 +0,0 @@
1
- 'use strict';
2
-
3
- var core = require('@bounded-sh/core');
4
- var index_native = require('./index.native-DIw0cB5C.js');
5
- var web3_js = require('@solana/web3.js');
6
- var anchor = require('@coral-xyz/anchor');
7
- var React = require('react');
8
- var ReactDOM = require('react-dom/client');
9
-
10
- function _interopNamespaceDefault(e) {
11
- var n = Object.create(null);
12
- if (e) {
13
- Object.keys(e).forEach(function (k) {
14
- if (k !== 'default') {
15
- var d = Object.getOwnPropertyDescriptor(e, k);
16
- Object.defineProperty(n, k, d.get ? d : {
17
- enumerable: true,
18
- get: function () { return e[k]; }
19
- });
20
- }
21
- });
22
- }
23
- n.default = e;
24
- return Object.freeze(n);
25
- }
26
-
27
- var anchor__namespace = /*#__PURE__*/_interopNamespaceDefault(anchor);
28
- var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
29
- var ReactDOM__namespace = /*#__PURE__*/_interopNamespaceDefault(ReactDOM);
30
-
31
- // @privy-io/react-auth(/solana) are OPTIONAL peer deps. They are loaded lazily
32
- // via dynamic import() rather than a static top-level import: a static import
33
- // would (a) in the ESM bundle still be a bare `import` the consumer resolves —
34
- // fine — but (b) in the CJS bundle become an eager top-level require() that
35
- // throws for any consumer who hasn't installed Privy (this module is pulled
36
- // into the entry via a static re-export). The lazy import keeps the browser
37
- // ESM bundle free of any runtime `require('@privy-io...')` AND lets a consumer
38
- // who never uses Privy load the package without it installed. Populated once
39
- // in `initialize()` (browser-only) before the Privy React tree renders.
40
- let privyImports;
41
- let privySolana;
42
- async function loadPrivyModules() {
43
- if (privyImports && privySolana)
44
- return;
45
- [privyImports, privySolana] = await Promise.all([
46
- import('@privy-io/react-auth'),
47
- import('@privy-io/react-auth/solana'),
48
- ]);
49
- }
50
- // @solana/kit is an OPTIONAL wallet-only dep, used only to build the Privy
51
- // Solana RPC transports. Loaded lazily (like the Privy SDKs) via dynamic
52
- // import() rather than a static top-level import: a static import is hoisted by
53
- // rollup into the entry chunk, forcing every consumer (including vanilla,
54
- // non-wallet web apps) to have @solana/kit installed and eagerly require()d.
55
- // Deferring it here keeps it out of the entry bundle.
56
- let solanaKit;
57
- async function loadSolanaKit() {
58
- if (!solanaKit) {
59
- solanaKit = await import('@solana/kit');
60
- }
61
- return solanaKit;
62
- }
63
- function requirePrivyWalletConfig(privyConfig) {
64
- if (!privyConfig || typeof privyConfig.appId !== 'string' || privyConfig.appId.trim() === '') {
65
- throw new Error('Privy auth requires config.privyConfig.appId; no default Privy app is used.');
66
- }
67
- if (!privyConfig.config || typeof privyConfig.config !== 'object') {
68
- throw new Error('Privy auth requires config.privyConfig.config for the app-scoped Privy provider.');
69
- }
70
- return {
71
- appId: privyConfig.appId,
72
- config: privyConfig.config,
73
- };
74
- }
75
- class PrivyWalletProvider {
76
- constructor(appName, appLogoUrl, privyConfig, networkUrl = null, configuredNetwork = null) {
77
- this.containerElement = null;
78
- this.chainId = null;
79
- this.root = null;
80
- this.privyMethods = null;
81
- this.pendingLogin = null;
82
- // Resolved Solana RPC URLs (computed in the constructor; consumed in
83
- // initialize() where @solana/kit is lazily loaded to build the transports).
84
- this.configuredRpcUrl = null;
85
- // This is used to store the pending transaction until the wallet is connected for workaround for the wallet not being connected after login completion
86
- this.pendingTransaction = null;
87
- // This is used to store pending signTransaction calls until the wallet is connected
88
- this.pendingSignTransaction = null;
89
- // This is used to store pending signMessage calls until the wallet is connected
90
- this.pendingSignMessage = null;
91
- // This is used to store pending signAndSubmitTransaction calls until the wallet is connected
92
- this.pendingSignAndSubmitTransaction = null;
93
- this.networkUrl = index_native.normalizeSolanaRpcUrl(networkUrl);
94
- this.configuredNetwork = configuredNetwork;
95
- if (typeof window === 'undefined') {
96
- throw new Error('PrivyWalletProvider can only be instantiated in a browser environment');
97
- }
98
- const requiredPrivyConfig = requirePrivyWalletConfig(privyConfig);
99
- if (PrivyWalletProvider.instance) {
100
- return PrivyWalletProvider.instance;
101
- }
102
- this.containerElement = null;
103
- this.root = null;
104
- this.privyMethods = null;
105
- this.privyConfig = requiredPrivyConfig;
106
- if (!this.privyConfig.config.appearance) {
107
- this.privyConfig.config.appearance = {};
108
- }
109
- if (appName != null && appName != '' && !this.privyConfig.config.appearance.landingHeader) {
110
- this.privyConfig.config.appearance.landingHeader = appName;
111
- }
112
- if (appLogoUrl != null && appLogoUrl != '' && !this.privyConfig.config.appearance.logo) {
113
- this.privyConfig.config.appearance.logo = appLogoUrl;
114
- }
115
- // (externalWallets connectors are configured in initialize() once the
116
- // Privy SDK is lazily loaded — see loadPrivyModules.)
117
- // Resolve Solana RPC URLs for v3. The @solana/kit transports are built
118
- // lazily in initialize() so a non-Privy consumer never needs @solana/kit.
119
- if (this.networkUrl || configuredNetwork) {
120
- this.configuredRpcUrl = index_native.resolveSolanaRpcUrl(this.networkUrl, configuredNetwork, "Privy Solana RPC");
121
- }
122
- if (configuredNetwork) {
123
- this.chainId = index_native.resolveSolanaWalletStandardChain(configuredNetwork, "Privy Solana transaction");
124
- }
125
- const existingProviders = document.querySelectorAll('[data-privy-provider]');
126
- existingProviders.forEach(el => el.remove());
127
- // Fire-and-forget: initialize() lazily loads the Privy SDK then renders
128
- // the hidden React tree. privyMethods stays null until that render runs,
129
- // which the login/connect methods already wait for. Surface a clear error
130
- // if the optional @privy-io/react-auth peer dep isn't installed.
131
- this.initialize().catch((err) => {
132
- console.error('PrivyWalletProvider: failed to load @privy-io/react-auth — ensure it is installed to use Privy login.', err);
133
- });
134
- // Assign this instance to the static instance property
135
- PrivyWalletProvider.instance = this;
136
- }
137
- // Optional: Provide a static method to get the instance
138
- static getInstance(appName, appLogoUrl, privyConfig, networkUrl = null, configuredNetwork = null) {
139
- if (!PrivyWalletProvider.instance) {
140
- new PrivyWalletProvider(appName, appLogoUrl, privyConfig, networkUrl, configuredNetwork);
141
- }
142
- return PrivyWalletProvider.instance;
143
- }
144
- async initialize() {
145
- // Lazily load the Privy SDK (browser-only) before building the React tree.
146
- await loadPrivyModules();
147
- // Build the Solana RPC transports now that we're on the async path, so
148
- // @solana/kit can be lazily imported (kept out of the entry bundle).
149
- const { createSolanaRpc, createSolanaRpcSubscriptions } = await loadSolanaKit();
150
- if (this.configuredRpcUrl && this.chainId && !this.privyConfig.config.solana) {
151
- this.privyConfig.config.solana = {};
152
- }
153
- if (this.configuredRpcUrl && this.chainId) {
154
- this.privyConfig.config.solana.rpcs = {
155
- [this.chainId]: {
156
- rpc: createSolanaRpc(this.configuredRpcUrl),
157
- rpcSubscriptions: createSolanaRpcSubscriptions(this.configuredRpcUrl.replace('https://', 'wss://'))
158
- }
159
- };
160
- }
161
- // Ensure externalWallets connectors are always configured — required for
162
- // useWallets().ready to resolve even when no browser extension is present.
163
- if (!this.privyConfig.config.externalWallets && privySolana) {
164
- this.privyConfig.config.externalWallets = {
165
- solana: { connectors: privySolana.toSolanaWalletConnectors() }
166
- };
167
- }
168
- if (!this.containerElement) {
169
- this.containerElement = document.createElement('div');
170
- this.containerElement.setAttribute('data-privy-provider', 'true');
171
- document.body.appendChild(this.containerElement);
172
- const that = this;
173
- const PrivyComponent = () => {
174
- const privy = privyImports.usePrivy();
175
- const useOAuthTokens = privyImports.useOAuthTokens();
176
- const useFundWalletSolana = privySolana.useFundWallet();
177
- const useSendTransactionSolana = privySolana.useSignAndSendTransaction();
178
- const { signTransaction } = privySolana.useSignTransaction();
179
- const { signMessage: signMessageHook } = privySolana.useSignMessage();
180
- const { ready: walletReady, wallets } = privySolana.useWallets();
181
- const { createWallet } = privySolana.useCreateWallet();
182
- const { exportWallet } = privySolana.useExportWallet();
183
- const useSolanaWallets = { createWallet, exportWallet, ready: walletReady, wallets };
184
- const useIdentityToken = privyImports.useIdentityToken();
185
- const { connectWallet } = privyImports.useConnectWallet({
186
- onSuccess: async ({ wallet }) => {
187
- await that.createSession(wallet.address, await privy.getAccessToken(), useIdentityToken.identityToken);
188
- // If there's a pending transaction, execute it now
189
- if (that.pendingTransaction) {
190
- const { evmTransactionData, solTransactionData, options, resolve, reject } = that.pendingTransaction;
191
- try {
192
- const result = await that.runTransaction(evmTransactionData, solTransactionData, options);
193
- resolve(result);
194
- }
195
- catch (error) {
196
- reject(error);
197
- }
198
- that.pendingTransaction = null;
199
- }
200
- // If there's a pending signTransaction, execute it now
201
- if (that.pendingSignTransaction) {
202
- const { transaction, resolve, reject } = that.pendingSignTransaction;
203
- try {
204
- const result = await that.signTransaction(transaction);
205
- resolve(result);
206
- }
207
- catch (error) {
208
- reject(error);
209
- }
210
- that.pendingSignTransaction = null;
211
- }
212
- // If there's a pending signMessage, execute it now
213
- if (that.pendingSignMessage) {
214
- const { message, resolve, reject } = that.pendingSignMessage;
215
- try {
216
- const result = await that.signMessage(message);
217
- resolve(result);
218
- }
219
- catch (error) {
220
- reject(error);
221
- }
222
- that.pendingSignMessage = null;
223
- }
224
- // If there's a pending signAndSubmitTransaction, execute it now
225
- if (that.pendingSignAndSubmitTransaction) {
226
- const { transaction, feePayer, resolve, reject } = that.pendingSignAndSubmitTransaction;
227
- try {
228
- const result = await that.signAndSubmitTransaction(transaction, feePayer);
229
- resolve(result);
230
- }
231
- catch (error) {
232
- reject(error);
233
- }
234
- that.pendingSignAndSubmitTransaction = null;
235
- }
236
- },
237
- onError: (error) => {
238
- // Only log errors that aren't user-initiated cancellations
239
- if (error !== 'exited_auth_flow' && (error === null || error === void 0 ? void 0 : error.message) !== 'exited_auth_flow') {
240
- console.error('Wallet connection error:', error);
241
- }
242
- if (that.pendingTransaction) {
243
- that.pendingTransaction.reject(error);
244
- that.pendingTransaction = null;
245
- }
246
- if (that.pendingSignTransaction) {
247
- that.pendingSignTransaction.reject(error);
248
- that.pendingSignTransaction = null;
249
- }
250
- if (that.pendingSignMessage) {
251
- that.pendingSignMessage.reject(error);
252
- that.pendingSignMessage = null;
253
- }
254
- if (that.pendingSignAndSubmitTransaction) {
255
- that.pendingSignAndSubmitTransaction.reject(error);
256
- that.pendingSignAndSubmitTransaction = null;
257
- }
258
- }
259
- });
260
- const { login } = privyImports.useLogin({
261
- onComplete: async ({ user }) => {
262
- var _a;
263
- // This is a hack to indicate to the app that privy login is not complete
264
- // @ts-ignore
265
- window.runningPrivyOnComplete = true;
266
- if (!user) {
267
- core.getActiveSessionManager().clearSession();
268
- return;
269
- }
270
- const solanaLinkedAccounts = user.linkedAccounts.filter((account) => account.chainType === 'solana');
271
- const sortedLinkedAccounts = solanaLinkedAccounts.sort((a, b) => new Date(b.latestVerifiedAt).getTime() - new Date(a.latestVerifiedAt).getTime());
272
- let finalAddress = (_a = sortedLinkedAccounts[0]) === null || _a === void 0 ? void 0 : _a.address;
273
- if (!finalAddress) {
274
- const solanaWallet = await createWallet();
275
- finalAddress = solanaWallet.address;
276
- core.getActiveSessionManager().clearSession();
277
- return;
278
- }
279
- const session = await core.getActiveSessionManager().getSession();
280
- if (!session || finalAddress !== session.address) {
281
- try {
282
- const accessToken = await privy.getAccessToken();
283
- const idToken = useIdentityToken.identityToken;
284
- await that.createSession(finalAddress, accessToken, idToken);
285
- }
286
- catch (error) {
287
- console.error('Error creating session:', error);
288
- }
289
- }
290
- // @ts-ignore
291
- window.runningPrivyOnComplete = false;
292
- index_native.setCurrentUser({ address: finalAddress, provider: that });
293
- if (that.pendingLogin) {
294
- that.pendingLogin.resolve({ address: finalAddress, provider: that });
295
- that.pendingLogin = null;
296
- }
297
- },
298
- onError: (error) => {
299
- // Only log errors that aren't user-initiated cancellations
300
- if (error !== 'exited_auth_flow' && (error === null || error === void 0 ? void 0 : error.message) !== 'exited_auth_flow') {
301
- console.error('Login error:', error);
302
- }
303
- if (that.pendingLogin) {
304
- that.pendingLogin.reject(error);
305
- that.pendingLogin = null;
306
- }
307
- }
308
- });
309
- const { logout } = privyImports.useLogout({
310
- onSuccess: () => {
311
- core.getActiveSessionManager().clearSession();
312
- index_native.setCurrentUser(null);
313
- }
314
- });
315
- React__namespace.useEffect(() => {
316
- if (privy.ready) {
317
- that.privyMethods = {
318
- ready: privy.ready,
319
- walletReady: walletReady,
320
- authenticated: privy.authenticated,
321
- wallets,
322
- login,
323
- logout,
324
- connectWallet,
325
- getAccessToken: privy.getAccessToken,
326
- identityToken: useIdentityToken.identityToken,
327
- usePrivy: privy,
328
- useOAuthTokens: useOAuthTokens,
329
- useFundWalletSolana: useFundWalletSolana,
330
- useSendTransactionSolana: useSendTransactionSolana,
331
- useSolanaWallets: useSolanaWallets,
332
- signTransaction: signTransaction,
333
- signMessage: signMessageHook,
334
- };
335
- }
336
- }, [privy.ready, privy.authenticated, wallets, login, logout, walletReady]);
337
- return null;
338
- };
339
- const FinalPrivyComponent = () => {
340
- if (typeof window === 'undefined') {
341
- return null;
342
- }
343
- return React__namespace.createElement(privyImports.PrivyProvider, {
344
- appId: this.privyConfig.appId,
345
- config: this.privyConfig.config,
346
- children: React__namespace.createElement(PrivyComponent)
347
- });
348
- };
349
- this.root = ReactDOM__namespace.createRoot(this.containerElement);
350
- this.root.render(React__namespace.createElement(FinalPrivyComponent));
351
- }
352
- }
353
- async login() {
354
- var _a, _b;
355
- await this.ensureReady();
356
- // Check if we have a valid session that matches an authenticated wallet
357
- const session = await core.getActiveSessionManager().getSession();
358
- if (((_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.authenticated) && ((_b = this.privyMethods.wallets) === null || _b === void 0 ? void 0 : _b.length) > 0 && session) {
359
- // Find the wallet matching the session
360
- const matchingWallet = this.privyMethods.wallets.find((wallet) => wallet.address === session.address);
361
- if (matchingWallet) {
362
- // Valid session with matching wallet, return immediately
363
- index_native.setCurrentUser({ address: matchingWallet.address, provider: this });
364
- return {
365
- address: matchingWallet.address,
366
- provider: this
367
- };
368
- }
369
- // Session exists but doesn't match any connected wallet
370
- // This can happen after wallet switching - force fresh login
371
- console.log('Session wallet mismatch detected, forcing fresh login flow');
372
- }
373
- // If no valid session or wallet mismatch, force a fresh login flow
374
- // This ensures the user can select the correct wallet, especially after logout
375
- if (this.pendingLogin) {
376
- return new Promise((resolve, reject) => {
377
- this.pendingLogin.resolve = resolve;
378
- this.pendingLogin.reject = reject;
379
- });
380
- }
381
- return new Promise((resolve, reject) => {
382
- this.pendingLogin = { resolve, reject };
383
- // open Privy modal to let user select/verify wallet
384
- this.privyMethods.login();
385
- // safety timeout
386
- setTimeout(() => {
387
- if (this.pendingLogin) {
388
- this.pendingLogin.reject(new Error("Login timed out"));
389
- this.pendingLogin = null;
390
- }
391
- }, 180000);
392
- });
393
- }
394
- async getNativeMethods() {
395
- var _a;
396
- await this.ensureReady();
397
- return (_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.usePrivy;
398
- }
399
- async logout() {
400
- await this.ensureReady();
401
- await this.privyMethods.logout();
402
- }
403
- async runTransaction(_evmTransactionData, solTransactionData, options) {
404
- var _a, _b, _c;
405
- await this.ensureReady({ waitForWallets: true });
406
- let session = await core.getActiveSessionManager().getSession();
407
- let sessionAddress = session === null || session === void 0 ? void 0 : session.address;
408
- let privyWallets = (_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.wallets;
409
- let privyWallet = privyWallets === null || privyWallets === void 0 ? void 0 : privyWallets.find((wallet) => wallet.address === sessionAddress);
410
- // If wallet not found yet, it may be an embedded wallet (email login) that hasn't
411
- // appeared in the wallets array due to React state timing. Wait for it before
412
- // falling back to connectWallet() which shows an unwanted wallet selection modal.
413
- if (!privyWallets || privyWallets.length === 0 || !privyWallet) {
414
- if (((_b = this.privyMethods) === null || _b === void 0 ? void 0 : _b.authenticated) && sessionAddress) {
415
- privyWallet = await this.waitForMatchingWallet(sessionAddress);
416
- }
417
- }
418
- if (!privyWallet) {
419
- // If there's already a pending transaction, throw an error to prevent overlapping calls
420
- if (this.pendingTransaction) {
421
- throw new Error("Oops... something went wrong. Please try again.");
422
- }
423
- // Create a promise to wait for the transaction result
424
- return new Promise((resolve, reject) => {
425
- this.pendingTransaction = {
426
- resolve,
427
- reject,
428
- evmTransactionData: _evmTransactionData,
429
- solTransactionData,
430
- options
431
- };
432
- this.privyMethods.connectWallet();
433
- // Set a timeout to reject the promise if connection takes too long
434
- setTimeout(() => {
435
- if (this.pendingTransaction) {
436
- this.pendingTransaction.reject(new Error("Wallet connection timed out"));
437
- this.pendingTransaction = null;
438
- }
439
- }, 30000); // 30 seconds timeout
440
- });
441
- }
442
- // Proceed with the transaction using privyWallet
443
- const wallet = privyWallet;
444
- if (solTransactionData == null) {
445
- throw new Error("Solana transaction data is required");
446
- }
447
- const rpcUrl = this.getRpcUrl(solTransactionData.network);
448
- const connection = new web3_js.Connection(rpcUrl, "confirmed");
449
- const remainingAccounts = core.convertRemainingAccounts(solTransactionData.txArgs[0].remainingAccounts);
450
- const app_id = solTransactionData.appId;
451
- if (!app_id) {
452
- throw new Error("App ID is required");
453
- }
454
- const anchorProvider = new anchor__namespace.AnchorProvider(connection, wallet.provider, anchor__namespace.AnchorProvider.defaultOptions());
455
- const finalDeduped = [];
456
- for (const acc of remainingAccounts) {
457
- const existing = finalDeduped.find((d) => d.pubkey.equals(acc.pubkey));
458
- if (existing) {
459
- existing.isSigner = existing.isSigner || acc.isSigner;
460
- existing.isWritable = existing.isWritable || acc.isWritable;
461
- }
462
- else {
463
- finalDeduped.push(acc);
464
- }
465
- }
466
- let tx;
467
- let blockhash;
468
- let lastValidBlockHeight;
469
- if (solTransactionData.signedTransaction) {
470
- // Server already set the blockhash and co-signed — do NOT overwrite
471
- // the blockhash or it will invalidate the server's signature.
472
- tx = web3_js.VersionedTransaction.deserialize(index_native.bufferExports.Buffer.from(solTransactionData.signedTransaction, 'base64'));
473
- // Extract the blockhash that was baked into the signed message
474
- blockhash = tx.message.recentBlockhash;
475
- const latestBlockhash = await connection.getLatestBlockhash('confirmed');
476
- lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
477
- }
478
- else {
479
- const result = await core.buildSetDocumentsTransaction(connection, solTransactionData.txArgs[0].idl, anchorProvider, new web3_js.PublicKey(wallet.address), { app_id, documents: solTransactionData.txArgs[0].setDocumentData, delete_paths: solTransactionData.txArgs[0].deletePaths, txData: solTransactionData.txArgs[0].txData }, finalDeduped, solTransactionData.lutKey, solTransactionData.preInstructions, false, solTransactionData.additionalLutAddresses);
480
- tx = result.tx;
481
- blockhash = result.blockhash;
482
- lastValidBlockHeight = result.lastValidBlockHeight;
483
- }
484
- // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
485
- const isLegacyTx = 'recentBlockhash' in tx && !('message' in tx && 'staticAccountKeys' in tx.message);
486
- if (isLegacyTx) {
487
- tx.recentBlockhash = blockhash;
488
- tx.lastValidBlockHeight = lastValidBlockHeight;
489
- }
490
- else {
491
- tx.message.recentBlockhash = blockhash;
492
- }
493
- try {
494
- if ((options === null || options === void 0 ? void 0 : options.shouldSubmitTx) === false) {
495
- // Just sign, don't submit - return raw signed bytes (same as original runTransaction)
496
- const signedTx = await this.signTransactionRaw(tx, privyWallet, solTransactionData.network);
497
- return {
498
- signedTransaction: signedTx, // Raw Uint8Array from Privy
499
- blockNumber: 0,
500
- gasUsed: "0",
501
- data: ""
502
- };
503
- }
504
- // Sign and submit using shared helper
505
- const { signature, txInfo } = await this.signAndSubmitInternal(tx, privyWallet, rpcUrl, connection, solTransactionData.network);
506
- return {
507
- transactionSignature: signature,
508
- blockNumber: (txInfo === null || txInfo === void 0 ? void 0 : txInfo.slot) || 0,
509
- gasUsed: ((_c = txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta) === null || _c === void 0 ? void 0 : _c.fee.toString()) || '0',
510
- data: txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta,
511
- };
512
- }
513
- catch (err) {
514
- console.error(err);
515
- throw err;
516
- }
517
- }
518
- /**
519
- * Signs a Solana transaction without submitting it.
520
- *
521
- * This method handles blockhash automatically if not set - you do NOT need to
522
- * set recentBlockhash on the transaction before calling this method.
523
- * The network/RPC URL is derived from the provider's configuration (set during initialization).
524
- *
525
- * @param transaction - The transaction to sign (Transaction or VersionedTransaction)
526
- * @returns The signed transaction
527
- */
528
- async signTransaction(transaction) {
529
- var _a, _b;
530
- await this.ensureReady({ waitForWallets: true });
531
- let privyWallets = (_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.wallets;
532
- let session = await core.getActiveSessionManager().getSession();
533
- let sessionAddress = session === null || session === void 0 ? void 0 : session.address;
534
- let privyWallet = privyWallets === null || privyWallets === void 0 ? void 0 : privyWallets.find((wallet) => wallet.address === sessionAddress);
535
- // If there's already a pending sign transaction, throw an error to prevent overlapping calls
536
- if (this.pendingSignTransaction) {
537
- throw new Error("Oops... something went wrong. Please try again.");
538
- }
539
- // If wallet not found yet, it may be an embedded wallet (email login) that hasn't
540
- // appeared in the wallets array due to React state timing. Wait for it before
541
- // falling back to connectWallet() which shows an unwanted wallet selection modal.
542
- if (!privyWallets || privyWallets.length === 0 || !privyWallet) {
543
- if (((_b = this.privyMethods) === null || _b === void 0 ? void 0 : _b.authenticated) && sessionAddress) {
544
- privyWallet = await this.waitForMatchingWallet(sessionAddress);
545
- }
546
- }
547
- // If still no wallet after waiting, trigger connection and queue the signing
548
- if (!privyWallet) {
549
- return new Promise((resolve, reject) => {
550
- this.pendingSignTransaction = {
551
- resolve,
552
- reject,
553
- transaction
554
- };
555
- this.privyMethods.connectWallet();
556
- // Set a timeout to reject the promise if connection takes too long
557
- setTimeout(() => {
558
- if (this.pendingSignTransaction) {
559
- this.pendingSignTransaction.reject(new Error("Wallet connection timed out"));
560
- this.pendingSignTransaction = null;
561
- }
562
- }, 30000); // 30 seconds timeout
563
- });
564
- }
565
- // Privy requires serialized transaction bytes, which requires a blockhash.
566
- // If the transaction doesn't have one, get a fresh blockhash and set it.
567
- // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
568
- const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
569
- if (isLegacyTransaction) {
570
- const legacyTx = transaction;
571
- if (!legacyTx.recentBlockhash) {
572
- const rpcUrl = this.getRpcUrl();
573
- const connection = new web3_js.Connection(rpcUrl, 'confirmed');
574
- const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
575
- legacyTx.recentBlockhash = blockhash;
576
- legacyTx.lastValidBlockHeight = lastValidBlockHeight;
577
- }
578
- // Set feePayer if not already set
579
- if (!legacyTx.feePayer) {
580
- legacyTx.feePayer = new web3_js.PublicKey(privyWallet.address);
581
- }
582
- }
583
- else {
584
- // VersionedTransaction
585
- const versionedTx = transaction;
586
- if (!versionedTx.message.recentBlockhash) {
587
- const rpcUrl = this.getRpcUrl();
588
- const connection = new web3_js.Connection(rpcUrl, 'confirmed');
589
- const { blockhash } = await connection.getLatestBlockhash('confirmed');
590
- versionedTx.message.recentBlockhash = blockhash;
591
- }
592
- }
593
- // Sign using raw method, then deserialize for the public API
594
- const signedTxRaw = await this.signTransactionRaw(transaction, privyWallet);
595
- return this.deserializeSignedTransaction(signedTxRaw);
596
- }
597
- /**
598
- * Signs and submits a Solana transaction to the network.
599
- *
600
- * This method handles blockhash and transaction confirmation automatically - you do NOT need to
601
- * set recentBlockhash or lastValidBlockHeight on the transaction before calling this method.
602
- * The network/RPC URL is derived from the provider's configuration (set during initialization).
603
- *
604
- * @param transaction - The transaction to sign and submit (Transaction or VersionedTransaction)
605
- * @param feePayer - Optional fee payer public key. If not provided and the transaction doesn't
606
- * already have a feePayer set, the connected wallet address will be used.
607
- * Useful for co-signing scenarios where a different account pays the fees.
608
- * @returns The transaction signature
609
- */
610
- async signAndSubmitTransaction(transaction, feePayer) {
611
- var _a, _b;
612
- await this.ensureReady({ waitForWallets: true });
613
- let privyWallets = (_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.wallets;
614
- let session = await core.getActiveSessionManager().getSession();
615
- let sessionAddress = session === null || session === void 0 ? void 0 : session.address;
616
- let privyWallet = privyWallets === null || privyWallets === void 0 ? void 0 : privyWallets.find((wallet) => wallet.address === sessionAddress);
617
- // If there's already a pending signAndSubmitTransaction, throw an error to prevent overlapping calls
618
- if (this.pendingSignAndSubmitTransaction) {
619
- throw new Error("Oops... something went wrong. Please try again.");
620
- }
621
- // If wallet not found yet, it may be an embedded wallet (email login) that hasn't
622
- // appeared in the wallets array due to React state timing. Wait for it before
623
- // falling back to connectWallet() which shows an unwanted wallet selection modal.
624
- if (!privyWallets || privyWallets.length === 0 || !privyWallet) {
625
- if (((_b = this.privyMethods) === null || _b === void 0 ? void 0 : _b.authenticated) && sessionAddress) {
626
- privyWallet = await this.waitForMatchingWallet(sessionAddress);
627
- }
628
- }
629
- // If still no wallet after waiting, trigger connection and queue the signing
630
- if (!privyWallet) {
631
- return new Promise((resolve, reject) => {
632
- this.pendingSignAndSubmitTransaction = {
633
- resolve,
634
- reject,
635
- transaction,
636
- feePayer
637
- };
638
- this.privyMethods.connectWallet();
639
- // Set a timeout to reject the promise if connection takes too long
640
- setTimeout(() => {
641
- if (this.pendingSignAndSubmitTransaction) {
642
- this.pendingSignAndSubmitTransaction.reject(new Error("Wallet connection timed out"));
643
- this.pendingSignAndSubmitTransaction = null;
644
- }
645
- }, 30000); // 30 seconds timeout
646
- });
647
- }
648
- // Get RPC URL and create connection
649
- const rpcUrl = this.getRpcUrl();
650
- const connection = new web3_js.Connection(rpcUrl, 'confirmed');
651
- // Get fresh blockhash and set it on the transaction before signing
652
- const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
653
- // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
654
- const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
655
- if (isLegacyTransaction) {
656
- const legacyTx = transaction;
657
- legacyTx.recentBlockhash = blockhash;
658
- legacyTx.lastValidBlockHeight = lastValidBlockHeight;
659
- // Set feePayer if not already set
660
- if (!legacyTx.feePayer) {
661
- legacyTx.feePayer = feePayer !== null && feePayer !== void 0 ? feePayer : new web3_js.PublicKey(privyWallet.address);
662
- }
663
- }
664
- else {
665
- // VersionedTransaction
666
- const versionedTx = transaction;
667
- versionedTx.message.recentBlockhash = blockhash;
668
- // Note: VersionedTransaction feePayer is set in the message at creation time
669
- // and cannot be modified after creation
670
- }
671
- // Use shared sign and submit logic
672
- const { signature } = await this.signAndSubmitInternal(transaction, privyWallet, rpcUrl, connection);
673
- return signature;
674
- }
675
- // ============ Private Helpers ============
676
- getRpcUrl(network) {
677
- return index_native.resolveSolanaRpcUrl(this.networkUrl, network !== null && network !== void 0 ? network : this.configuredNetwork, "Privy Solana transaction");
678
- }
679
- getChainId(network) {
680
- if (network) {
681
- return index_native.resolveSolanaWalletStandardChain(network, "Privy Solana transaction");
682
- }
683
- if (this.chainId)
684
- return this.chainId;
685
- if (this.configuredNetwork) {
686
- return index_native.resolveSolanaWalletStandardChain(this.configuredNetwork, "Privy Solana transaction");
687
- }
688
- throw new Error("Privy Solana transaction requires config.chain as solana_devnet, solana_mainnet, or surfnet.");
689
- }
690
- /**
691
- * Internal sign transaction - serializes and signs via Privy
692
- * Returns the raw result from Privy (Uint8Array)
693
- * This mirrors exactly what runTransaction was doing
694
- */
695
- async signTransactionRaw(transaction, privyWallet, network) {
696
- var _a;
697
- // Serialize the transaction
698
- // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
699
- const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
700
- let serializedForSign;
701
- if (isLegacyTransaction) {
702
- serializedForSign = transaction.serialize({ requireAllSignatures: false, verifySignatures: false });
703
- }
704
- else {
705
- serializedForSign = transaction.serialize();
706
- }
707
- // Sign via Privy - returns { signedTransaction: Uint8Array }
708
- const result = await ((_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.signTransaction({
709
- transaction: serializedForSign,
710
- wallet: privyWallet,
711
- chain: this.getChainId(network)
712
- }));
713
- // Privy returns { signedTransaction: Uint8Array }, unwrap it
714
- const signedTx = (result === null || result === void 0 ? void 0 : result.signedTransaction) || result;
715
- return signedTx;
716
- }
717
- /**
718
- * Deserialize a signed transaction from Uint8Array to Transaction object
719
- */
720
- deserializeSignedTransaction(signedTxRaw) {
721
- // Handle different formats Privy might return
722
- let signedTx;
723
- if (signedTxRaw instanceof Uint8Array) {
724
- signedTx = signedTxRaw;
725
- }
726
- else if (Array.isArray(signedTxRaw)) {
727
- signedTx = new Uint8Array(signedTxRaw);
728
- }
729
- else if (signedTxRaw && typeof signedTxRaw === 'object' && 'signedTransaction' in signedTxRaw) {
730
- // Privy might wrap the result
731
- signedTx = signedTxRaw.signedTransaction instanceof Uint8Array
732
- ? signedTxRaw.signedTransaction
733
- : new Uint8Array(signedTxRaw.signedTransaction);
734
- }
735
- else if (index_native.bufferExports.Buffer.isBuffer(signedTxRaw)) {
736
- signedTx = new Uint8Array(signedTxRaw);
737
- }
738
- else {
739
- throw new Error(`Unexpected signed transaction format: ${typeof signedTxRaw}`);
740
- }
741
- // Try to deserialize as VersionedTransaction first, fall back to legacy Transaction
742
- try {
743
- return web3_js.VersionedTransaction.deserialize(signedTx);
744
- }
745
- catch (_a) {
746
- return web3_js.Transaction.from(signedTx);
747
- }
748
- }
749
- /**
750
- * Internal sign and submit - handles Surfnet vs non-Surfnet logic
751
- * This is the core submission logic used by both signAndSubmitTransaction and runTransaction
752
- *
753
- * For Surfnet: sign with signTransactionRaw, then sendRawTransaction
754
- * For non-Surfnet: use Privy's signAndSendTransaction (combined operation)
755
- */
756
- async signAndSubmitInternal(transaction, privyWallet, rpcUrl, connection, network) {
757
- var _a;
758
- const isSurfnet = rpcUrl === index_native.SURFNET_RPC_URL;
759
- let signature;
760
- if (isSurfnet) {
761
- // For Surfnet: sign with signTransactionRaw, then sendRawTransaction
762
- const signedTx = await this.signTransactionRaw(transaction, privyWallet, network);
763
- signature = await connection.sendRawTransaction(signedTx);
764
- }
765
- else {
766
- // For non-Surfnet: use Privy's combined signAndSendTransaction
767
- // Serialize the transaction for Privy API
768
- // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
769
- const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
770
- let serializedTx;
771
- if (isLegacyTransaction) {
772
- serializedTx = transaction.serialize({ requireAllSignatures: false, verifySignatures: false });
773
- }
774
- else {
775
- serializedTx = transaction.serialize();
776
- }
777
- const result = await ((_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.useSendTransactionSolana.signAndSendTransaction({
778
- transaction: serializedTx,
779
- wallet: privyWallet,
780
- chain: this.getChainId(network)
781
- }));
782
- // Handle case where signature might be bytes instead of string
783
- const rawSig = result.signature;
784
- if (rawSig instanceof Uint8Array || Array.isArray(rawSig)) {
785
- signature = index_native.bs58.encode(rawSig instanceof Uint8Array ? rawSig : new Uint8Array(rawSig));
786
- }
787
- else {
788
- signature = rawSig;
789
- }
790
- }
791
- const txInfo = await index_native.confirmAndCheckTransaction(connection, signature);
792
- return { signature, txInfo };
793
- }
794
- async signMessage(message) {
795
- var _a, _b, _c;
796
- await this.ensureReady({ waitForWallets: true });
797
- const session = await core.getActiveSessionManager().getSession();
798
- let sessionAddress = session === null || session === void 0 ? void 0 : session.address;
799
- // If there's already a pending sign message, throw an error to prevent overlapping calls
800
- if (this.pendingSignMessage) {
801
- throw new Error("Oops... something went wrong. Please try again.");
802
- }
803
- // If no wallets connected yet, it may be an embedded wallet (email login) that hasn't
804
- // appeared in the wallets array due to React state timing. Wait for it before
805
- // falling back to connectWallet() which shows an unwanted wallet selection modal.
806
- if (!((_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.wallets) || this.privyMethods.wallets.length === 0) {
807
- if (((_b = this.privyMethods) === null || _b === void 0 ? void 0 : _b.authenticated) && sessionAddress) {
808
- const matchedWallet = await this.waitForMatchingWallet(sessionAddress);
809
- if (!matchedWallet) {
810
- return new Promise((resolve, reject) => {
811
- this.pendingSignMessage = {
812
- resolve,
813
- reject,
814
- message
815
- };
816
- this.privyMethods.connectWallet();
817
- // Set a timeout to reject the promise if connection takes too long
818
- setTimeout(() => {
819
- if (this.pendingSignMessage) {
820
- this.pendingSignMessage.reject(new Error("Wallet connection timed out"));
821
- this.pendingSignMessage = null;
822
- }
823
- }, 30000); // 30 seconds timeout
824
- });
825
- }
826
- }
827
- else {
828
- return new Promise((resolve, reject) => {
829
- this.pendingSignMessage = {
830
- resolve,
831
- reject,
832
- message
833
- };
834
- this.privyMethods.connectWallet();
835
- // Set a timeout to reject the promise if connection takes too long
836
- setTimeout(() => {
837
- if (this.pendingSignMessage) {
838
- this.pendingSignMessage.reject(new Error("Wallet connection timed out"));
839
- this.pendingSignMessage = null;
840
- }
841
- }, 30000); // 30 seconds timeout
842
- });
843
- }
844
- }
845
- let privyWallet = this.privyMethods.wallets.find((wallet) => wallet.address === sessionAddress);
846
- if (!privyWallet) {
847
- throw new Error('Active Privy wallets do not include the authenticated session wallet; please log in again.');
848
- }
849
- // Use the Privy signMessage hook for Solana wallets
850
- // The message needs to be passed as a Uint8Array
851
- const messageBytes = index_native.getPlatform().textEncode(message);
852
- const result = await ((_c = this.privyMethods) === null || _c === void 0 ? void 0 : _c.signMessage({
853
- message: messageBytes,
854
- wallet: privyWallet,
855
- }));
856
- // The signature is returned as a Uint8Array, encode it as base58 (standard Solana format)
857
- const signatureBytes = (result === null || result === void 0 ? void 0 : result.signature) || result;
858
- const bs58 = await Promise.resolve().then(function () { return require('./index.native-DIw0cB5C.js'); }).then(function (n) { return n.index; });
859
- return bs58.default.encode(signatureBytes);
860
- }
861
- async restoreSession() {
862
- const session = await core.getActiveSessionManager().getSession();
863
- if (session) {
864
- return { provider: this, address: session.address };
865
- }
866
- else {
867
- return null;
868
- }
869
- }
870
- // NOTE: accessToken/idToken are accepted for backwards-compat with existing
871
- // call sites but are no longer used. The session is minted by having the Privy
872
- // Solana wallet SIGN the canonical SIWS challenge (the same wallet-signature
873
- // path Phantom/MWA/guest use), so the bounded /session issuer needs no
874
- // Privy-specific token verification — it arrives as a Solana signature and is
875
- // recorded server-side as authMethod 'phantom'.
876
- async createSession(address, _accessToken, _idToken) {
877
- var _a, _b, _c, _d;
878
- const privyWallet = (_b = (_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.wallets) === null || _b === void 0 ? void 0 : _b.find((w) => w.address === address);
879
- if (!privyWallet) {
880
- throw new Error('No Privy Solana wallet matching the requested session address is available.');
881
- }
882
- const nonce = await core.genAuthNonce();
883
- const message = await core.genSolanaMessage(address, nonce);
884
- const messageBytes = index_native.getPlatform().textEncode(message);
885
- // Low-level Privy sign hook — signs WITHOUT touching the session (the public
886
- // signMessage() bootstraps sessions, which would recurse here).
887
- const signResult = await ((_c = this.privyMethods) === null || _c === void 0 ? void 0 : _c.signMessage({
888
- message: messageBytes,
889
- wallet: privyWallet,
890
- }));
891
- const signatureBytes = (_d = signResult === null || signResult === void 0 ? void 0 : signResult.signature) !== null && _d !== void 0 ? _d : signResult;
892
- // base64-encoded detached signature (matches Phantom + guest providers).
893
- const signature = index_native.bufferExports.Buffer.from(signatureBytes).toString('base64');
894
- const createSessionResult = await core.createSessionWithSignature(address, message, signature);
895
- if (createSessionResult) {
896
- await core.getActiveSessionManager().storeSession(address, createSessionResult.accessToken, createSessionResult.idToken, createSessionResult.refreshToken);
897
- }
898
- }
899
- /**
900
- * Waits for a wallet matching the session address to appear in the wallets array.
901
- * This handles the timing gap where Privy's embedded wallet (created for email login users)
902
- * may not yet be in the useWallets() array when signTransaction is called immediately after login.
903
- */
904
- async waitForMatchingWallet(sessionAddress, timeoutMs = 10000) {
905
- var _a;
906
- const startTime = Date.now();
907
- while (Date.now() - startTime < timeoutMs) {
908
- const wallets = (_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.wallets;
909
- if (wallets && wallets.length > 0) {
910
- const wallet = wallets.find((w) => w.address === sessionAddress);
911
- if (wallet)
912
- return wallet;
913
- }
914
- await new Promise(resolve => setTimeout(resolve, 200));
915
- }
916
- return null;
917
- }
918
- async ensureReady({ waitForWallets = false, timeoutMs = 15000 } = {}) {
919
- const isReady = () => {
920
- var _a, _b;
921
- if (!((_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.ready))
922
- return false;
923
- if (waitForWallets && !((_b = this.privyMethods) === null || _b === void 0 ? void 0 : _b.walletReady))
924
- return false;
925
- return true;
926
- };
927
- if (isReady())
928
- return;
929
- return new Promise((resolve, reject) => {
930
- const startTime = Date.now();
931
- const check = () => {
932
- if (isReady()) {
933
- resolve();
934
- }
935
- else if (Date.now() - startTime > timeoutMs) {
936
- reject(new Error('Login provider failed to initialize. This can happen in incognito mode or when third-party cookies are blocked. Try using a regular browser window.'));
937
- }
938
- else {
939
- setTimeout(check, 100);
940
- }
941
- };
942
- check();
943
- });
944
- }
945
- }
946
- PrivyWalletProvider.instance = null;
947
-
948
- exports.PrivyWalletProvider = PrivyWalletProvider;
949
- //# sourceMappingURL=privy-wallet-provider-Cb1GUmOi.js.map