@pooflabs/core 0.0.34 → 0.0.36-rc.1

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.
@@ -3,7 +3,7 @@ export interface ClientConfig {
3
3
  name: string;
4
4
  logoUrl: string;
5
5
  apiKey: string;
6
- authMethod: 'none' | 'privy' | 'wallet' | 'rainbowkit' | 'coinbase-smart-wallet' | 'onboard' | 'phantom';
6
+ authMethod: 'none' | 'privy' | 'wallet' | 'rainbowkit' | 'coinbase-smart-wallet' | 'onboard' | 'phantom' | 'mobile-wallet-adapter';
7
7
  wsApiUrl: string;
8
8
  apiUrl: string;
9
9
  appId: string;
@@ -27,6 +27,15 @@ export interface ClientConfig {
27
27
  appIcon?: string;
28
28
  enablePrivyFallback?: boolean;
29
29
  };
30
+ mobileWalletConfig?: {
31
+ appIdentity?: {
32
+ name?: string;
33
+ uri?: string;
34
+ icon?: string;
35
+ };
36
+ cluster?: string;
37
+ theme?: 'light' | 'dark';
38
+ };
30
39
  mockAuth?: boolean;
31
40
  }
32
41
  export declare let clientConfig: ClientConfig;
package/dist/index.js CHANGED
@@ -4037,6 +4037,7 @@ const WS_CONFIG = {
4037
4037
  const WS_V2_PATH = '/ws/v2';
4038
4038
  let browserReconnectHooksAttached = false;
4039
4039
  let lastBrowserTriggeredReconnectAt = 0;
4040
+ let reconnectInProgress = null;
4040
4041
  // ============ Helper Functions ============
4041
4042
  function generateSubscriptionId() {
4042
4043
  return `sub_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
@@ -4095,10 +4096,11 @@ function scheduleTokenRefresh(connection, isServer) {
4095
4096
  return;
4096
4097
  const timeUntilExpiry = expirationTime - Date.now();
4097
4098
  if (timeUntilExpiry <= TOKEN_REFRESH_BUFFER) {
4098
- console.info('[WS v2] Token expiring soon, proactively refreshing and reconnecting');
4099
- // Refresh the token directly rather than going through getFreshAuthToken(),
4100
- // which only refreshes when the token is within 60s of expiry. We want to
4101
- // refresh as soon as we enter the buffer window to avoid unnecessary reconnects.
4099
+ console.info('[WS v2] Token expiring soon, proactively refreshing');
4100
+ // Refresh the token and store it. Do NOT reconnect — the server only
4101
+ // verifies JWT at $connect time, so the existing connection continues
4102
+ // working. The fresh token is picked up by urlProvider the next time
4103
+ // a reconnect naturally happens (network drop, keepalive timeout, etc.).
4102
4104
  try {
4103
4105
  const currentRefreshToken = await getRefreshToken(isServer);
4104
4106
  if (!currentRefreshToken) {
@@ -4108,7 +4110,7 @@ function scheduleTokenRefresh(connection, isServer) {
4108
4110
  const refreshData = await refreshSession(currentRefreshToken);
4109
4111
  if (refreshData && refreshData.idToken && refreshData.accessToken) {
4110
4112
  await updateIdTokenAndAccessToken(refreshData.idToken, refreshData.accessToken, isServer);
4111
- reconnectWithNewAuthV2();
4113
+ console.info('[WS v2] Token refreshed successfully, stored for next connection');
4112
4114
  }
4113
4115
  else {
4114
4116
  console.warn('[WS v2] Proactive token refresh returned incomplete data');
@@ -4216,8 +4218,6 @@ async function getOrCreateConnection(appId, isServer) {
4216
4218
  isConnected: false,
4217
4219
  appId,
4218
4220
  tokenRefreshTimer: null,
4219
- lastMessageAt: Date.now(),
4220
- keepaliveTimer: null,
4221
4221
  consecutiveAuthFailures: 0,
4222
4222
  };
4223
4223
  connections.set(appId, connection);
@@ -4238,8 +4238,6 @@ async function getOrCreateConnection(appId, isServer) {
4238
4238
  else {
4239
4239
  wsUrl.searchParams.append('appId', config.appId);
4240
4240
  }
4241
- // Add timestamp to prevent connection reuse issues
4242
- wsUrl.searchParams.append('_t', Date.now().toString());
4243
4241
  // Add auth token if available
4244
4242
  const authToken = await getFreshAuthToken(isServer);
4245
4243
  if (authToken) {
@@ -4271,7 +4269,6 @@ async function getOrCreateConnection(appId, isServer) {
4271
4269
  ws.addEventListener('open', () => {
4272
4270
  connection.isConnecting = false;
4273
4271
  connection.isConnected = true;
4274
- connection.lastMessageAt = Date.now();
4275
4272
  connection.consecutiveAuthFailures = 0;
4276
4273
  // Schedule periodic token freshness checks
4277
4274
  scheduleTokenRefresh(connection, isServer);
@@ -4280,25 +4277,9 @@ async function getOrCreateConnection(appId, isServer) {
4280
4277
  sub.lastData = undefined;
4281
4278
  sendSubscribe(connection, sub);
4282
4279
  }
4283
- // Start keepalive detection — if no messages for 90s, force reconnect
4284
- if (connection.keepaliveTimer) {
4285
- clearInterval(connection.keepaliveTimer);
4286
- }
4287
- connection.keepaliveTimer = setInterval(() => {
4288
- var _a;
4289
- if (Date.now() - connection.lastMessageAt > 90000) {
4290
- console.warn('[WS v2] No messages received for 90s, forcing reconnect');
4291
- if (connection.keepaliveTimer) {
4292
- clearInterval(connection.keepaliveTimer);
4293
- connection.keepaliveTimer = null;
4294
- }
4295
- (_a = connection.ws) === null || _a === void 0 ? void 0 : _a.reconnect();
4296
- }
4297
- }, 30000);
4298
4280
  });
4299
4281
  // Handle incoming messages
4300
4282
  ws.addEventListener('message', (event) => {
4301
- connection.lastMessageAt = Date.now();
4302
4283
  try {
4303
4284
  const message = JSON.parse(event.data);
4304
4285
  handleServerMessage(connection, message);
@@ -4322,10 +4303,6 @@ async function getOrCreateConnection(appId, isServer) {
4322
4303
  clearInterval(connection.tokenRefreshTimer);
4323
4304
  connection.tokenRefreshTimer = null;
4324
4305
  }
4325
- if (connection.keepaliveTimer) {
4326
- clearInterval(connection.keepaliveTimer);
4327
- connection.keepaliveTimer = null;
4328
- }
4329
4306
  });
4330
4307
  return connection;
4331
4308
  }
@@ -4398,7 +4375,10 @@ function handleServerMessage(connection, message) {
4398
4375
  }
4399
4376
  function notifyCallbacks(subscription, data) {
4400
4377
  var _a;
4401
- for (const callback of subscription.callbacks) {
4378
+ // Snapshot the callbacks array so that unsubscriptions during
4379
+ // notification don't cause callbacks to be skipped.
4380
+ const callbacks = subscription.callbacks.slice();
4381
+ for (const callback of callbacks) {
4402
4382
  try {
4403
4383
  (_a = callback.onData) === null || _a === void 0 ? void 0 : _a.call(callback, data);
4404
4384
  }
@@ -4579,17 +4559,19 @@ async function removeCallbackFromSubscription(connection, subscriptionId, callba
4579
4559
  async function closeAllSubscriptionsV2() {
4580
4560
  const closePromises = [];
4581
4561
  for (const [appId, connection] of connections) {
4582
- // Clear token refresh timer
4583
4562
  if (connection.tokenRefreshTimer) {
4584
4563
  clearInterval(connection.tokenRefreshTimer);
4585
4564
  connection.tokenRefreshTimer = null;
4586
4565
  }
4587
4566
  if (connection.ws) {
4567
+ const ws = connection.ws;
4568
+ connection.ws = null;
4569
+ connection.isConnected = false;
4588
4570
  closePromises.push(new Promise((resolve) => {
4589
- connection.ws.addEventListener('close', () => {
4571
+ ws.addEventListener('close', () => {
4590
4572
  resolve();
4591
4573
  });
4592
- connection.ws.close();
4574
+ ws.close();
4593
4575
  }));
4594
4576
  }
4595
4577
  connections.delete(appId);
@@ -4636,7 +4618,18 @@ function getCachedDataV2(path, prompt) {
4636
4618
  * Note: Existing subscriptions will receive new initial data after reconnection.
4637
4619
  */
4638
4620
  async function reconnectWithNewAuthV2() {
4639
- // For each active connection
4621
+ if (reconnectInProgress) {
4622
+ return reconnectInProgress;
4623
+ }
4624
+ reconnectInProgress = doReconnectWithNewAuth();
4625
+ try {
4626
+ await reconnectInProgress;
4627
+ }
4628
+ finally {
4629
+ reconnectInProgress = null;
4630
+ }
4631
+ }
4632
+ async function doReconnectWithNewAuth() {
4640
4633
  for (const [appId, connection] of connections) {
4641
4634
  if (!connection.ws) {
4642
4635
  continue;
@@ -4645,7 +4638,6 @@ async function reconnectWithNewAuthV2() {
4645
4638
  pending.reject(new Error('Connection reconnecting due to auth change'));
4646
4639
  }
4647
4640
  connection.pendingSubscriptions.clear();
4648
- // Resolve any pending unsubscriptions - connection is closing anyway
4649
4641
  for (const [, pending] of connection.pendingUnsubscriptions) {
4650
4642
  pending.resolve();
4651
4643
  }
@@ -4655,8 +4647,6 @@ async function reconnectWithNewAuthV2() {
4655
4647
  // Close the WebSocket (this triggers reconnection in ReconnectingWebSocket)
4656
4648
  // We use reconnect() which will close and re-open with fresh URL (including new token)
4657
4649
  try {
4658
- // ReconnectingWebSocket.reconnect() closes current connection and opens a new one
4659
- // The urlProvider will be called again, getting a fresh auth token
4660
4650
  connection.ws.reconnect();
4661
4651
  }
4662
4652
  catch (error) {