@pooflabs/core 0.0.34 → 0.0.35

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/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');
@@ -4238,8 +4240,6 @@ async function getOrCreateConnection(appId, isServer) {
4238
4240
  else {
4239
4241
  wsUrl.searchParams.append('appId', config.appId);
4240
4242
  }
4241
- // Add timestamp to prevent connection reuse issues
4242
- wsUrl.searchParams.append('_t', Date.now().toString());
4243
4243
  // Add auth token if available
4244
4244
  const authToken = await getFreshAuthToken(isServer);
4245
4245
  if (authToken) {
@@ -4579,17 +4579,23 @@ async function removeCallbackFromSubscription(connection, subscriptionId, callba
4579
4579
  async function closeAllSubscriptionsV2() {
4580
4580
  const closePromises = [];
4581
4581
  for (const [appId, connection] of connections) {
4582
- // Clear token refresh timer
4583
4582
  if (connection.tokenRefreshTimer) {
4584
4583
  clearInterval(connection.tokenRefreshTimer);
4585
4584
  connection.tokenRefreshTimer = null;
4586
4585
  }
4586
+ if (connection.keepaliveTimer) {
4587
+ clearInterval(connection.keepaliveTimer);
4588
+ connection.keepaliveTimer = null;
4589
+ }
4587
4590
  if (connection.ws) {
4591
+ const ws = connection.ws;
4592
+ connection.ws = null;
4593
+ connection.isConnected = false;
4588
4594
  closePromises.push(new Promise((resolve) => {
4589
- connection.ws.addEventListener('close', () => {
4595
+ ws.addEventListener('close', () => {
4590
4596
  resolve();
4591
4597
  });
4592
- connection.ws.close();
4598
+ ws.close();
4593
4599
  }));
4594
4600
  }
4595
4601
  connections.delete(appId);
@@ -4636,7 +4642,18 @@ function getCachedDataV2(path, prompt) {
4636
4642
  * Note: Existing subscriptions will receive new initial data after reconnection.
4637
4643
  */
4638
4644
  async function reconnectWithNewAuthV2() {
4639
- // For each active connection
4645
+ if (reconnectInProgress) {
4646
+ return reconnectInProgress;
4647
+ }
4648
+ reconnectInProgress = doReconnectWithNewAuth();
4649
+ try {
4650
+ await reconnectInProgress;
4651
+ }
4652
+ finally {
4653
+ reconnectInProgress = null;
4654
+ }
4655
+ }
4656
+ async function doReconnectWithNewAuth() {
4640
4657
  for (const [appId, connection] of connections) {
4641
4658
  if (!connection.ws) {
4642
4659
  continue;
@@ -4645,7 +4662,6 @@ async function reconnectWithNewAuthV2() {
4645
4662
  pending.reject(new Error('Connection reconnecting due to auth change'));
4646
4663
  }
4647
4664
  connection.pendingSubscriptions.clear();
4648
- // Resolve any pending unsubscriptions - connection is closing anyway
4649
4665
  for (const [, pending] of connection.pendingUnsubscriptions) {
4650
4666
  pending.resolve();
4651
4667
  }
@@ -4655,8 +4671,6 @@ async function reconnectWithNewAuthV2() {
4655
4671
  // Close the WebSocket (this triggers reconnection in ReconnectingWebSocket)
4656
4672
  // We use reconnect() which will close and re-open with fresh URL (including new token)
4657
4673
  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
4674
  connection.ws.reconnect();
4661
4675
  }
4662
4676
  catch (error) {