@emeryld/rrroutes-client 2.0.12 → 2.1.0

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
@@ -473,6 +473,7 @@ var buildRoomPayloadSchema = (metaSchema) => import_zod.z.object({
473
473
 
474
474
  // src/sockets/socket.client.context.tsx
475
475
  var React = __toESM(require("react"), 1);
476
+ var import_socket = require("socket.io-client");
476
477
  var import_jsx_runtime = require("react/jsx-runtime");
477
478
  var SocketCtx = React.createContext(null);
478
479
  function dbg(dbgOpts, e) {
@@ -480,6 +481,43 @@ function dbg(dbgOpts, e) {
480
481
  if (!dbgOpts[e.type]) return;
481
482
  dbgOpts.logger(e);
482
483
  }
484
+ function safeDescribeHookValue(value) {
485
+ if (value == null) return value;
486
+ const valueType = typeof value;
487
+ if (valueType === "string" || valueType === "number" || valueType === "boolean") return value;
488
+ if (valueType === "bigint" || valueType === "symbol") return String(value);
489
+ if (valueType === "function") return `[function ${value.name || "anonymous"}]`;
490
+ if (Array.isArray(value)) return `[array length=${value.length}]`;
491
+ if (value instanceof import_socket.Socket) {
492
+ const socket = value;
493
+ return `[Socket id=${socket.id ?? "unknown"} connected=${socket.connected ?? false}]`;
494
+ }
495
+ const ctorName = value.constructor?.name ?? "object";
496
+ const keys = Object.keys(value);
497
+ const keyPreview = keys.slice(0, 4).join(",");
498
+ const suffix = keys.length > 4 ? ",\u2026" : "";
499
+ return `[${ctorName} keys=${keyPreview}${suffix}]`;
500
+ }
501
+ function createHookDebugEvent(prev, next, hook) {
502
+ const reason = prev ? "change" : "init";
503
+ const changed = Object.keys(next).reduce((acc, dependency) => {
504
+ const prevValue = prev ? prev[dependency] : void 0;
505
+ const nextValue = next[dependency];
506
+ if (!prev || !Object.is(prevValue, nextValue)) {
507
+ acc.push({ dependency, previous: safeDescribeHookValue(prevValue), next: safeDescribeHookValue(nextValue) });
508
+ }
509
+ return acc;
510
+ }, []);
511
+ if (!changed.length) return null;
512
+ return { type: "hook", hook, reason, changes: changed };
513
+ }
514
+ function trackHookTrigger({ ref, hook, providerDebug, snapshot }) {
515
+ const prev = ref.current;
516
+ ref.current = snapshot;
517
+ if (!providerDebug?.logger || !providerDebug?.hook) return;
518
+ const event = createHookDebugEvent(prev, snapshot, hook);
519
+ if (event) dbg(providerDebug, event);
520
+ }
483
521
  function buildSocketProvider(args) {
484
522
  const { events, options: baseOptions } = args;
485
523
  return {
@@ -499,54 +537,73 @@ function SocketProvider(props) {
499
537
  const { events, baseOptions, children, fallback, providerDebug, destroyLeaveMeta } = props;
500
538
  const [resolvedSocket, setResolvedSocket] = React.useState(null);
501
539
  const socket = "socket" in props ? props.socket ?? null : resolvedSocket;
540
+ const providerDebugRef = React.useRef();
541
+ providerDebugRef.current = providerDebug;
542
+ const resolveEffectDebugRef = React.useRef(null);
543
+ const clientMemoDebugRef = React.useRef(null);
544
+ const destroyEffectDebugRef = React.useRef(null);
502
545
  React.useEffect(() => {
546
+ trackHookTrigger({
547
+ ref: resolveEffectDebugRef,
548
+ hook: "resolve_effect",
549
+ providerDebug: providerDebugRef.current,
550
+ snapshot: { resolvedSocket }
551
+ });
503
552
  if (!("getSocket" in props)) return;
504
553
  let cancelled = false;
505
- dbg(providerDebug, { type: "resolve", phase: "start" });
554
+ dbg(providerDebugRef.current, { type: "resolve", phase: "start" });
506
555
  if (!resolvedSocket) {
507
556
  Promise.resolve(props.getSocket()).then((s) => {
508
557
  if (cancelled) {
509
- dbg(providerDebug, { type: "resolve", phase: "cancelled" });
558
+ dbg(providerDebugRef.current, { type: "resolve", phase: "cancelled" });
510
559
  return;
511
560
  }
512
561
  if (!s) {
513
- dbg(providerDebug, { type: "resolve", phase: "missing" });
562
+ dbg(providerDebugRef.current, { type: "resolve", phase: "missing" });
514
563
  return;
515
564
  }
516
565
  setResolvedSocket(s);
517
- dbg(providerDebug, { type: "resolve", phase: "ok" });
566
+ dbg(providerDebugRef.current, { type: "resolve", phase: "ok" });
518
567
  }).catch((err) => {
519
568
  if (cancelled) return;
520
- dbg(providerDebug, { type: "resolve", phase: "error", err: String(err) });
569
+ dbg(providerDebugRef.current, { type: "resolve", phase: "error", err: String(err) });
521
570
  });
522
571
  }
523
572
  return () => {
524
573
  cancelled = true;
525
574
  };
526
575
  }, [resolvedSocket]);
576
+ trackHookTrigger({
577
+ ref: clientMemoDebugRef,
578
+ hook: "client_memo",
579
+ providerDebug: providerDebugRef.current,
580
+ snapshot: { events, baseOptions, socket }
581
+ });
527
582
  const client = React.useMemo(() => {
528
583
  if (!socket) {
529
- dbg(providerDebug, { type: "client", phase: "missing" });
584
+ dbg(providerDebugRef.current, { type: "client", phase: "init", missing: true });
530
585
  return null;
531
586
  }
532
587
  const c = new SocketClient(events, { ...baseOptions, socket });
533
- dbg(providerDebug, { type: "client", phase: "ready" });
588
+ dbg(providerDebugRef.current, { type: "client", phase: "init", missing: false });
534
589
  return c;
535
- }, [events, baseOptions, socket, providerDebug]);
590
+ }, [events, baseOptions, socket]);
536
591
  React.useEffect(() => {
592
+ trackHookTrigger({
593
+ ref: destroyEffectDebugRef,
594
+ hook: "destroy_effect",
595
+ providerDebug: providerDebugRef.current,
596
+ snapshot: { client, destroyLeaveMeta }
597
+ });
537
598
  return () => {
538
599
  if (client) {
539
600
  client.destroy(destroyLeaveMeta);
540
- dbg(providerDebug, { type: "client", phase: "destroy" });
601
+ dbg(providerDebugRef.current, { type: "client", phase: "destroy" });
541
602
  }
542
603
  };
543
- }, [client, providerDebug]);
544
- if (!client) {
545
- dbg(providerDebug, { type: "render", phase: "waiting_for_socket" });
546
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: fallback ?? children });
547
- }
548
- dbg(providerDebug, { type: "render", phase: "provide" });
549
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SocketCtx.Provider, { value: client, children });
604
+ }, [client, destroyLeaveMeta]);
605
+ dbg(providerDebugRef.current, { type: "render", hasClient: !!client });
606
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SocketCtx.Provider, { value: client, children: client == null ? fallback ?? children : children });
550
607
  }
551
608
  function useSocketClient() {
552
609
  const ctx = React.useContext(SocketCtx);
@@ -591,31 +648,24 @@ var SocketClient = class {
591
648
  intervalMs: hb.intervalMs ?? 15e3,
592
649
  timeoutMs: hb.timeoutMs ?? 7500
593
650
  };
594
- this.dbg({
595
- type: "lifecycle",
596
- phase: "init_start",
597
- socketId: this.socket?.id ?? void 0,
598
- details: {
599
- environment: this.environment
600
- }
601
- });
602
651
  if (!this.socket) {
603
652
  this.dbg({
604
653
  type: "lifecycle",
605
- phase: "init_socket_missing",
654
+ phase: "init",
606
655
  err: "Socket reference is null during initialization"
607
656
  });
608
657
  } else {
609
658
  this.dbg({
610
659
  type: "lifecycle",
611
- phase: "init_ready",
660
+ phase: "init",
612
661
  socketId: this.socket.id,
613
662
  details: {
614
663
  heartbeatIntervalMs: this.hb.intervalMs,
615
- heartbeatTimeoutMs: this.hb.timeoutMs
664
+ heartbeatTimeoutMs: this.hb.timeoutMs,
665
+ environment: this.environment
616
666
  }
617
667
  });
618
- this.logSocketConfigSnapshot("init", "constructor");
668
+ this.logSocketConfigSnapshot("constructor");
619
669
  }
620
670
  this.onConnect = () => {
621
671
  if (!this.socket) {
@@ -630,7 +680,7 @@ var SocketClient = class {
630
680
  nsp: this.getNamespace(this.socket)
631
681
  }
632
682
  });
633
- this.logSocketConfigSnapshot("update", "connect_event");
683
+ this.logSocketConfigSnapshot("connect_event");
634
684
  this.getSysEvent("sys:connect")({
635
685
  socket: this.socket,
636
686
  client: this
@@ -650,7 +700,7 @@ var SocketClient = class {
650
700
  nsp: this.getNamespace(this.socket)
651
701
  }
652
702
  });
653
- this.logSocketConfigSnapshot("update", "reconnect_event");
703
+ this.logSocketConfigSnapshot("reconnect_event");
654
704
  this.getSysEvent("sys:reconnect")({
655
705
  attempt,
656
706
  socket: this.socket,
@@ -670,7 +720,7 @@ var SocketClient = class {
670
720
  roomsTracked: this.roomCounts.size
671
721
  }
672
722
  });
673
- this.logSocketConfigSnapshot("update", "disconnect_event");
723
+ this.logSocketConfigSnapshot("disconnect_event");
674
724
  this.getSysEvent("sys:disconnect")({
675
725
  reason: String(reason),
676
726
  socket: this.socket,
@@ -688,7 +738,7 @@ var SocketClient = class {
688
738
  err: String(err),
689
739
  details: this.getVerboseDetails({ rawError: err })
690
740
  });
691
- this.logSocketConfigSnapshot("update", "connect_error_event");
741
+ this.logSocketConfigSnapshot("connect_error_event");
692
742
  this.getSysEvent("sys:connect_error")({
693
743
  error: String(err),
694
744
  socket: this.socket,
@@ -697,14 +747,14 @@ var SocketClient = class {
697
747
  };
698
748
  this.onPong = (raw) => {
699
749
  if (!this.socket) {
700
- this.dbg({ type: "heartbeat", action: "pong_recv", err: "Socket is null" });
750
+ this.dbg({ type: "heartbeat", phase: "pong_recv", err: "Socket is null" });
701
751
  throw new Error("Socket is null in onPong handler");
702
752
  }
703
753
  const parsed = this.config.pongPayload.safeParse(raw);
704
754
  if (!parsed.success) {
705
755
  this.dbg({
706
756
  type: "heartbeat",
707
- action: "validation_failed",
757
+ phase: "validation_failed",
708
758
  err: `pong payload validation failed: ${parsed.error.message}`,
709
759
  details: this.getValidationDetails(parsed.error)
710
760
  });
@@ -713,7 +763,7 @@ var SocketClient = class {
713
763
  const validated = parsed.data;
714
764
  this.dbg({
715
765
  type: "heartbeat",
716
- action: "pong_recv",
766
+ phase: "pong_recv",
717
767
  payload: validated
718
768
  });
719
769
  this.getSysEvent("sys:pong")({
@@ -760,16 +810,16 @@ var SocketClient = class {
760
810
  secure: typeof opts.secure === "boolean" ? opts.secure : void 0
761
811
  };
762
812
  }
763
- logSocketConfigSnapshot(phase, reason) {
813
+ logSocketConfigSnapshot(reason) {
764
814
  if (!this.debug.logger || !this.debug.config) return;
765
815
  const snapshot = this.snapshotSocketConfig(this.socket);
766
816
  this.dbg({
767
817
  type: "config",
768
- phase,
769
- reason,
770
- socketId: this.socket?.id,
771
- snapshot: snapshot ?? void 0,
772
- err: snapshot ? void 0 : "Socket unavailable for config snapshot"
818
+ phase: reason,
819
+ ...snapshot == null ? { err: "Socket is missing. " } : {
820
+ socketId: this.socket?.id,
821
+ snapshot
822
+ }
773
823
  });
774
824
  }
775
825
  getValidationDetails(error) {
@@ -837,7 +887,7 @@ var SocketClient = class {
837
887
  if (!this.socket) {
838
888
  this.dbg({
839
889
  type: "heartbeat",
840
- action: "start",
890
+ phase: "start",
841
891
  err: "Socket is null"
842
892
  });
843
893
  return;
@@ -845,7 +895,7 @@ var SocketClient = class {
845
895
  const socket = this.socket;
846
896
  this.dbg({
847
897
  type: "heartbeat",
848
- action: "start",
898
+ phase: "start",
849
899
  details: {
850
900
  intervalMs: this.hb.intervalMs,
851
901
  timeoutMs: this.hb.timeoutMs
@@ -855,7 +905,7 @@ var SocketClient = class {
855
905
  if (!socket) {
856
906
  this.dbg({
857
907
  type: "heartbeat",
858
- action: "tick_skip",
908
+ phase: "tick_skip",
859
909
  err: "Socket missing during heartbeat tick"
860
910
  });
861
911
  return;
@@ -868,7 +918,7 @@ var SocketClient = class {
868
918
  if (!check.success) {
869
919
  this.dbg({
870
920
  type: "heartbeat",
871
- action: "validation_failed",
921
+ phase: "validation_failed",
872
922
  err: "ping payload validation failed",
873
923
  details: this.getValidationDetails(check.error)
874
924
  });
@@ -881,7 +931,7 @@ var SocketClient = class {
881
931
  socket.emit("sys:ping", dataToSend);
882
932
  this.dbg({
883
933
  type: "heartbeat",
884
- action: "ping_emit",
934
+ phase: "ping_emit",
885
935
  payload: dataToSend
886
936
  });
887
937
  };
@@ -902,7 +952,7 @@ var SocketClient = class {
902
952
  }
903
953
  this.dbg({
904
954
  type: "heartbeat",
905
- action: "stop",
955
+ phase: "stop",
906
956
  details: {
907
957
  hadTimer
908
958
  }
@@ -933,7 +983,7 @@ var SocketClient = class {
933
983
  }
934
984
  joinRooms(rooms, meta) {
935
985
  if (!this.socket) {
936
- this.dbg({ type: "room", action: "join", rooms: this.toArray(rooms), err: "Socket is null" });
986
+ this.dbg({ type: "room", phase: "join", rooms: this.toArray(rooms), err: "Socket is null" });
937
987
  throw new Error("Socket is null in joinRooms method");
938
988
  }
939
989
  if (!this.getSysEvent("sys:room_join")({
@@ -942,7 +992,7 @@ var SocketClient = class {
942
992
  socket: this.socket,
943
993
  client: this
944
994
  })) {
945
- this.dbg({ type: "room", action: "join", rooms: this.toArray(rooms), err: "sys:room_join handler aborted join" });
995
+ this.dbg({ type: "room", phase: "join", rooms: this.toArray(rooms), err: "sys:room_join handler aborted join" });
946
996
  return;
947
997
  }
948
998
  const list = this.toArray(rooms);
@@ -961,7 +1011,7 @@ var SocketClient = class {
961
1011
  this.rollbackJoinIncrement(toJoin);
962
1012
  this.dbg({
963
1013
  type: "room",
964
- action: "join",
1014
+ phase: "join",
965
1015
  rooms: toJoin,
966
1016
  err: "payload validation failed",
967
1017
  details: this.getValidationDetails(payloadResult.error)
@@ -971,12 +1021,12 @@ var SocketClient = class {
971
1021
  const payload = payloadResult.data;
972
1022
  const normalizedRooms = this.toArray(payload.rooms);
973
1023
  this.socket.emit("sys:room_join", payload);
974
- this.dbg({ type: "room", action: "join", rooms: normalizedRooms });
1024
+ this.dbg({ type: "room", phase: "join", rooms: normalizedRooms });
975
1025
  }
976
1026
  }
977
1027
  leaveRooms(rooms, meta) {
978
1028
  if (!this.socket) {
979
- this.dbg({ type: "room", action: "leave", rooms: this.toArray(rooms), err: "Socket is null" });
1029
+ this.dbg({ type: "room", phase: "leave", rooms: this.toArray(rooms), err: "Socket is null" });
980
1030
  throw new Error("Socket is null in leaveRooms method");
981
1031
  }
982
1032
  if (!this.getSysEvent("sys:room_leave")({
@@ -985,7 +1035,7 @@ var SocketClient = class {
985
1035
  socket: this.socket,
986
1036
  client: this
987
1037
  })) {
988
- this.dbg({ type: "room", action: "leave", rooms: this.toArray(rooms), err: "sys:room_leave handler aborted leave" });
1038
+ this.dbg({ type: "room", phase: "leave", rooms: this.toArray(rooms), err: "sys:room_leave handler aborted leave" });
989
1039
  return;
990
1040
  }
991
1041
  const list = this.toArray(rooms);
@@ -1006,7 +1056,7 @@ var SocketClient = class {
1006
1056
  this.rollbackLeaveDecrement(toLeave);
1007
1057
  this.dbg({
1008
1058
  type: "room",
1009
- action: "leave",
1059
+ phase: "leave",
1010
1060
  rooms: toLeave,
1011
1061
  err: "payload validation failed",
1012
1062
  details: this.getValidationDetails(payloadResult.error)
@@ -1016,14 +1066,14 @@ var SocketClient = class {
1016
1066
  const payload = payloadResult.data;
1017
1067
  const normalizedRooms = this.toArray(payload.rooms);
1018
1068
  this.socket.emit("sys:room_leave", payload);
1019
- this.dbg({ type: "room", action: "leave", rooms: normalizedRooms });
1069
+ this.dbg({ type: "room", phase: "leave", rooms: normalizedRooms });
1020
1070
  }
1021
1071
  }
1022
1072
  on(event, handler) {
1023
1073
  const schema = this.events[event].message;
1024
- this.dbg({ type: "register", action: "register", event });
1074
+ this.dbg({ type: "register", phase: "register", event });
1025
1075
  if (!this.socket) {
1026
- this.dbg({ type: "register", action: "register", event, err: "Socket is null" });
1076
+ this.dbg({ type: "register", phase: "register", event, err: "Socket is null" });
1027
1077
  return () => {
1028
1078
  };
1029
1079
  }
@@ -1091,7 +1141,7 @@ var SocketClient = class {
1091
1141
  s.delete(entry);
1092
1142
  if (s.size === 0) this.handlerMap.delete(String(event));
1093
1143
  }
1094
- this.dbg({ type: "register", action: "unregister", event });
1144
+ this.dbg({ type: "register", phase: "unregister", event });
1095
1145
  };
1096
1146
  }
1097
1147
  /**
@@ -1160,7 +1210,7 @@ var SocketClient = class {
1160
1210
  nsp: this.getNamespace(this.socket)
1161
1211
  }
1162
1212
  });
1163
- this.logSocketConfigSnapshot("update", "disconnect_call");
1213
+ this.logSocketConfigSnapshot("disconnect_call");
1164
1214
  }
1165
1215
  connect() {
1166
1216
  if (!this.socket) {
@@ -1180,7 +1230,7 @@ var SocketClient = class {
1180
1230
  nsp: this.getNamespace(this.socket)
1181
1231
  }
1182
1232
  });
1183
- this.logSocketConfigSnapshot("update", "connect_call");
1233
+ this.logSocketConfigSnapshot("connect_call");
1184
1234
  }
1185
1235
  };
1186
1236
  // Annotate the CommonJS export names for ESM import in node: