@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.cjs CHANGED
@@ -1593,7 +1593,9 @@ function useSocketConnection(args) {
1593
1593
  React.useEffect(() => {
1594
1594
  if (autoJoin && normalizedRooms.length > 0)
1595
1595
  client.joinRooms(normalizedRooms, args.joinMeta);
1596
- const unsubscribe = client.on(event, onMessage);
1596
+ const unsubscribe = client.on(event, (payload, meta) => {
1597
+ onMessage(payload, meta);
1598
+ });
1597
1599
  return () => {
1598
1600
  unsubscribe();
1599
1601
  if (autoLeave && normalizedRooms.length > 0)
@@ -1650,6 +1652,16 @@ function arrayShallowEqual(a, b) {
1650
1652
  function roomStateEqual(prev, next) {
1651
1653
  return arrayShallowEqual(prev.rooms, next.rooms) && safeJsonKey(prev.joinMeta) === safeJsonKey(next.joinMeta) && safeJsonKey(prev.leaveMeta) === safeJsonKey(next.leaveMeta);
1652
1654
  }
1655
+ function isSameObjectReference(prev, next) {
1656
+ if (prev !== next) return false;
1657
+ if (next == null) return false;
1658
+ const valueType = typeof next;
1659
+ return valueType === "object" || valueType === "function";
1660
+ }
1661
+ function shouldWarnSocketMutationGuard() {
1662
+ const nodeEnv = globalThis.process?.env?.NODE_ENV;
1663
+ return nodeEnv !== "production";
1664
+ }
1653
1665
  function safeDescribeHookValue2(value) {
1654
1666
  if (value == null) return value;
1655
1667
  const valueType = typeof value;
@@ -1930,28 +1942,67 @@ function buildSocketedRoute(options) {
1930
1942
  }
1931
1943
  });
1932
1944
  if (!client) return;
1945
+ const queue = [];
1946
+ const sameRefWarnedEvents = /* @__PURE__ */ new Set();
1947
+ let draining = false;
1948
+ let active = true;
1949
+ const drainQueue = () => {
1950
+ if (!active || draining) return;
1951
+ draining = true;
1952
+ try {
1953
+ while (active && queue.length > 0) {
1954
+ const nextUpdate = queue.shift();
1955
+ if (!nextUpdate) continue;
1956
+ built.setData(
1957
+ (prev) => {
1958
+ const next = nextUpdate.fn(
1959
+ prev,
1960
+ nextUpdate.payload,
1961
+ nextUpdate.meta ? { ...nextUpdate.meta, args: useArgs } : { args: useArgs }
1962
+ );
1963
+ if (next === null) return prev;
1964
+ if (shouldWarnSocketMutationGuard() && isSameObjectReference(prev, next) && !sameRefWarnedEvents.has(nextUpdate.event)) {
1965
+ sameRefWarnedEvents.add(nextUpdate.event);
1966
+ console.warn(
1967
+ `[socketedRoute] applySocket("${nextUpdate.event}") returned the previous reference. Return a new object/array for updates, or return null for no change.`
1968
+ );
1969
+ }
1970
+ const nextRoomState = roomsFromData(
1971
+ next,
1972
+ toRooms
1973
+ );
1974
+ setRoomState(
1975
+ (prevRoomState) => roomStateEqual(prevRoomState, nextRoomState) ? prevRoomState : nextRoomState
1976
+ );
1977
+ return next;
1978
+ },
1979
+ ...useArgs
1980
+ );
1981
+ }
1982
+ } finally {
1983
+ draining = false;
1984
+ if (active && queue.length > 0) drainQueue();
1985
+ }
1986
+ };
1933
1987
  const entries = Object.entries(applySocket).filter(
1934
1988
  ([_event, fn]) => typeof fn === "function"
1935
1989
  );
1936
1990
  const unsubscribes = entries.map(
1937
1991
  ([ev, fn]) => client.on(ev, (payload, meta) => {
1938
- built.setData(
1939
- (prev) => {
1940
- const next = fn(prev, payload, meta);
1941
- const nextRoomState = roomsFromData(
1942
- next,
1943
- toRooms
1944
- );
1945
- setRoomState(
1946
- (prevRoomState) => roomStateEqual(prevRoomState, nextRoomState) ? prevRoomState : nextRoomState
1947
- );
1948
- return next;
1949
- },
1950
- ...useArgs
1951
- );
1992
+ queue.push({
1993
+ event: ev,
1994
+ fn,
1995
+ payload,
1996
+ ...meta ? { meta } : {}
1997
+ });
1998
+ drainQueue();
1952
1999
  })
1953
2000
  );
1954
- return () => unsubscribes.forEach((u) => u?.());
2001
+ return () => {
2002
+ active = false;
2003
+ queue.length = 0;
2004
+ unsubscribes.forEach((u) => u?.());
2005
+ };
1955
2006
  }, [client, applySocket, built, argsKey, toRooms, debug]);
1956
2007
  return { ...endpointResult, rooms: roomState.rooms };
1957
2008
  };
@@ -2464,9 +2515,9 @@ var SocketClient = class {
2464
2515
  };
2465
2516
  }
2466
2517
  const socket = this.socket;
2467
- const wrapped = (envelopeOrRaw) => {
2468
- const maybeEnvelope = envelopeOrRaw;
2469
- const rawData = maybeEnvelope?.data ?? maybeEnvelope;
2518
+ const toStringList = (value) => Array.isArray(value) ? value.filter((entry2) => typeof entry2 === "string") : [];
2519
+ const wrappedEnv = (envelope) => {
2520
+ const rawData = envelope.data;
2470
2521
  const parsed = schema.safeParse(rawData);
2471
2522
  if (!parsed.success) {
2472
2523
  this.dbg({
@@ -2477,15 +2528,17 @@ var SocketClient = class {
2477
2528
  });
2478
2529
  return;
2479
2530
  }
2531
+ const data = parsed.data;
2480
2532
  const receivedAt = /* @__PURE__ */ new Date();
2481
- const sentAt = maybeEnvelope?.sentAt ? new Date(maybeEnvelope.sentAt) : void 0;
2533
+ const sentAt = envelope?.sentAt ? new Date(envelope.sentAt) : void 0;
2482
2534
  const meta = {
2483
2535
  envelope: {
2484
- eventName: maybeEnvelope?.eventName ?? event,
2485
- sentAt: maybeEnvelope?.sentAt ?? receivedAt.toISOString(),
2486
- sentTo: maybeEnvelope?.sentTo ?? [],
2487
- data: void 0,
2488
- metadata: maybeEnvelope?.metadata
2536
+ eventName: typeof envelope?.eventName === "string" ? envelope.eventName : event,
2537
+ sentAt: envelope?.sentAt ?? receivedAt.toISOString(),
2538
+ sentTo: toStringList(envelope?.sentTo),
2539
+ data,
2540
+ metadata: envelope?.metadata,
2541
+ rooms: toStringList(envelope?.rooms)
2489
2542
  },
2490
2543
  ctx: {
2491
2544
  receivedAt,
@@ -2505,22 +2558,38 @@ var SocketClient = class {
2505
2558
  metadata: meta.envelope.metadata
2506
2559
  } : void 0
2507
2560
  });
2508
- handler(parsed.data, meta);
2561
+ handler(data, meta);
2562
+ };
2563
+ const wrappedDispatcher = (envelopeOrRaw) => {
2564
+ if (typeof envelopeOrRaw === "object" && envelopeOrRaw !== null && "eventName" in envelopeOrRaw && "sentAt" in envelopeOrRaw && "sentTo" in envelopeOrRaw && "data" in envelopeOrRaw) {
2565
+ wrappedEnv(envelopeOrRaw);
2566
+ } else {
2567
+ this.dbg({
2568
+ type: "receive",
2569
+ event,
2570
+ envelope: void 0
2571
+ });
2572
+ handler(envelopeOrRaw, void 0);
2573
+ }
2509
2574
  };
2510
2575
  const errorWrapped = (e) => {
2511
2576
  this.dbg({ type: "receive", event, err: String(e) });
2512
2577
  };
2513
- socket.on(String(event), wrapped);
2578
+ socket.on(String(event), wrappedDispatcher);
2514
2579
  socket.on(`${String(event)}:error`, errorWrapped);
2515
2580
  let set = this.handlerMap.get(String(event));
2516
2581
  if (!set) {
2517
2582
  set = /* @__PURE__ */ new Set();
2518
2583
  this.handlerMap.set(String(event), set);
2519
2584
  }
2520
- const entry = { orig: handler, wrapped, errorWrapped };
2585
+ const entry = {
2586
+ orig: handler,
2587
+ wrapped: wrappedDispatcher,
2588
+ errorWrapped
2589
+ };
2521
2590
  set.add(entry);
2522
2591
  return () => {
2523
- socket.off(String(event), wrapped);
2592
+ socket.off(String(event), wrappedDispatcher);
2524
2593
  socket.off(`${String(event)}:error`, errorWrapped);
2525
2594
  const s = this.handlerMap.get(String(event));
2526
2595
  if (s) {