@emeryld/rrroutes-client 2.6.1 → 2.6.3

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.mjs CHANGED
@@ -1557,7 +1557,9 @@ function useSocketConnection(args) {
1557
1557
  React.useEffect(() => {
1558
1558
  if (autoJoin && normalizedRooms.length > 0)
1559
1559
  client.joinRooms(normalizedRooms, args.joinMeta);
1560
- const unsubscribe = client.on(event, onMessage);
1560
+ const unsubscribe = client.on(event, (payload, meta) => {
1561
+ onMessage(payload, meta);
1562
+ });
1561
1563
  return () => {
1562
1564
  unsubscribe();
1563
1565
  if (autoLeave && normalizedRooms.length > 0)
@@ -1614,6 +1616,16 @@ function arrayShallowEqual(a, b) {
1614
1616
  function roomStateEqual(prev, next) {
1615
1617
  return arrayShallowEqual(prev.rooms, next.rooms) && safeJsonKey(prev.joinMeta) === safeJsonKey(next.joinMeta) && safeJsonKey(prev.leaveMeta) === safeJsonKey(next.leaveMeta);
1616
1618
  }
1619
+ function isSameObjectReference(prev, next) {
1620
+ if (prev !== next) return false;
1621
+ if (next == null) return false;
1622
+ const valueType = typeof next;
1623
+ return valueType === "object" || valueType === "function";
1624
+ }
1625
+ function shouldWarnSocketMutationGuard() {
1626
+ const nodeEnv = globalThis.process?.env?.NODE_ENV;
1627
+ return nodeEnv !== "production";
1628
+ }
1617
1629
  function safeDescribeHookValue2(value) {
1618
1630
  if (value == null) return value;
1619
1631
  const valueType = typeof value;
@@ -1894,28 +1906,67 @@ function buildSocketedRoute(options) {
1894
1906
  }
1895
1907
  });
1896
1908
  if (!client) return;
1909
+ const queue = [];
1910
+ const sameRefWarnedEvents = /* @__PURE__ */ new Set();
1911
+ let draining = false;
1912
+ let active = true;
1913
+ const drainQueue = () => {
1914
+ if (!active || draining) return;
1915
+ draining = true;
1916
+ try {
1917
+ while (active && queue.length > 0) {
1918
+ const nextUpdate = queue.shift();
1919
+ if (!nextUpdate) continue;
1920
+ built.setData(
1921
+ (prev) => {
1922
+ const next = nextUpdate.fn(
1923
+ prev,
1924
+ nextUpdate.payload,
1925
+ nextUpdate.meta ? { ...nextUpdate.meta, args: useArgs } : { args: useArgs }
1926
+ );
1927
+ if (next === null) return prev;
1928
+ if (shouldWarnSocketMutationGuard() && isSameObjectReference(prev, next) && !sameRefWarnedEvents.has(nextUpdate.event)) {
1929
+ sameRefWarnedEvents.add(nextUpdate.event);
1930
+ console.warn(
1931
+ `[socketedRoute] applySocket("${nextUpdate.event}") returned the previous reference. Return a new object/array for updates, or return null for no change.`
1932
+ );
1933
+ }
1934
+ const nextRoomState = roomsFromData(
1935
+ next,
1936
+ toRooms
1937
+ );
1938
+ setRoomState(
1939
+ (prevRoomState) => roomStateEqual(prevRoomState, nextRoomState) ? prevRoomState : nextRoomState
1940
+ );
1941
+ return next;
1942
+ },
1943
+ ...useArgs
1944
+ );
1945
+ }
1946
+ } finally {
1947
+ draining = false;
1948
+ if (active && queue.length > 0) drainQueue();
1949
+ }
1950
+ };
1897
1951
  const entries = Object.entries(applySocket).filter(
1898
1952
  ([_event, fn]) => typeof fn === "function"
1899
1953
  );
1900
1954
  const unsubscribes = entries.map(
1901
1955
  ([ev, fn]) => client.on(ev, (payload, meta) => {
1902
- built.setData(
1903
- (prev) => {
1904
- const next = fn(prev, payload, meta);
1905
- const nextRoomState = roomsFromData(
1906
- next,
1907
- toRooms
1908
- );
1909
- setRoomState(
1910
- (prevRoomState) => roomStateEqual(prevRoomState, nextRoomState) ? prevRoomState : nextRoomState
1911
- );
1912
- return next;
1913
- },
1914
- ...useArgs
1915
- );
1956
+ queue.push({
1957
+ event: ev,
1958
+ fn,
1959
+ payload,
1960
+ ...meta ? { meta } : {}
1961
+ });
1962
+ drainQueue();
1916
1963
  })
1917
1964
  );
1918
- return () => unsubscribes.forEach((u) => u?.());
1965
+ return () => {
1966
+ active = false;
1967
+ queue.length = 0;
1968
+ unsubscribes.forEach((u) => u?.());
1969
+ };
1919
1970
  }, [client, applySocket, built, argsKey, toRooms, debug]);
1920
1971
  return { ...endpointResult, rooms: roomState.rooms };
1921
1972
  };
@@ -2428,9 +2479,9 @@ var SocketClient = class {
2428
2479
  };
2429
2480
  }
2430
2481
  const socket = this.socket;
2431
- const wrapped = (envelopeOrRaw) => {
2432
- const maybeEnvelope = envelopeOrRaw;
2433
- const rawData = maybeEnvelope?.data ?? maybeEnvelope;
2482
+ const toStringList = (value) => Array.isArray(value) ? value.filter((entry2) => typeof entry2 === "string") : [];
2483
+ const wrappedEnv = (envelope) => {
2484
+ const rawData = envelope.data;
2434
2485
  const parsed = schema.safeParse(rawData);
2435
2486
  if (!parsed.success) {
2436
2487
  this.dbg({
@@ -2441,15 +2492,17 @@ var SocketClient = class {
2441
2492
  });
2442
2493
  return;
2443
2494
  }
2495
+ const data = parsed.data;
2444
2496
  const receivedAt = /* @__PURE__ */ new Date();
2445
- const sentAt = maybeEnvelope?.sentAt ? new Date(maybeEnvelope.sentAt) : void 0;
2497
+ const sentAt = envelope?.sentAt ? new Date(envelope.sentAt) : void 0;
2446
2498
  const meta = {
2447
2499
  envelope: {
2448
- eventName: maybeEnvelope?.eventName ?? event,
2449
- sentAt: maybeEnvelope?.sentAt ?? receivedAt.toISOString(),
2450
- sentTo: maybeEnvelope?.sentTo ?? [],
2451
- data: void 0,
2452
- metadata: maybeEnvelope?.metadata
2500
+ eventName: typeof envelope?.eventName === "string" ? envelope.eventName : event,
2501
+ sentAt: envelope?.sentAt ?? receivedAt.toISOString(),
2502
+ sentTo: toStringList(envelope?.sentTo),
2503
+ data,
2504
+ metadata: envelope?.metadata,
2505
+ rooms: toStringList(envelope?.rooms)
2453
2506
  },
2454
2507
  ctx: {
2455
2508
  receivedAt,
@@ -2469,22 +2522,38 @@ var SocketClient = class {
2469
2522
  metadata: meta.envelope.metadata
2470
2523
  } : void 0
2471
2524
  });
2472
- handler(parsed.data, meta);
2525
+ handler(data, meta);
2526
+ };
2527
+ const wrappedDispatcher = (envelopeOrRaw) => {
2528
+ if (typeof envelopeOrRaw === "object" && envelopeOrRaw !== null && "eventName" in envelopeOrRaw && "sentAt" in envelopeOrRaw && "sentTo" in envelopeOrRaw && "data" in envelopeOrRaw) {
2529
+ wrappedEnv(envelopeOrRaw);
2530
+ } else {
2531
+ this.dbg({
2532
+ type: "receive",
2533
+ event,
2534
+ envelope: void 0
2535
+ });
2536
+ handler(envelopeOrRaw, void 0);
2537
+ }
2473
2538
  };
2474
2539
  const errorWrapped = (e) => {
2475
2540
  this.dbg({ type: "receive", event, err: String(e) });
2476
2541
  };
2477
- socket.on(String(event), wrapped);
2542
+ socket.on(String(event), wrappedDispatcher);
2478
2543
  socket.on(`${String(event)}:error`, errorWrapped);
2479
2544
  let set = this.handlerMap.get(String(event));
2480
2545
  if (!set) {
2481
2546
  set = /* @__PURE__ */ new Set();
2482
2547
  this.handlerMap.set(String(event), set);
2483
2548
  }
2484
- const entry = { orig: handler, wrapped, errorWrapped };
2549
+ const entry = {
2550
+ orig: handler,
2551
+ wrapped: wrappedDispatcher,
2552
+ errorWrapped
2553
+ };
2485
2554
  set.add(entry);
2486
2555
  return () => {
2487
- socket.off(String(event), wrapped);
2556
+ socket.off(String(event), wrappedDispatcher);
2488
2557
  socket.off(`${String(event)}:error`, errorWrapped);
2489
2558
  const s = this.handlerMap.get(String(event));
2490
2559
  if (s) {