@pooflabs/web 0.0.62 → 0.0.64

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.
@@ -70,5 +70,11 @@ export declare class PrivyWalletProvider implements AuthProvider {
70
70
  signMessage(message: string): Promise<string>;
71
71
  restoreSession(): Promise<User | null>;
72
72
  private createSession;
73
+ /**
74
+ * Waits for a wallet matching the session address to appear in the wallets array.
75
+ * This handles the timing gap where Privy's embedded wallet (created for email login users)
76
+ * may not yet be in the useWallets() array when signTransaction is called immediately after login.
77
+ */
78
+ private waitForMatchingWallet;
73
79
  private ensureReady;
74
80
  }
@@ -6541,10 +6541,14 @@ class WebSessionManager {
6541
6541
  const newObj = JSON.parse(newSession);
6542
6542
  return { address: newObj.address, session: newObj };
6543
6543
  }
6544
+ // Refresh failed — clear stale session to prevent retry loops
6545
+ this.clearSession();
6544
6546
  return null;
6545
6547
  }
6546
6548
  }
6547
6549
  catch (err) {
6550
+ // Token decode or refresh failed — clear stale session to prevent retry loops
6551
+ this.clearSession();
6548
6552
  return null;
6549
6553
  }
6550
6554
  return { address: sessionObj.address, session: sessionObj };
@@ -9468,15 +9472,30 @@ class ServerSessionManager {
9468
9472
  constructor() {
9469
9473
  /* Private cache (lives for the life of the process) */
9470
9474
  this.session = null;
9475
+ /* Coalesce concurrent getSession() calls into a single in-flight request */
9476
+ this.pendingSession = null;
9471
9477
  }
9472
9478
  /* ---------------------------------------------- *
9473
9479
  * GET (lazy-fetch)
9474
9480
  * ---------------------------------------------- */
9475
9481
  async getSession() {
9476
- if (this.session === null) {
9477
- this.session = await createSession();
9478
- }
9479
- return this.session;
9482
+ if (this.session !== null) {
9483
+ return this.session;
9484
+ }
9485
+ // If a session creation is already in-flight, reuse that promise
9486
+ // instead of firing a second concurrent request.
9487
+ if (this.pendingSession !== null) {
9488
+ return this.pendingSession;
9489
+ }
9490
+ this.pendingSession = createSession()
9491
+ .then((session) => {
9492
+ this.session = session;
9493
+ return session;
9494
+ })
9495
+ .finally(() => {
9496
+ this.pendingSession = null;
9497
+ });
9498
+ return this.pendingSession;
9480
9499
  }
9481
9500
  /* ---------------------------------------------- *
9482
9501
  * STORE (overwrites the cached value)
@@ -9489,6 +9508,7 @@ class ServerSessionManager {
9489
9508
  * ---------------------------------------------- */
9490
9509
  clearSession() {
9491
9510
  this.session = null;
9511
+ this.pendingSession = null;
9492
9512
  }
9493
9513
  /* ---------------------------------------------- *
9494
9514
  * QUICK helpers
@@ -9791,6 +9811,150 @@ function hashForKey$1(value) {
9791
9811
  }
9792
9812
  return h.toString(36);
9793
9813
  }
9814
+ /**
9815
+ * Validates that a field name is a safe identifier (alphanumeric, underscores, dots for nested paths).
9816
+ * Prevents prompt injection via crafted field names.
9817
+ */
9818
+ function validateFieldName(field) {
9819
+ if (!/^[a-zA-Z0-9_.]+$/.test(field)) {
9820
+ throw new Error(`Invalid field name "${field}". Field names must only contain letters, numbers, underscores, and dots.`);
9821
+ }
9822
+ }
9823
+ /**
9824
+ * Parses a raw aggregation result (e.g. [{ count: 42 }] or [{ _id: null, total: 100 }])
9825
+ * into a single numeric value.
9826
+ */
9827
+ function parseAggregateValue(result) {
9828
+ if (typeof result === 'number')
9829
+ return result;
9830
+ if (Array.isArray(result)) {
9831
+ if (result.length === 0)
9832
+ return 0;
9833
+ // Multiple elements — not a collapsed aggregate result
9834
+ if (result.length > 1) {
9835
+ throw new Error(`Unexpected aggregate result: got array with ${result.length} elements. The AI may have returned full documents instead of an aggregation.`);
9836
+ }
9837
+ const first = result[0];
9838
+ if (typeof first === 'number')
9839
+ return first;
9840
+ if (first && typeof first === 'object') {
9841
+ // $count stage returns { count: N }
9842
+ if (typeof first.count === 'number')
9843
+ return first.count;
9844
+ // $group stage returns { _id: null, result: N } — expect _id + one numeric field
9845
+ const numericEntries = Object.entries(first).filter(([key, val]) => key !== '_id' && typeof val === 'number');
9846
+ if (numericEntries.length === 1)
9847
+ return numericEntries[0][1];
9848
+ }
9849
+ // Avoid leaking document contents into error messages
9850
+ const shape = first && typeof first === 'object' ? `{${Object.keys(first).join(', ')}}` : String(first);
9851
+ throw new Error(`Unexpected aggregate result shape: ${shape}. Expected {count: N} or {_id: null, <field>: N}.`);
9852
+ }
9853
+ if (result && typeof result === 'object' && typeof result.count === 'number') {
9854
+ return result.count;
9855
+ }
9856
+ throw new Error(`Unexpected aggregate result type: ${typeof result}. Expected a number, array, or object with a count field.`);
9857
+ }
9858
+ /**
9859
+ * Count items in a collection path. Returns a numeric result.
9860
+ *
9861
+ * This uses the AI query engine with a count-specific prompt prefix,
9862
+ * so TaroBase will generate a $count aggregation pipeline and return
9863
+ * just the count rather than full documents.
9864
+ *
9865
+ * IMPORTANT: This only works for collections where the read policy is "true".
9866
+ * If the read policy requires per-document checks, the server will return
9867
+ * an error because aggregate counts cannot be performed without pulling all
9868
+ * documents for access control evaluation.
9869
+ *
9870
+ * @param path - Collection path (e.g., "posts", "users/abc/comments")
9871
+ * @param opts - Optional filter prompt and overrides
9872
+ * @returns AggregateResult with the count value
9873
+ */
9874
+ async function count(path, opts = {}) {
9875
+ const prefix = 'Return ONLY the total count of matching documents. Use the $count stage to produce a field named "count". Do NOT return the documents themselves.';
9876
+ const fullPrompt = opts.prompt
9877
+ ? `${prefix} Filter: ${opts.prompt}`
9878
+ : prefix;
9879
+ const result = await get$2(path, { prompt: fullPrompt, bypassCache: true, _overrides: opts._overrides });
9880
+ return { value: parseAggregateValue(result) };
9881
+ }
9882
+ /**
9883
+ * Run an aggregate operation on a collection path. Returns a numeric result.
9884
+ *
9885
+ * Supported operations:
9886
+ * - count: Total number of documents
9887
+ * - uniqueCount: Number of distinct values for a field
9888
+ * - sum: Sum of a numeric field
9889
+ * - avg: Average of a numeric field
9890
+ * - min: Minimum value of a numeric field
9891
+ * - max: Maximum value of a numeric field
9892
+ *
9893
+ * IMPORTANT: This only works for collections where the read policy is "true".
9894
+ * If the read policy requires per-document checks, the server will return
9895
+ * an error because aggregate operations cannot be performed without pulling
9896
+ * all documents for access control evaluation.
9897
+ *
9898
+ * @param path - Collection path (e.g., "posts", "users/abc/comments")
9899
+ * @param operation - The aggregate operation to perform
9900
+ * @param opts - Options including optional filter prompt and field name
9901
+ * @returns AggregateResult with the computed numeric value
9902
+ */
9903
+ async function aggregate(path, operation, opts = {}) {
9904
+ let prefix;
9905
+ switch (operation) {
9906
+ case 'count':
9907
+ prefix = 'Return ONLY the total count of matching documents. Use the $count stage to produce a field named "count". Do NOT return the documents themselves.';
9908
+ break;
9909
+ case 'uniqueCount':
9910
+ if (!opts.field)
9911
+ throw new Error('aggregate "uniqueCount" requires a field option');
9912
+ validateFieldName(opts.field);
9913
+ prefix = `Return ONLY the count of unique/distinct values of the "${opts.field}" field. Use $group with _id set to "$${opts.field}" then $count to produce a field named "count". Do NOT return the documents themselves.`;
9914
+ break;
9915
+ case 'sum':
9916
+ if (!opts.field)
9917
+ throw new Error('aggregate "sum" requires a field option');
9918
+ validateFieldName(opts.field);
9919
+ prefix = `Return ONLY the sum of the "${opts.field}" field across all matching documents. Use $group with _id: null and result: { $sum: "$${opts.field}" }. Do NOT return the documents themselves.`;
9920
+ break;
9921
+ case 'avg':
9922
+ if (!opts.field)
9923
+ throw new Error('aggregate "avg" requires a field option');
9924
+ validateFieldName(opts.field);
9925
+ prefix = `Return ONLY the average of the "${opts.field}" field across all matching documents. Use $group with _id: null and result: { $avg: "$${opts.field}" }. Do NOT return the documents themselves.`;
9926
+ break;
9927
+ case 'min':
9928
+ if (!opts.field)
9929
+ throw new Error('aggregate "min" requires a field option');
9930
+ validateFieldName(opts.field);
9931
+ prefix = `Return ONLY the minimum value of the "${opts.field}" field across all matching documents. Use $group with _id: null and result: { $min: "$${opts.field}" }. Do NOT return the documents themselves.`;
9932
+ break;
9933
+ case 'max':
9934
+ if (!opts.field)
9935
+ throw new Error('aggregate "max" requires a field option');
9936
+ validateFieldName(opts.field);
9937
+ prefix = `Return ONLY the maximum value of the "${opts.field}" field across all matching documents. Use $group with _id: null and result: { $max: "$${opts.field}" }. Do NOT return the documents themselves.`;
9938
+ break;
9939
+ default:
9940
+ throw new Error(`Unsupported aggregate operation: ${operation}`);
9941
+ }
9942
+ const fullPrompt = opts.prompt
9943
+ ? `${prefix} Filter: ${opts.prompt}`
9944
+ : prefix;
9945
+ const result = await get$2(path, { prompt: fullPrompt, bypassCache: true, _overrides: opts._overrides });
9946
+ // For uniqueCount, the AI may return $group results without the final $count
9947
+ // stage, producing [{_id: "val1"}, {_id: "val2"}, ...]. Verify elements look
9948
+ // like $group output (only _id key) before using array length as the count.
9949
+ if (operation === 'uniqueCount' && Array.isArray(result) && result.length > 1) {
9950
+ const looksLikeGroupOutput = result.every((el) => el && typeof el === 'object' && Object.keys(el).length === 1 && '_id' in el);
9951
+ if (looksLikeGroupOutput) {
9952
+ return { value: result.length };
9953
+ }
9954
+ throw new Error(`Unexpected uniqueCount result: got ${result.length} elements that don't match $group output shape.`);
9955
+ }
9956
+ return { value: parseAggregateValue(result) };
9957
+ }
9794
9958
  async function get$2(path, opts = {}) {
9795
9959
  try {
9796
9960
  let normalizedPath = path.startsWith("/") ? path.slice(1) : path;
@@ -10257,7 +10421,7 @@ const BASE_MIN_RECONNECT_DELAY_MS = 1000;
10257
10421
  const MIN_RECONNECT_DELAY_JITTER_MS = 1000;
10258
10422
  const MAX_RECONNECT_DELAY_MS = 300000;
10259
10423
  const RECONNECT_DELAY_GROW_FACTOR = 1.8;
10260
- const MIN_BROWSER_RECONNECT_INTERVAL_MS = 30000;
10424
+ const MIN_BROWSER_RECONNECT_INTERVAL_MS = 5000;
10261
10425
  const WS_CONFIG = {
10262
10426
  // Keep retrying indefinitely so long outages recover without page refresh.
10263
10427
  maxRetries: Infinity,
@@ -10422,6 +10586,8 @@ async function getOrCreateConnection(appId, isServer) {
10422
10586
  isConnected: false,
10423
10587
  appId,
10424
10588
  tokenRefreshTimer: null,
10589
+ lastMessageAt: Date.now(),
10590
+ keepaliveTimer: null,
10425
10591
  };
10426
10592
  connections.set(appId, connection);
10427
10593
  // URL provider for reconnection with fresh tokens
@@ -10458,6 +10624,7 @@ async function getOrCreateConnection(appId, isServer) {
10458
10624
  ws.addEventListener('open', () => {
10459
10625
  connection.isConnecting = false;
10460
10626
  connection.isConnected = true;
10627
+ connection.lastMessageAt = Date.now();
10461
10628
  // Schedule token refresh before expiry
10462
10629
  (async () => {
10463
10630
  const token = await getIdToken$1(isServer);
@@ -10465,11 +10632,28 @@ async function getOrCreateConnection(appId, isServer) {
10465
10632
  })();
10466
10633
  // Re-subscribe to all existing subscriptions after reconnect
10467
10634
  for (const sub of connection.subscriptions.values()) {
10635
+ sub.lastData = undefined;
10468
10636
  sendSubscribe(connection, sub);
10469
10637
  }
10638
+ // Start keepalive detection — if no messages for 90s, force reconnect
10639
+ if (connection.keepaliveTimer) {
10640
+ clearInterval(connection.keepaliveTimer);
10641
+ }
10642
+ connection.keepaliveTimer = setInterval(() => {
10643
+ var _a;
10644
+ if (Date.now() - connection.lastMessageAt > 90000) {
10645
+ console.warn('[WS v2] No messages received for 90s, forcing reconnect');
10646
+ if (connection.keepaliveTimer) {
10647
+ clearInterval(connection.keepaliveTimer);
10648
+ connection.keepaliveTimer = null;
10649
+ }
10650
+ (_a = connection.ws) === null || _a === void 0 ? void 0 : _a.reconnect();
10651
+ }
10652
+ }, 30000);
10470
10653
  });
10471
10654
  // Handle incoming messages
10472
10655
  ws.addEventListener('message', (event) => {
10656
+ connection.lastMessageAt = Date.now();
10473
10657
  try {
10474
10658
  const message = JSON.parse(event.data);
10475
10659
  handleServerMessage(connection, message);
@@ -10481,20 +10665,22 @@ async function getOrCreateConnection(appId, isServer) {
10481
10665
  // Handle errors
10482
10666
  ws.addEventListener('error', (event) => {
10483
10667
  console.error('[WS v2] WebSocket error:', event);
10484
- // Reject all pending subscriptions
10485
- for (const [id, pending] of connection.pendingSubscriptions) {
10668
+ for (const [, pending] of connection.pendingSubscriptions) {
10486
10669
  pending.reject(new Error('WebSocket error'));
10487
- connection.pendingSubscriptions.delete(id);
10488
10670
  }
10671
+ connection.pendingSubscriptions.clear();
10489
10672
  });
10490
10673
  // Handle close
10491
10674
  ws.addEventListener('close', () => {
10492
10675
  connection.isConnected = false;
10493
- // Clear token refresh timer
10494
10676
  if (connection.tokenRefreshTimer) {
10495
10677
  clearTimeout(connection.tokenRefreshTimer);
10496
10678
  connection.tokenRefreshTimer = null;
10497
10679
  }
10680
+ if (connection.keepaliveTimer) {
10681
+ clearInterval(connection.keepaliveTimer);
10682
+ connection.keepaliveTimer = null;
10683
+ }
10498
10684
  });
10499
10685
  return connection;
10500
10686
  }
@@ -10694,9 +10880,7 @@ async function subscribeV2(path, subscriptionOptions) {
10694
10880
  await subscriptionPromise;
10695
10881
  }
10696
10882
  catch (error) {
10697
- // Remove subscription on error
10698
- connection.subscriptions.delete(subscriptionId);
10699
- throw error;
10883
+ console.warn('[WS v2] Subscription confirmation failed, keeping for reconnect recovery:', error);
10700
10884
  }
10701
10885
  }
10702
10886
  // Return unsubscribe function
@@ -10812,8 +10996,6 @@ async function reconnectWithNewAuthV2() {
10812
10996
  if (!connection.ws) {
10813
10997
  continue;
10814
10998
  }
10815
- // Reject any pending subscriptions - they'll need to be retried after reconnect
10816
- // This prevents hanging promises during auth transitions
10817
10999
  for (const [, pending] of connection.pendingSubscriptions) {
10818
11000
  pending.reject(new Error('Connection reconnecting due to auth change'));
10819
11001
  }
@@ -13345,7 +13527,7 @@ async function loadDependencies() {
13345
13527
  const [reactModule, reactDomModule, phantomModule] = await Promise.all([
13346
13528
  import('react'),
13347
13529
  import('react-dom/client'),
13348
- Promise.resolve().then(function () { return require('./index-C2cjjAWD.js'); })
13530
+ Promise.resolve().then(function () { return require('./index-BmJDdk1y.js'); })
13349
13531
  ]);
13350
13532
  // Extract default export from ESM module namespace
13351
13533
  // Dynamic import() returns { default: Module, ...exports }, not the module directly
@@ -33327,13 +33509,21 @@ class PrivyWalletProvider {
33327
33509
  await this.privyMethods.logout();
33328
33510
  }
33329
33511
  async runTransaction(_evmTransactionData, solTransactionData, options) {
33330
- var _a, _b;
33512
+ var _a, _b, _c;
33331
33513
  await this.ensureReady({ waitForWallets: true });
33332
33514
  let session = await WebSessionManager.getSession();
33333
33515
  let sessionAddress = session === null || session === void 0 ? void 0 : session.address;
33334
33516
  let privyWallets = (_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.wallets;
33335
33517
  let privyWallet = privyWallets === null || privyWallets === void 0 ? void 0 : privyWallets.find((wallet) => wallet.address === sessionAddress);
33518
+ // If wallet not found yet, it may be an embedded wallet (email login) that hasn't
33519
+ // appeared in the wallets array due to React state timing. Wait for it before
33520
+ // falling back to connectWallet() which shows an unwanted wallet selection modal.
33336
33521
  if (!privyWallets || privyWallets.length === 0 || !privyWallet) {
33522
+ if (((_b = this.privyMethods) === null || _b === void 0 ? void 0 : _b.authenticated) && sessionAddress) {
33523
+ privyWallet = await this.waitForMatchingWallet(sessionAddress);
33524
+ }
33525
+ }
33526
+ if (!privyWallet) {
33337
33527
  // If there's already a pending transaction, throw an error to prevent overlapping calls
33338
33528
  if (this.pendingTransaction) {
33339
33529
  throw new Error("Oops... something went wrong. Please try again.");
@@ -33413,7 +33603,7 @@ class PrivyWalletProvider {
33413
33603
  return {
33414
33604
  transactionSignature: signature,
33415
33605
  blockNumber: (txInfo === null || txInfo === void 0 ? void 0 : txInfo.slot) || 0,
33416
- gasUsed: ((_b = txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta) === null || _b === void 0 ? void 0 : _b.fee.toString()) || '0',
33606
+ gasUsed: ((_c = txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta) === null || _c === void 0 ? void 0 : _c.fee.toString()) || '0',
33417
33607
  data: txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta,
33418
33608
  };
33419
33609
  }
@@ -33433,7 +33623,7 @@ class PrivyWalletProvider {
33433
33623
  * @returns The signed transaction
33434
33624
  */
33435
33625
  async signTransaction(transaction) {
33436
- var _a;
33626
+ var _a, _b;
33437
33627
  await this.ensureReady({ waitForWallets: true });
33438
33628
  let privyWallets = (_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.wallets;
33439
33629
  let session = await WebSessionManager.getSession();
@@ -33443,8 +33633,16 @@ class PrivyWalletProvider {
33443
33633
  if (this.pendingSignTransaction) {
33444
33634
  throw new Error("Oops... something went wrong. Please try again.");
33445
33635
  }
33446
- // If wallet not connected, trigger connection and queue the signing
33636
+ // If wallet not found yet, it may be an embedded wallet (email login) that hasn't
33637
+ // appeared in the wallets array due to React state timing. Wait for it before
33638
+ // falling back to connectWallet() which shows an unwanted wallet selection modal.
33447
33639
  if (!privyWallets || privyWallets.length === 0 || !privyWallet) {
33640
+ if (((_b = this.privyMethods) === null || _b === void 0 ? void 0 : _b.authenticated) && sessionAddress) {
33641
+ privyWallet = await this.waitForMatchingWallet(sessionAddress);
33642
+ }
33643
+ }
33644
+ // If still no wallet after waiting, trigger connection and queue the signing
33645
+ if (!privyWallet) {
33448
33646
  return new Promise((resolve, reject) => {
33449
33647
  this.pendingSignTransaction = {
33450
33648
  resolve,
@@ -33507,7 +33705,7 @@ class PrivyWalletProvider {
33507
33705
  * @returns The transaction signature
33508
33706
  */
33509
33707
  async signAndSubmitTransaction(transaction, feePayer) {
33510
- var _a;
33708
+ var _a, _b;
33511
33709
  await this.ensureReady({ waitForWallets: true });
33512
33710
  let privyWallets = (_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.wallets;
33513
33711
  let session = await WebSessionManager.getSession();
@@ -33517,8 +33715,16 @@ class PrivyWalletProvider {
33517
33715
  if (this.pendingSignAndSubmitTransaction) {
33518
33716
  throw new Error("Oops... something went wrong. Please try again.");
33519
33717
  }
33520
- // If wallet not connected, trigger connection and queue the signing
33718
+ // If wallet not found yet, it may be an embedded wallet (email login) that hasn't
33719
+ // appeared in the wallets array due to React state timing. Wait for it before
33720
+ // falling back to connectWallet() which shows an unwanted wallet selection modal.
33521
33721
  if (!privyWallets || privyWallets.length === 0 || !privyWallet) {
33722
+ if (((_b = this.privyMethods) === null || _b === void 0 ? void 0 : _b.authenticated) && sessionAddress) {
33723
+ privyWallet = await this.waitForMatchingWallet(sessionAddress);
33724
+ }
33725
+ }
33726
+ // If still no wallet after waiting, trigger connection and queue the signing
33727
+ if (!privyWallet) {
33522
33728
  return new Promise((resolve, reject) => {
33523
33729
  this.pendingSignAndSubmitTransaction = {
33524
33730
  resolve,
@@ -33684,7 +33890,7 @@ class PrivyWalletProvider {
33684
33890
  return { signature, txInfo };
33685
33891
  }
33686
33892
  async signMessage(message) {
33687
- var _a, _b;
33893
+ var _a, _b, _c;
33688
33894
  await this.ensureReady({ waitForWallets: true });
33689
33895
  const session = await WebSessionManager.getSession();
33690
33896
  let sessionAddress = session === null || session === void 0 ? void 0 : session.address;
@@ -33692,23 +33898,47 @@ class PrivyWalletProvider {
33692
33898
  if (this.pendingSignMessage) {
33693
33899
  throw new Error("Oops... something went wrong. Please try again.");
33694
33900
  }
33695
- // If no wallets connected, trigger wallet connection and queue the signing
33901
+ // If no wallets connected yet, it may be an embedded wallet (email login) that hasn't
33902
+ // appeared in the wallets array due to React state timing. Wait for it before
33903
+ // falling back to connectWallet() which shows an unwanted wallet selection modal.
33696
33904
  if (!((_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.wallets) || this.privyMethods.wallets.length === 0) {
33697
- return new Promise((resolve, reject) => {
33698
- this.pendingSignMessage = {
33699
- resolve,
33700
- reject,
33701
- message
33702
- };
33703
- this.privyMethods.connectWallet();
33704
- // Set a timeout to reject the promise if connection takes too long
33705
- setTimeout(() => {
33706
- if (this.pendingSignMessage) {
33707
- this.pendingSignMessage.reject(new Error("Wallet connection timed out"));
33708
- this.pendingSignMessage = null;
33709
- }
33710
- }, 30000); // 30 seconds timeout
33711
- });
33905
+ if (((_b = this.privyMethods) === null || _b === void 0 ? void 0 : _b.authenticated) && sessionAddress) {
33906
+ const matchedWallet = await this.waitForMatchingWallet(sessionAddress);
33907
+ if (!matchedWallet) {
33908
+ return new Promise((resolve, reject) => {
33909
+ this.pendingSignMessage = {
33910
+ resolve,
33911
+ reject,
33912
+ message
33913
+ };
33914
+ this.privyMethods.connectWallet();
33915
+ // Set a timeout to reject the promise if connection takes too long
33916
+ setTimeout(() => {
33917
+ if (this.pendingSignMessage) {
33918
+ this.pendingSignMessage.reject(new Error("Wallet connection timed out"));
33919
+ this.pendingSignMessage = null;
33920
+ }
33921
+ }, 30000); // 30 seconds timeout
33922
+ });
33923
+ }
33924
+ }
33925
+ else {
33926
+ return new Promise((resolve, reject) => {
33927
+ this.pendingSignMessage = {
33928
+ resolve,
33929
+ reject,
33930
+ message
33931
+ };
33932
+ this.privyMethods.connectWallet();
33933
+ // Set a timeout to reject the promise if connection takes too long
33934
+ setTimeout(() => {
33935
+ if (this.pendingSignMessage) {
33936
+ this.pendingSignMessage.reject(new Error("Wallet connection timed out"));
33937
+ this.pendingSignMessage = null;
33938
+ }
33939
+ }, 30000); // 30 seconds timeout
33940
+ });
33941
+ }
33712
33942
  }
33713
33943
  let privyWallet = this.privyMethods.wallets.find((wallet) => wallet.address === sessionAddress);
33714
33944
  if (!privyWallet) {
@@ -33726,7 +33956,7 @@ class PrivyWalletProvider {
33726
33956
  // Use the Privy signMessage hook for Solana wallets
33727
33957
  // The message needs to be passed as a Uint8Array
33728
33958
  const messageBytes = new TextEncoder().encode(message);
33729
- const result = await ((_b = this.privyMethods) === null || _b === void 0 ? void 0 : _b.signMessage({
33959
+ const result = await ((_c = this.privyMethods) === null || _c === void 0 ? void 0 : _c.signMessage({
33730
33960
  message: messageBytes,
33731
33961
  wallet: privyWallet,
33732
33962
  }));
@@ -33751,6 +33981,25 @@ class PrivyWalletProvider {
33751
33981
  const createSessionResult = await createSessionWithPrivy(accessToken, address, idToken);
33752
33982
  await WebSessionManager.storeSession(address, createSessionResult.accessToken, createSessionResult.idToken, createSessionResult.refreshToken);
33753
33983
  }
33984
+ /**
33985
+ * Waits for a wallet matching the session address to appear in the wallets array.
33986
+ * This handles the timing gap where Privy's embedded wallet (created for email login users)
33987
+ * may not yet be in the useWallets() array when signTransaction is called immediately after login.
33988
+ */
33989
+ async waitForMatchingWallet(sessionAddress, timeoutMs = 10000) {
33990
+ var _a;
33991
+ const startTime = Date.now();
33992
+ while (Date.now() - startTime < timeoutMs) {
33993
+ const wallets = (_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.wallets;
33994
+ if (wallets && wallets.length > 0) {
33995
+ const wallet = wallets.find((w) => w.address === sessionAddress);
33996
+ if (wallet)
33997
+ return wallet;
33998
+ }
33999
+ await new Promise(resolve => setTimeout(resolve, 200));
34000
+ }
34001
+ return null;
34002
+ }
33754
34003
  async ensureReady({ waitForWallets = false, timeoutMs = 15000 } = {}) {
33755
34004
  const isReady = () => {
33756
34005
  var _a, _b;
@@ -34949,12 +35198,14 @@ exports.PhantomWalletProvider = PhantomWalletProvider;
34949
35198
  exports.PrivyWalletProvider = PrivyWalletProvider;
34950
35199
  exports.ServerSessionManager = ServerSessionManager;
34951
35200
  exports.WebSessionManager = WebSessionManager;
35201
+ exports.aggregate = aggregate;
34952
35202
  exports.bs58 = bs58;
34953
35203
  exports.bufferExports = bufferExports;
34954
35204
  exports.buildSetDocumentsTransaction = buildSetDocumentsTransaction;
34955
35205
  exports.clearCache = clearCache;
34956
35206
  exports.closeAllSubscriptions = closeAllSubscriptions;
34957
35207
  exports.convertRemainingAccounts = convertRemainingAccounts;
35208
+ exports.count = count;
34958
35209
  exports.createSessionWithPrivy = createSessionWithPrivy;
34959
35210
  exports.createSessionWithSignature = createSessionWithSignature;
34960
35211
  exports.genAuthNonce = genAuthNonce;
@@ -34987,4 +35238,4 @@ exports.signSessionCreateMessage = signSessionCreateMessage;
34987
35238
  exports.signTransaction = signTransaction;
34988
35239
  exports.subscribe = subscribe;
34989
35240
  exports.useAuth = useAuth;
34990
- //# sourceMappingURL=index-BCpgjKea.js.map
35241
+ //# sourceMappingURL=index-9kQbe-Gv.js.map