@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 +110 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +111 -61
- package/dist/index.mjs.map +1 -1
- package/dist/sockets/socket.client.context.d.ts +14 -2
- package/dist/sockets/socket.client.debug.d.ts +5 -6
- package/package.json +2 -2
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(
|
|
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(
|
|
558
|
+
dbg(providerDebugRef.current, { type: "resolve", phase: "cancelled" });
|
|
510
559
|
return;
|
|
511
560
|
}
|
|
512
561
|
if (!s) {
|
|
513
|
-
dbg(
|
|
562
|
+
dbg(providerDebugRef.current, { type: "resolve", phase: "missing" });
|
|
514
563
|
return;
|
|
515
564
|
}
|
|
516
565
|
setResolvedSocket(s);
|
|
517
|
-
dbg(
|
|
566
|
+
dbg(providerDebugRef.current, { type: "resolve", phase: "ok" });
|
|
518
567
|
}).catch((err) => {
|
|
519
568
|
if (cancelled) return;
|
|
520
|
-
dbg(
|
|
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(
|
|
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(
|
|
588
|
+
dbg(providerDebugRef.current, { type: "client", phase: "init", missing: false });
|
|
534
589
|
return c;
|
|
535
|
-
}, [events, baseOptions, socket
|
|
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(
|
|
601
|
+
dbg(providerDebugRef.current, { type: "client", phase: "destroy" });
|
|
541
602
|
}
|
|
542
603
|
};
|
|
543
|
-
}, [client,
|
|
544
|
-
|
|
545
|
-
|
|
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: "
|
|
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: "
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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",
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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",
|
|
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",
|
|
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
|
-
|
|
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",
|
|
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",
|
|
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",
|
|
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
|
-
|
|
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",
|
|
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",
|
|
1074
|
+
this.dbg({ type: "register", phase: "register", event });
|
|
1025
1075
|
if (!this.socket) {
|
|
1026
|
-
this.dbg({ type: "register",
|
|
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",
|
|
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("
|
|
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("
|
|
1233
|
+
this.logSocketConfigSnapshot("connect_call");
|
|
1184
1234
|
}
|
|
1185
1235
|
};
|
|
1186
1236
|
// Annotate the CommonJS export names for ESM import in node:
|