@rebasepro/client 0.9.1-canary.baa7a6b → 0.9.1-canary.c0d4c07

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.es.js CHANGED
@@ -1405,6 +1405,20 @@ function extractMessageError(message) {
1405
1405
  };
1406
1406
  }
1407
1407
  /**
1408
+ * Broadcast and presence frames.
1409
+ *
1410
+ * Fire-and-forget (the server sends no response envelope), and exempt from the
1411
+ * client-side auth gate — a public channel is usable without an account.
1412
+ */
1413
+ var CHANNEL_MESSAGE_TYPES = new Set([
1414
+ "join_channel",
1415
+ "leave_channel",
1416
+ "broadcast",
1417
+ "presence_track",
1418
+ "presence_untrack",
1419
+ "presence_state"
1420
+ ]);
1421
+ /**
1408
1422
  * Low-level realtime WebSocket client.
1409
1423
  *
1410
1424
  * @internal Not a stable app-facing API. `createRebaseClient()` constructs and
@@ -1421,6 +1435,19 @@ var RebaseWebSocketClient = class {
1421
1435
  listeners = /* @__PURE__ */ new Map();
1422
1436
  /** Channel-name → handlers, for broadcast and presence frames. */
1423
1437
  channelHandlers = /* @__PURE__ */ new Map();
1438
+ /** Set by `close()`. Blocks any later operation from silently redialling. */
1439
+ closedByCaller = false;
1440
+ /**
1441
+ * Whether a socket exists at all (open or still opening).
1442
+ *
1443
+ * Lets callers distinguish "authenticate the live socket" from "there is
1444
+ * nothing to authenticate yet", without that question forcing a dial.
1445
+ */
1446
+ get hasSocket() {
1447
+ return this.ws !== null;
1448
+ }
1449
+ /** So the "no WebSocket in this environment" warning is said once, not per call. */
1450
+ warnedNoWebSocket = false;
1424
1451
  /** Subscribe to broadcast/presence frames for one channel. */
1425
1452
  onChannelMessage(channel, handler) {
1426
1453
  if (!this.channelHandlers.has(channel)) this.channelHandlers.set(channel, /* @__PURE__ */ new Set());
@@ -1466,8 +1493,25 @@ var RebaseWebSocketClient = class {
1466
1493
  this.getAuthToken = config.getAuthToken;
1467
1494
  this.onUnauthorized = config.onUnauthorized;
1468
1495
  this.WebSocketConstructor = config.WebSocket || (typeof WebSocket !== "undefined" ? WebSocket : void 0);
1469
- if (!this.WebSocketConstructor) console.warn("WebSocket is not defined in this environment. Realtime subscriptions will not work unless you provide a WebSocket implementation in the config.");
1470
- else this.initWebSocket();
1496
+ }
1497
+ /**
1498
+ * Open the socket if it is not open (or opening) already.
1499
+ *
1500
+ * Idempotent, synchronous, and safe to call on every operation that needs a
1501
+ * live socket — `initWebSocket` already no-ops on an open socket and is
1502
+ * re-entrant, since the reconnect path has always called it.
1503
+ */
1504
+ ensureConnected() {
1505
+ if (this.closedByCaller) return;
1506
+ if (!this.WebSocketConstructor) {
1507
+ if (!this.warnedNoWebSocket) {
1508
+ this.warnedNoWebSocket = true;
1509
+ console.warn("WebSocket is not defined in this environment. Realtime subscriptions will not work unless you provide a WebSocket implementation in the config.");
1510
+ }
1511
+ return;
1512
+ }
1513
+ if (this.ws || this.reconnectTimeout) return;
1514
+ this.initWebSocket();
1471
1515
  }
1472
1516
  /**
1473
1517
  * Authenticate the WebSocket connection
@@ -1517,7 +1561,16 @@ var RebaseWebSocketClient = class {
1517
1561
  });
1518
1562
  }
1519
1563
  }
1520
- disconnect() {
1564
+ /**
1565
+ * Drop the socket.
1566
+ *
1567
+ * `permanent` distinguishes the two callers. Signing out drops the socket
1568
+ * but the client stays usable — a later subscribe should reconnect
1569
+ * anonymously. `client.close()` is the caller saying they are done, and
1570
+ * must not be undone by a stray queued frame.
1571
+ */
1572
+ disconnect(permanent = false) {
1573
+ if (permanent) this.closedByCaller = true;
1521
1574
  this.isAuthenticated = false;
1522
1575
  this.authPromise = null;
1523
1576
  if (this.reconnectTimeout) {
@@ -1906,18 +1959,21 @@ var RebaseWebSocketClient = class {
1906
1959
  sendMessage(message) {
1907
1960
  const queuedMsg = message;
1908
1961
  if (queuedMsg._queuedResolve && queuedMsg._queuedReject) return this.doSendMessage(message, queuedMsg._queuedResolve, queuedMsg._queuedReject);
1909
- if (!this.isConnected || !this.ws) return new Promise((resolve, reject) => {
1910
- const queueable = message;
1911
- queueable._queuedResolve = resolve;
1912
- queueable._queuedReject = reject;
1913
- this.messageQueue.push(message);
1914
- });
1962
+ if (!this.isConnected || !this.ws) {
1963
+ this.ensureConnected();
1964
+ return new Promise((resolve, reject) => {
1965
+ const queueable = message;
1966
+ queueable._queuedResolve = resolve;
1967
+ queueable._queuedReject = reject;
1968
+ this.messageQueue.push(message);
1969
+ });
1970
+ }
1915
1971
  return new Promise((resolve, reject) => {
1916
1972
  this.doSendMessage(message, resolve, reject);
1917
1973
  });
1918
1974
  }
1919
1975
  async doSendMessage(message, resolve, reject) {
1920
- if (message.type !== "AUTHENTICATE" && this.getAuthToken && !this.isAuthenticated) try {
1976
+ if (message.type !== "AUTHENTICATE" && !CHANNEL_MESSAGE_TYPES.has(message.type) && this.getAuthToken && !this.isAuthenticated) try {
1921
1977
  await this.ensureAuthenticated();
1922
1978
  } catch (error) {
1923
1979
  reject(new RebaseApiError$1(error instanceof Error ? error.message : "Authentication required"));
@@ -1925,17 +1981,7 @@ var RebaseWebSocketClient = class {
1925
1981
  }
1926
1982
  const requestId = message.requestId || `req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
1927
1983
  message.requestId = requestId;
1928
- const expectsResponse = ![
1929
- "subscribe_collection",
1930
- "subscribe_one",
1931
- "unsubscribe",
1932
- "join_channel",
1933
- "leave_channel",
1934
- "broadcast",
1935
- "presence_track",
1936
- "presence_untrack",
1937
- "presence_state"
1938
- ].includes(message.type);
1984
+ const expectsResponse = !(message.type === "subscribe_collection" || message.type === "subscribe_one" || message.type === "unsubscribe" || CHANNEL_MESSAGE_TYPES.has(message.type));
1939
1985
  if (expectsResponse && !this.pendingRequests.has(requestId)) {
1940
1986
  const timeoutHandle = setTimeout(() => {
1941
1987
  if (this.pendingRequests.has(requestId)) {
@@ -2164,6 +2210,7 @@ var RebaseWebSocketClient = class {
2164
2210
  });
2165
2211
  }
2166
2212
  listenCollection(props, onUpdate, onError) {
2213
+ this.ensureConnected();
2167
2214
  const subscriptionKey = this.createCollectionSubscriptionKey(props);
2168
2215
  const callbackId = `callback_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
2169
2216
  const existingSubscription = this.collectionSubscriptions.get(subscriptionKey);
@@ -2225,6 +2272,7 @@ var RebaseWebSocketClient = class {
2225
2272
  };
2226
2273
  }
2227
2274
  listenOne(props, onUpdate, onError) {
2275
+ this.ensureConnected();
2228
2276
  const subscriptionKey = this.createSingleSubscriptionKey(props);
2229
2277
  const callbackId = `callback_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
2230
2278
  const existingSubscription = this.singleSubscriptions.get(subscriptionKey);
@@ -2742,7 +2790,7 @@ function createRebaseClient(options) {
2742
2790
  if (!ws) return;
2743
2791
  if (event === "SIGNED_OUT") ws.disconnect();
2744
2792
  else if (event === "SIGNED_IN" || event === "TOKEN_REFRESHED") {
2745
- if (session?.accessToken) ws.authenticate(session.accessToken).catch(console.warn);
2793
+ if (session?.accessToken && ws.hasSocket) ws.authenticate(session.accessToken).catch(console.warn);
2746
2794
  }
2747
2795
  });
2748
2796
  }
@@ -2857,7 +2905,7 @@ channel: (name) => {
2857
2905
  close: () => {
2858
2906
  for (const channel of realtimeChannels.values()) channel.leave();
2859
2907
  realtimeChannels.clear();
2860
- ws?.disconnect();
2908
+ ws?.disconnect(true);
2861
2909
  },
2862
2910
  setToken: transport.setToken,
2863
2911
  setAuthTokenGetter: transport.setAuthTokenGetter,