@emeryld/rrroutes-client 2.0.7 → 2.0.9

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
@@ -488,16 +488,23 @@ function buildSocketProvider(args) {
488
488
  }
489
489
  function SocketProvider(props) {
490
490
  const { events, baseOptions, children, fallback, providerDebug } = props;
491
- const [socket, setSocket] = React.useState(
492
- "socket" in props ? props.socket : null
493
- );
491
+ const [resolvedSocket, setResolvedSocket] = React.useState(null);
492
+ const socket = "socket" in props ? props.socket ?? null : resolvedSocket;
494
493
  React.useEffect(() => {
494
+ if (!("getSocket" in props)) return;
495
495
  let cancelled = false;
496
- if (!socket && "getSocket" in props) {
497
- dbg(providerDebug, { type: "resolve", phase: "start" });
496
+ dbg(providerDebug, { type: "resolve", phase: "start" });
497
+ if (!resolvedSocket) {
498
498
  Promise.resolve(props.getSocket()).then((s) => {
499
- if (cancelled) return;
500
- setSocket(s);
499
+ if (cancelled) {
500
+ dbg(providerDebug, { type: "resolve", phase: "cancelled" });
501
+ return;
502
+ }
503
+ if (!s) {
504
+ dbg(providerDebug, { type: "resolve", phase: "missing" });
505
+ return;
506
+ }
507
+ setResolvedSocket(s);
501
508
  dbg(providerDebug, { type: "resolve", phase: "ok" });
502
509
  }).catch((err) => {
503
510
  if (cancelled) return;
@@ -507,9 +514,12 @@ function SocketProvider(props) {
507
514
  return () => {
508
515
  cancelled = true;
509
516
  };
510
- }, [socket]);
517
+ }, [resolvedSocket]);
511
518
  const client = React.useMemo(() => {
512
- if (!socket) return null;
519
+ if (!socket) {
520
+ dbg(providerDebug, { type: "client", phase: "missing" });
521
+ return null;
522
+ }
513
523
  const c = new SocketClient(events, { ...baseOptions, socket });
514
524
  dbg(providerDebug, { type: "client", phase: "ready" });
515
525
  return c;
@@ -560,7 +570,7 @@ var SocketClient = class {
560
570
  this.roomCounts = /* @__PURE__ */ new Map();
561
571
  this.handlerMap = /* @__PURE__ */ new Map();
562
572
  this.events = events;
563
- this.socket = opts.socket;
573
+ this.socket = opts.socket ?? null;
564
574
  this.roomJoinEvent = opts.roomJoinEvent ?? "room:join";
565
575
  this.roomLeaveEvent = opts.roomLeaveEvent ?? "room:leave";
566
576
  this.environment = opts.environment ?? "development";
@@ -580,7 +590,8 @@ var SocketClient = class {
580
590
  this.dbg({
581
591
  type: "connection",
582
592
  phase: "connect",
583
- id: this.socket.id ?? ""
593
+ id: this.socket?.id ?? ""
594
+ // CHANGED
584
595
  });
585
596
  this.startHeartbeat();
586
597
  };
@@ -627,11 +638,13 @@ var SocketClient = class {
627
638
  });
628
639
  this.hb.onPong?.({ latencyMs: latency, payload: raw, socket: this.socket });
629
640
  };
630
- this.socket.on("connect", this.onConnect);
631
- this.socket.on("reconnect", this.onReconnect);
632
- this.socket.on("disconnect", this.onDisconnect);
633
- this.socket.on("connect_error", this.onConnectError);
634
- this.socket.on(this.hb.pongEvent, this.onPong);
641
+ if (this.socket) {
642
+ this.socket.on("connect", this.onConnect);
643
+ this.socket.on("reconnect", this.onReconnect);
644
+ this.socket.on("disconnect", this.onDisconnect);
645
+ this.socket.on("connect_error", this.onConnectError);
646
+ this.socket.on(this.hb.pongEvent, this.onPong);
647
+ }
635
648
  }
636
649
  dbg(e) {
637
650
  const d = this.debug;
@@ -659,7 +672,9 @@ var SocketClient = class {
659
672
  }
660
673
  startHeartbeat() {
661
674
  this.stopHeartbeat();
675
+ if (!this.socket) return;
662
676
  const tick = () => {
677
+ if (!this.socket) return;
663
678
  const basePayload = this.hb.makePingPayload({ socket: this.socket }) ?? {};
664
679
  const candidate = { ...basePayload, __clientSentAt: (/* @__PURE__ */ new Date()).toISOString() };
665
680
  const check = this.hb.pingSchema.safeParse(candidate);
@@ -692,6 +707,12 @@ var SocketClient = class {
692
707
  const schema = this.events[event].message;
693
708
  const parsed = schema.safeParse(payload);
694
709
  if (!parsed.success) throw new Error(`Invalid payload for "${event}": ${parsed.error.message}`);
710
+ if (!this.socket) {
711
+ if (this.environment === "development") {
712
+ console.warn(`[socket] emit("${String(event)}") skipped because socket is null`);
713
+ }
714
+ return;
715
+ }
695
716
  if (onAck) {
696
717
  this.socket.timeout(timeoutMs ?? this.hb.timeoutMs).emit(String(event), parsed.data, (ack) => {
697
718
  try {
@@ -716,7 +737,7 @@ var SocketClient = class {
716
737
  this.roomCounts.set(r, next);
717
738
  if (next === 1) toJoin.push(r);
718
739
  }
719
- if (toJoin.length > 0) {
740
+ if (toJoin.length > 0 && this.socket) {
720
741
  this.socket.emit(this.roomJoinEvent, { rooms: toJoin });
721
742
  this.dbg({ type: "room", action: "join", rooms: toJoin });
722
743
  }
@@ -731,7 +752,7 @@ var SocketClient = class {
731
752
  if (next === 0) this.roomCounts.delete(r);
732
753
  else this.roomCounts.set(r, next);
733
754
  }
734
- if (toLeave.length > 0) {
755
+ if (toLeave.length > 0 && this.socket) {
735
756
  this.socket.emit(this.roomLeaveEvent, { rooms: toLeave });
736
757
  this.dbg({ type: "room", action: "leave", rooms: toLeave });
737
758
  }
@@ -739,6 +760,14 @@ var SocketClient = class {
739
760
  on(event, handler) {
740
761
  const schema = this.events[event].message;
741
762
  this.dbg({ type: "register", action: "register", event });
763
+ if (!this.socket) {
764
+ if (this.environment === "development") {
765
+ console.warn(`[socket] on("${String(event)}") skipped because socket is null`);
766
+ }
767
+ return () => {
768
+ };
769
+ }
770
+ const socket = this.socket;
742
771
  const wrapped = (envelopeOrRaw, maybeAck) => {
743
772
  const maybeEnvelope = envelopeOrRaw;
744
773
  const rawData = maybeEnvelope?.data ?? maybeEnvelope;
@@ -757,9 +786,9 @@ var SocketClient = class {
757
786
  ctx: {
758
787
  receivedAt,
759
788
  latencyMs: sentAt ? Math.max(0, receivedAt.getTime() - sentAt.getTime()) : void 0,
760
- nsp: this.socket.nsp,
761
- socketId: this.socket.id,
762
- socket: this.socket,
789
+ nsp: socket.nsp,
790
+ socketId: socket.id,
791
+ socket,
763
792
  reply: typeof maybeAck === "function" ? (d) => {
764
793
  try {
765
794
  maybeAck(d);
@@ -785,8 +814,8 @@ var SocketClient = class {
785
814
  console.warn(`[socket] ${String(event)}:error`, e);
786
815
  }
787
816
  };
788
- this.socket.on(String(event), wrapped);
789
- this.socket.on(`${String(event)}:error`, errorWrapped);
817
+ socket.on(String(event), wrapped);
818
+ socket.on(`${String(event)}:error`, errorWrapped);
790
819
  let set = this.handlerMap.get(String(event));
791
820
  if (!set) {
792
821
  set = /* @__PURE__ */ new Set();
@@ -795,8 +824,8 @@ var SocketClient = class {
795
824
  const entry = { orig: handler, wrapped, errorWrapped };
796
825
  set.add(entry);
797
826
  return () => {
798
- this.socket.off(String(event), wrapped);
799
- this.socket.off(`${String(event)}:error`, errorWrapped);
827
+ socket.off(String(event), wrapped);
828
+ socket.off(`${String(event)}:error`, errorWrapped);
800
829
  const s = this.handlerMap.get(String(event));
801
830
  if (s) {
802
831
  s.delete(entry);
@@ -811,32 +840,37 @@ var SocketClient = class {
811
840
  */
812
841
  destroy() {
813
842
  this.stopHeartbeat();
814
- this.socket.off("connect", this.onConnect);
815
- this.socket.off("reconnect", this.onReconnect);
816
- this.socket.off("disconnect", this.onDisconnect);
817
- this.socket.off("connect_error", this.onConnectError);
818
- this.socket.off(this.hb.pongEvent, this.onPong);
819
- for (const [event, set] of this.handlerMap.entries()) {
820
- for (const entry of set) {
821
- this.socket.off(String(event), entry.wrapped);
822
- this.socket.off(`${String(event)}:error`, entry.errorWrapped);
843
+ const socket = this.socket;
844
+ if (socket) {
845
+ socket.off("connect", this.onConnect);
846
+ socket.off("reconnect", this.onReconnect);
847
+ socket.off("disconnect", this.onDisconnect);
848
+ socket.off("connect_error", this.onConnectError);
849
+ socket.off(this.hb.pongEvent, this.onPong);
850
+ for (const [event, set] of this.handlerMap.entries()) {
851
+ for (const entry of set) {
852
+ socket.off(String(event), entry.wrapped);
853
+ socket.off(`${String(event)}:error`, entry.errorWrapped);
854
+ }
823
855
  }
824
856
  }
825
857
  this.handlerMap.clear();
826
858
  const toLeave = Array.from(this.roomCounts.entries()).filter(([, count]) => count > 0).map(([room]) => room);
827
- if (toLeave.length > 0) {
828
- this.socket.emit(this.roomLeaveEvent, { rooms: toLeave });
859
+ if (toLeave.length > 0 && socket) {
860
+ socket.emit(this.roomLeaveEvent, { rooms: toLeave });
829
861
  this.dbg({ type: "room", action: "leave", rooms: toLeave });
830
862
  }
831
863
  this.roomCounts.clear();
832
864
  }
833
865
  /** Pass-throughs. Managing connection is the caller’s responsibility. */
834
866
  disconnect() {
867
+ if (!this.socket) return;
835
868
  this.stopHeartbeat();
836
869
  this.socket.disconnect();
837
870
  this.dbg({ type: "connection", phase: "disconnect", reason: "client_disconnect" });
838
871
  }
839
872
  connect() {
873
+ if (!this.socket) return;
840
874
  this.socket.connect();
841
875
  this.dbg({ type: "connection", phase: "connect", id: this.socket.id ?? "" });
842
876
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/routesV3.client.fetch.ts","../src/routesV3.client.index.ts","../src/sockets/socket.client.context.tsx","../src/sockets/socket.client.index.ts"],"sourcesContent":["/**\n * This package exports React Query hooks, so we mark it as client-only to keep Next.js happy.\n */\n'use client';\n\nexport * from './routesV3.client.types';\nexport * from './routesV3.client.fetch';\nexport * from './routesV3.client.index';\nexport * from './sockets/socket.client.index';","// routesV3.client.fetch.ts\n\nimport { Fetcher, FetchInput } from './routesV3.client.types';\n\n/**\n * Default fetch implementation used by the route client helper.\n * @param req Normalized request information (URL, method, body, headers).\n * @returns Parsed JSON (or text fallback) from the server response.\n */\nexport const defaultFetcher: Fetcher = async <T>(req: FetchInput): Promise<T> => {\n const headers: Record<string, string> = { ...(req.headers ?? {}) };\n const isFormData = typeof FormData !== 'undefined' && req.body instanceof FormData;\n if (!isFormData) {\n headers['Content-Type'] ||= 'application/json';\n headers['Accept'] ||= 'application/json';\n }\n\n const res = await fetch(req.url, {\n method: req.method,\n headers,\n body: isFormData ? (req.body as any) : req.body == null ? undefined : JSON.stringify(req.body),\n });\n\n const text = await res.text();\n if (!res.ok) {\n const snippet = text.slice(0, 400);\n throw new Error(`[${res.status}] ${res.statusText} — ${snippet}`);\n }\n\n try {\n return JSON.parse(text) as T;\n } catch {\n return text as unknown as T;\n }\n};\n","// routesV3.client.ts\nimport {\n keepPreviousData,\n useInfiniteQuery,\n useMutation,\n useQuery,\n type InfiniteData,\n type QueryKey,\n} from '@tanstack/react-query';\nimport type { ZodType } from 'zod';\nimport {\n HttpMethod,\n buildCacheKey,\n compilePath,\n} from '@emeryld/rrroutes-contract';\nimport type {\n AnyLeaf,\n InferBody,\n InferOutput,\n InferParams,\n InferQuery,\n} from '@emeryld/rrroutes-contract';\nimport { defaultFetcher } from './routesV3.client.fetch';\nimport type {\n ArgsFor,\n ArgsTuple,\n BuildMeta,\n BuiltForLeaf,\n BuiltInfinite,\n BuiltMutation,\n BuiltQuery,\n Cursor,\n DataShape,\n InfiniteBuildOptionsFor,\n MutationBuildOptionsFor,\n QueryBuildOptionsFor,\n RouteClient,\n RouteClientOptions,\n RouteClientDebugEvent,\n RouteClientDebugLogger,\n RouteClientDebugMode,\n RouteClientDebugOptions,\n RouteClientDebugToggleOptions,\n Updater,\n} from './routesV3.client.types';\n\n// -------------------------------------------------------------------------------------\n// Tiny helpers\n// -------------------------------------------------------------------------------------\n/**\n * Convert an HTTP method to uppercase (as expected by fetch).\n * @param m Lowercase HTTP method.\n * @returns Uppercase method string.\n */\nconst toUpper = (m: HttpMethod): Uppercase<HttpMethod> => m.toUpperCase() as Uppercase<HttpMethod>;\n\n/**\n * Parse the given value with the supplied schema (if present).\n * @param value Raw value to validate.\n * @param schema Optional Zod schema used for validation/coercion.\n * @returns The validated or original value.\n */\nfunction zParse<T>(value: unknown, schema?: ZodType): T {\n return schema ? (schema.parse(value) as T) : (value as T);\n}\n\n/**\n * Serialize a query object into a search string.\n * @param query Query params object (possibly undefined).\n * @returns Query string prefixed with `?`, or empty string.\n */\nfunction toSearchString(query: Record<string, unknown> | undefined) {\n if (!query) return '';\n const params = new URLSearchParams();\n for (const [k, v] of Object.entries(query)) {\n if (v == null) continue;\n if (Array.isArray(v)) {\n v.forEach((x) => {\n if (x == null) return;\n if (typeof x === 'object') {\n params.append(k, JSON.stringify(x));\n } else {\n params.append(k, String(x));\n }\n });\n continue;\n }\n if (typeof v === 'object') {\n params.set(k, JSON.stringify(v));\n continue;\n }\n params.set(k, String(v));\n }\n const s = params.toString();\n return s ? `?${s}` : '';\n}\n\n/**\n * Remove the given key from an object (used to drop cursors from cache keys).\n * @param obj Source object.\n * @param key Property name to omit.\n * @returns Copy of the object without the specified key.\n */\nfunction stripKey<Q extends Record<string, unknown> | undefined>(obj: Q, key: string): Q {\n if (!obj) return obj;\n const { [key]: _omit, ...rest } = obj as any;\n return rest as Q;\n}\n\n/**\n * Default cursor extractor used by infinite queries.\n * @param p Page result returned from the server.\n * @returns Next cursor string, if present.\n */\nconst defaultGetNextCursor = (p: unknown): Cursor =>\n p && typeof p === 'object' && 'nextCursor' in p ? (p as any).nextCursor : undefined;\n\n// Debug logging --------------------------------------------------------------\nconst noopDebugLogger: RouteClientDebugLogger = () => {};\n\nconst defaultDebugLogger: RouteClientDebugLogger = (event: RouteClientDebugEvent) => {\n if (typeof console === 'undefined') return;\n const fn = console.debug ?? console.log;\n fn?.call(console, '[rrroutes-client]', event);\n};\n\nconst debugEventTypes: RouteClientDebugEvent['type'][] = [\n 'fetch',\n 'invalidate',\n 'setData',\n 'build',\n 'useEndpoint',\n];\n\ntype DebugEmitter<Names extends string> = {\n emit: (event: RouteClientDebugEvent, name?: Names) => void;\n mode: RouteClientDebugMode;\n};\n\nconst noopEmit = () => {};\n\nfunction createDebugEmitter<Names extends string>(\n option?: RouteClientDebugOptions<Names>,\n environment?: string,\n): DebugEmitter<Names> {\n const disabled: DebugEmitter<Names> = { emit: noopEmit, mode: 'minimal' };\n\n if (environment && environment.toLowerCase() === 'production') {\n return disabled;\n }\n\n if (!option) {\n return disabled;\n }\n if (option === true || option === 'minimal') {\n return {\n emit: (event, name) => defaultDebugLogger(name ? { ...event, name } : event),\n mode: 'minimal',\n };\n }\n if (option === 'complete') {\n return {\n emit: (event, name) => defaultDebugLogger(name ? { ...event, name } : event),\n mode: 'complete',\n };\n }\n if (typeof option === 'function') {\n return {\n emit: (event, name) => option(name ? { ...event, name } : event),\n mode: 'minimal',\n };\n }\n if (typeof option === 'object') {\n const toggles = option as RouteClientDebugToggleOptions<Names>;\n const verbose = Boolean(toggles.verbose);\n const enabledTypes = debugEventTypes.filter((type) => toggles[type]);\n if (enabledTypes.length === 0) {\n return { emit: noopEmit, mode: verbose ? 'complete' : 'minimal' };\n }\n const whitelist = new Set<RouteClientDebugEvent['type']>(enabledTypes);\n const onlySet =\n toggles.only && toggles.only.length > 0 ? new Set<Names>(toggles.only) : undefined;\n const logger = toggles.logger ?? defaultDebugLogger;\n const emit: DebugEmitter<Names>['emit'] = (event, name) => {\n if (!whitelist.has(event.type)) return;\n if (onlySet) {\n if (!name || !onlySet.has(name)) return;\n }\n logger(name ? { ...event, name } : event);\n };\n return { emit, mode: verbose ? 'complete' : 'minimal' };\n }\n\n return disabled;\n}\n\n// Split the variadic tuple at runtime\n/**\n * Extract the optional argument object from a variadic tuple.\n * @param args Tuple passed to a built endpoint helper.\n * @returns The argument object if present.\n */\nfunction extractArgs<L extends AnyLeaf>(args: ArgsTuple<L>): ArgsFor<L> | undefined {\n return (args as unknown as any[])[0] as any;\n}\n\n/**\n * Normalize params and query values, then construct a request URL for the given leaf.\n * @param leaf Leaf describing the endpoint.\n * @param baseUrl Optional base URL prepended to the path.\n * @param params Route parameters supplied by the caller.\n * @param query Query parameters supplied by the caller.\n * @returns Object containing the composed URL plus normalized params/query payloads.\n */\nfunction buildUrl<L extends AnyLeaf>(\n leaf: L,\n baseUrl: string,\n params: InferParams<L> | undefined,\n query: InferQuery<L> | undefined,\n) {\n const normalizedParams = zParse<InferParams<L>>(params, leaf.cfg.paramsSchema);\n const normalizedQuery = zParse<InferQuery<L>>(query, leaf.cfg.querySchema);\n const path = compilePath<L['path']>(leaf.path, (normalizedParams ?? {}) as any);\n const url = `${baseUrl ?? ''}${path}${toSearchString(normalizedQuery as any)}`;\n return { url, normalizedQuery, normalizedParams };\n}\n\n// -------------------------------------------------------------------------------------\n// Client factory\n// -------------------------------------------------------------------------------------\n/**\n * Construct typed React Query helpers backed by a routes-v3 registry leaf.\n * @param opts Route client configuration (query client, fetcher overrides, etc).\n * @returns Object that can build endpoint hooks/mutations from leaves.\n */\nexport function createRouteClient<Names extends string = string>(\n opts: RouteClientOptions<Names>,\n): RouteClient<Names> {\n const queryClient = opts.queryClient;\n const fetcher = opts.fetcher ?? defaultFetcher;\n const baseUrl = opts.baseUrl;\n const cursorParam = opts.cursorParam ?? 'cursor';\n const getNextCursor = opts.getNextCursor ?? defaultGetNextCursor;\n const environment =\n opts.environment ?? undefined;\n const { emit: emitDebug, mode: debugMode } = createDebugEmitter<Names>(opts.debug, environment);\n const isVerboseDebug = debugMode === 'complete';\n const decorateDebugEvent = <T extends RouteClientDebugEvent>(\n event: T,\n details?: Partial<RouteClientDebugEvent>,\n ): RouteClientDebugEvent => {\n if (!isVerboseDebug || !details) return event;\n return { ...event, ...details } as RouteClientDebugEvent;\n };\n\n /**\n * Invalidate a set of queries sharing the given prefix.\n * @param prefix Key parts shared by matching endpoints.\n * @param exact When true, invalidate only exact key matches.\n */\n async function invalidate(prefix: string[], exact = false) {\n const queryKey = prefix as unknown as QueryKey;\n await queryClient.invalidateQueries({ queryKey, exact });\n emitDebug({ type: 'invalidate', key: queryKey, exact });\n }\n\n /**\n * Build the client surface for a single leaf (query/mutation/infinite query).\n * @param leaf Leaf describing the endpoint.\n * @param rqOpts Optional React Query configuration.\n * @returns Helper object exposing key/invalidate/setData/useEndpoint.\n */\n function buildInternal<L extends AnyLeaf>(\n leaf: L,\n rqOpts?: QueryBuildOptionsFor<L> | InfiniteBuildOptionsFor<L> | MutationBuildOptionsFor<L>,\n meta?: BuildMeta<Names>,\n ): BuiltForLeaf<L> {\n const isGet = leaf.method === 'get';\n const isFeed = !!leaf.cfg.feed;\n const method = toUpper(leaf.method);\n const leafLabel = `${leaf.method.toUpperCase()} ${String(leaf.path)}`;\n const debugName = meta?.name;\n const emit = (event: RouteClientDebugEvent) => emitDebug(event, debugName);\n emit({ type: 'build', leaf: leafLabel });\n\n // --- key/invalidate/setData shared helpers ---\n const key = (...tuple: ArgsTuple<L>): QueryKey => {\n const a = extractArgs<L>(tuple);\n const params = (a as any)?.params as InferParams<L> | undefined;\n const query = (a as any)?.query as InferQuery<L> | undefined;\n const qForKey = isGet && isFeed ? stripKey(query as any, cursorParam) : (query as any);\n return buildCacheKey({ leaf, params: params as any, query: qForKey }) as unknown as QueryKey;\n };\n\n /**\n * Invalidate the React Query cache for this exact leaf invocation.\n * @param tuple Optional params/query tuple.\n */\n const invalidateExact = async (...tuple: ArgsTuple<L>) => {\n const queryKey = key(...tuple);\n await queryClient.invalidateQueries({ queryKey, exact: true });\n emit({ type: 'invalidate', key: queryKey, exact: true });\n };\n\n /**\n * Update the cache entries for this leaf.\n * @param args Tuple whose first entry is the updater and optional params/query follow.\n */\n const setData = (...args: [Updater<DataShape<L>>, ...rest: ArgsTuple<L>]) => {\n const [updater, ...rest] = args;\n const k = key(...(rest as ArgsTuple<L>));\n if (isGet && isFeed) {\n queryClient.setQueryData<InfiniteData<InferOutput<L>> | undefined>(k, (prev) =>\n typeof updater === 'function' ? (updater as any)(prev) : (updater as any),\n );\n } else {\n queryClient.setQueryData<InferOutput<L> | undefined>(k, (prev) =>\n typeof updater === 'function' ? (updater as any)(prev) : (updater as any),\n );\n }\n emit({ type: 'setData', key: k });\n };\n\n // --- Infinite GET ---\n if (isGet && isFeed) {\n const useEndpoint: BuiltInfinite<L>['useEndpoint'] = (...tuple) => {\n emit({ type: 'useEndpoint', leaf: leafLabel, variant: 'infiniteGet' });\n const a = extractArgs<L>(tuple);\n const params = (a as any)?.params as InferParams<L> | undefined;\n const query = (a as any)?.query as InferQuery<L> | undefined;\n\n // Normalize once; we’ll inject the cursor per page below.\n const { normalizedQuery, normalizedParams } = buildUrl(leaf, baseUrl, params, query);\n return useInfiniteQuery<\n InferOutput<L>,\n unknown,\n InfiniteData<InferOutput<L>>,\n QueryKey,\n Cursor\n >({\n ...(rqOpts as InfiniteBuildOptionsFor<L>),\n queryKey: key(...tuple),\n initialPageParam: undefined,\n getNextPageParam: (lastPage) => getNextCursor(lastPage),\n placeholderData: keepPreviousData,\n queryFn: async ({ pageParam }) => {\n const pageQuery = {\n ...(normalizedQuery as any),\n ...(pageParam ? { [cursorParam]: pageParam } : {}),\n };\n const { url } = buildUrl(leaf, baseUrl, params, pageQuery);\n const startedAt = Date.now();\n const detail = isVerboseDebug ? { params: normalizedParams, query: pageQuery } : undefined;\n emit(\n decorateDebugEvent(\n { type: 'fetch', stage: 'start', method, url, leaf: leafLabel },\n detail,\n ),\n );\n try {\n const out = await fetcher<unknown>({ url, method });\n const parsed = zParse<InferOutput<L>>(out, leaf.cfg.outputSchema);\n\n // call onReceive after fetch and validation\n (rqOpts as InfiniteBuildOptionsFor<L> & { onReceive?: (data: InferOutput<L>) => void })\n ?.onReceive?.(parsed);\n\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'success',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n },\n isVerboseDebug ? { params: normalizedParams, query: pageQuery, output: parsed } : undefined,\n ),\n );\n return parsed;\n } catch (error) {\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'error',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n error,\n },\n detail,\n ),\n );\n throw error;\n }\n },\n // NOTE: TData is InfiniteData<T>, so we don't need a select here.\n }, queryClient);\n };\n\n return {\n key,\n invalidate: invalidateExact,\n setData: setData as any,\n useEndpoint,\n } as BuiltForLeaf<L>;\n }\n // --- Plain GET ---\n if (isGet) {\n const useEndpoint: BuiltQuery<L>['useEndpoint'] = (...tuple) => {\n emit({ type: 'useEndpoint', leaf: leafLabel, variant: 'get' });\n const a = extractArgs<L>(tuple);\n const params = (a as any)?.params as InferParams<L> | undefined;\n const query = (a as any)?.query as InferQuery<L> | undefined;\n\n const { url, normalizedQuery, normalizedParams } = buildUrl(leaf, baseUrl, params, query);\n return useQuery<InferOutput<L>, unknown, InferOutput<L>, QueryKey>({\n ...(rqOpts as QueryBuildOptionsFor<L>),\n queryKey: key(...tuple),\n placeholderData: keepPreviousData,\n queryFn: async () => {\n const startedAt = Date.now();\n const detail = isVerboseDebug\n ? { params: normalizedParams, query: normalizedQuery }\n : undefined;\n emit(\n decorateDebugEvent(\n { type: 'fetch', stage: 'start', method, url, leaf: leafLabel },\n detail,\n ),\n );\n try {\n const out = await fetcher<unknown>({ url, method });\n const parsed = zParse<InferOutput<L>>(out, leaf.cfg.outputSchema);\n\n // call onReceive after fetch and validation\n (rqOpts as QueryBuildOptionsFor<L> & { onReceive?: (data: InferOutput<L>) => void })\n ?.onReceive?.(parsed);\n\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'success',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n },\n isVerboseDebug\n ? { params: normalizedParams, query: normalizedQuery, output: parsed }\n : undefined,\n ),\n );\n return parsed;\n } catch (error) {\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'error',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n error,\n },\n detail,\n ),\n );\n throw error;\n }\n },\n }, queryClient);\n };\n\n return {\n key,\n invalidate: invalidateExact,\n setData: setData as any,\n useEndpoint,\n } as BuiltForLeaf<L>;\n }\n\n // --- Mutation (POST/PUT/PATCH/DELETE) ---\n const fetchEndpoint: BuiltMutation<L>['fetch'] = async (\n ...tupleWithBody: [...ArgsTuple<L>, InferBody<L>]\n ) => {\n if (tupleWithBody.length === 0) {\n throw new Error('Body is required when invoking a mutation fetch.');\n }\n const bodyIndex = tupleWithBody.length - 1;\n const tuple = tupleWithBody.slice(0, bodyIndex) as ArgsTuple<L>;\n const body = tupleWithBody[bodyIndex] as InferBody<L>;\n const args = extractArgs<L>(tuple);\n const params = (args as any)?.params as InferParams<L> | undefined;\n const query = (args as any)?.query as InferQuery<L> | undefined;\n\n const { url, normalizedQuery, normalizedParams } = buildUrl(leaf, baseUrl, params, query);\n const normalizedBody = zParse<InferBody<L>>(body, leaf.cfg.bodySchema);\n\n const isMultipart = Array.isArray(leaf.cfg.bodyFiles) && leaf.cfg.bodyFiles.length > 0;\n const payload = isMultipart ? toFormData(normalizedBody as any) : normalizedBody;\n\n const startedAt = Date.now();\n const detail = isVerboseDebug\n ? { params: normalizedParams, query: normalizedQuery }\n : undefined;\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'start',\n method,\n url,\n leaf: leafLabel,\n body: payload,\n },\n detail,\n ),\n );\n try {\n const out = await fetcher<unknown>({ url, method, body: payload });\n const parsed = zParse<InferOutput<L>>(out, leaf.cfg.outputSchema);\n\n // call onReceive after fetch and validation\n (rqOpts as MutationBuildOptionsFor<L> & { onReceive?: (data: InferOutput<L>) => void })\n ?.onReceive?.(parsed);\n\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'success',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n },\n isVerboseDebug\n ? { params: normalizedParams, query: normalizedQuery, output: parsed }\n : undefined,\n ),\n );\n return parsed;\n } catch (error) {\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'error',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n body: payload,\n error,\n },\n detail,\n ),\n );\n throw error;\n }\n };\n\n const useEndpoint: BuiltMutation<L>['useEndpoint'] = (...tuple) => {\n emit({ type: 'useEndpoint', leaf: leafLabel, variant: 'mutation' });\n return useMutation<InferOutput<L>, unknown, InferBody<L>, unknown>({\n ...(rqOpts as MutationBuildOptionsFor<L>),\n mutationKey: key(...tuple),\n mutationFn: (body: InferBody<L>) =>\n fetchEndpoint(...([...tuple, body] as [...ArgsTuple<L>, InferBody<L>])),\n }, queryClient);\n };\n\n return {\n key,\n invalidate: invalidateExact,\n setData: setData as any,\n useEndpoint,\n fetch: fetchEndpoint,\n } as BuiltForLeaf<L>;\n }\n\n return {\n queryClient,\n invalidate,\n build: buildInternal as RouteClient<Names>['build'],\n };\n}\n\n// -------------------------------------------------------------------------------------\n// Multipart helper\n// -------------------------------------------------------------------------------------\nfunction toFormData(body: Record<string, any>): FormData {\n const fd = new FormData();\n for (const [k, v] of Object.entries(body ?? {})) {\n if (v == null) continue;\n if (Array.isArray(v)) v.forEach((item, i) => fd.append(`${k}[${i}]`, item as any));\n else fd.append(k, v as any);\n }\n return fd;\n}\n","// packages/rrroutes-client/src/socket.client.context.tsx\n\nimport * as React from 'react';\nimport { Socket } from 'socket.io-client';\nimport {\n SocketClient,\n SocketClientOptions,\n EventMap,\n ClientCtx,\n Payload,\n ServerEnvelope,\n} from './socket.client.index';\nimport { ZodType } from 'zod';\n\n/** === Provider-side debug === */\nexport type SocketProviderDebugEvent =\n | { type: 'resolve'; phase: 'start' | 'ok' | 'error'; err?: string }\n | { type: 'client'; phase: 'ready' | 'destroy' }\n | { type: 'render'; phase: 'waiting_for_socket' | 'provide' };\n\nexport type SocketProviderDebugOptions = {\n verbose?: boolean;\n logger?: (e: SocketProviderDebugEvent) => void;\n} & {\n [P in SocketProviderDebugEvent['type']]?: boolean;\n};\n\n/** === Types for runtime socket injection === */\ntype BaseOptions<Ping extends ZodType, Pong extends ZodType, T extends EventMap> = Omit<\n SocketClientOptions<Ping, Pong, T>,\n 'socket'\n>;\n\ntype ProviderRuntimeSocket =\n | { socket: Socket } // sync socket\n | { getSocket: () => Socket | Promise<Socket> }; // lazy/async socket\n\ntype SocketProviderProps<Ping extends ZodType, Pong extends ZodType, T extends EventMap> =\n React.PropsWithChildren<{\n events: T;\n baseOptions: BaseOptions<Ping, Pong, T>;\n /** show while waiting for async socket; should not use the socket context */\n fallback?: React.ReactNode;\n providerDebug?: SocketProviderDebugOptions;\n } & ProviderRuntimeSocket>;\n\nconst SocketCtx = React.createContext<SocketClient<ZodType, ZodType, any> | null>(null);\n\nfunction dbg(dbgOpts: SocketProviderDebugOptions | undefined, e: SocketProviderDebugEvent) {\n if (!dbgOpts?.logger) return;\n if (!dbgOpts[e.type]) return;\n dbgOpts.logger(e);\n}\n\nexport function buildSocketProvider<Ping extends ZodType, Pong extends ZodType, T extends EventMap>(args: {\n events: T;\n options: BaseOptions<Ping, Pong, T>;\n}) {\n const { events, options: baseOptions } = args;\n\n return {\n SocketProvider: (\n props: React.PropsWithChildren<\n ProviderRuntimeSocket & { fallback?: React.ReactNode; providerDebug?: SocketProviderDebugOptions }\n >\n ) => (\n <SocketProvider<Ping, Pong, T>\n events={events}\n baseOptions={baseOptions}\n {...props}\n />\n ),\n useSocketClient: () => useSocketClient<Ping, Pong, T>(),\n useSocketConnection: <K extends keyof T & string>(\n p: Parameters<typeof useSocketConnection<T, K>>[0]\n ) => useSocketConnection<T, K>(p),\n };\n}\n\nfunction SocketProvider<Ping extends ZodType, Pong extends ZodType, T extends EventMap>(\n props: SocketProviderProps<Ping, Pong, T>\n) {\n const { events, baseOptions, children, fallback, providerDebug } = props;\n\n const [socket, setSocket] = React.useState<Socket | null>(\n 'socket' in props ? props.socket : null\n );\n\n React.useEffect(() => {\n let cancelled = false;\n\n if (!socket && 'getSocket' in props) {\n dbg(providerDebug, { type: 'resolve', phase: 'start' });\n Promise.resolve(props.getSocket())\n .then((s) => {\n if (cancelled) return;\n setSocket(s);\n dbg(providerDebug, { type: 'resolve', phase: 'ok' });\n })\n .catch((err) => {\n if (cancelled) return;\n dbg(providerDebug, { type: 'resolve', phase: 'error', err: String(err) });\n });\n }\n\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [socket]); // run once per lifecycle\n\n const client = React.useMemo(() => {\n if (!socket) return null;\n const c = new SocketClient(events, { ...baseOptions, socket });\n dbg(providerDebug, { type: 'client', phase: 'ready' });\n return c;\n }, [events, baseOptions, socket, providerDebug]);\n\n React.useEffect(() => {\n return () => {\n if (client) {\n client.destroy();\n dbg(providerDebug, { type: 'client', phase: 'destroy' });\n }\n };\n }, [client, providerDebug]);\n\n if (!client) {\n dbg(providerDebug, { type: 'render', phase: 'waiting_for_socket' });\n return <>{fallback ?? children}</>;\n }\n\n dbg(providerDebug, { type: 'render', phase: 'provide' });\n return <SocketCtx.Provider value={client}>{children}</SocketCtx.Provider>;\n}\n\nfunction useSocketClient<Ping extends ZodType, Pong extends ZodType, T extends EventMap>(): SocketClient<\n Ping,\n Pong,\n T\n> {\n const ctx = React.useContext(SocketCtx);\n if (!ctx) throw new Error('SocketClient not found. Wrap with <SocketProvider>.');\n return ctx as unknown as SocketClient<Ping, Pong, T>;\n}\n\ntype Rooms = string[] | string | undefined;\n\nexport type UseSocketConnectionArgs<T extends EventMap, K extends keyof T & string> = {\n event: K;\n rooms?: Rooms;\n onMessage: (\n payload: Payload<T, K>,\n meta: { envelope: ServerEnvelope<T, K>; ctx: ClientCtx }\n ) => void;\n onCleanup?: () => void;\n autoJoin?: boolean;\n autoLeave?: boolean;\n deps?: React.DependencyList;\n};\n\nfunction useSocketConnection<T extends EventMap, K extends keyof T & string>(\n args: UseSocketConnectionArgs<T, K>\n) {\n const { event, rooms, onMessage, onCleanup, autoJoin = true, autoLeave = true } = args;\n const client = useSocketClient<ZodType, ZodType, T>();\n\n const normalizedRooms = React.useMemo(\n () => (rooms == null ? [] : Array.isArray(rooms) ? rooms : [rooms]),\n [rooms]\n );\n\n React.useEffect(() => {\n if (autoJoin && normalizedRooms.length > 0) client.joinRooms(normalizedRooms);\n const unsubscribe = client.on(event, onMessage);\n\n return () => {\n unsubscribe();\n if (autoLeave && normalizedRooms.length > 0) client.leaveRooms(normalizedRooms);\n if (onCleanup) onCleanup();\n };\n }, args.deps ?? [client, event, onMessage, autoJoin, autoLeave, ...normalizedRooms]);\n}\n","// socket.client.index.ts\n\nimport { Socket } from 'socket.io-client';\nimport { z, ZodType } from 'zod';\nimport type { SocketEvent } from '@emeryld/rrroutes-contract';\n\nexport type EventMap = Record<string, SocketEvent>;\nexport type Payload<T extends EventMap, K extends keyof T> = z.infer<T[K]['message']>;\n\nexport type ServerEnvelope<T extends EventMap, K extends keyof T & string> = {\n eventName: K;\n sentAt: string | Date;\n sentTo: string[];\n data?: Payload<T, K>;\n metadata?: Record<string, unknown>;\n};\n\nexport type ClientCtx = {\n receivedAt: Date;\n latencyMs?: number;\n nsp?: string;\n socketId?: string;\n rooms?: string[];\n socket?: Socket;\n reply?: (data?: unknown) => void;\n};\n\nexport type ClientStatsSnapshot = {\n roomsCount: number;\n totalHandlers: number;\n rooms: { room: string; count: number }[];\n handlers: { event: string; handlers: number }[];\n};\n\n// helper, since original code used NoInfer\ntype NoInfer<T> = [T][T extends any ? 0 : never];\n\n/**\n * Merged/logically grouped debug events.\n *\n * Buckets:\n * - connection: connect, reconnect, disconnect, connect_error\n * - register: register, unregister\n * - pingpong: ping_emit, pong_recv\n * - room: join, leave\n * - emit\n * - receive\n * - stats\n */\nexport type SocketClientDebugEvent<K extends string = string> =\n | {\n type: 'connection';\n phase: 'connect' | 'reconnect' | 'disconnect' | 'connect_error';\n id?: string;\n attempt?: number;\n reason?: string;\n err?: string;\n }\n | {\n type: 'register';\n action: 'register' | 'unregister';\n event: K;\n }\n | {\n type: 'heartbeat';\n action: 'ping_emit' | 'pong_recv';\n latencyMs?: number;\n payload?: unknown;\n }\n | {\n type: 'room';\n action: 'join' | 'leave';\n rooms: string[];\n }\n | {\n type: 'emit';\n event: K;\n metadata?: Record<string, unknown>;\n }\n | {\n type: 'receive';\n event: K;\n envelope?: {\n eventName: K;\n sentAt: string | Date;\n sentTo: string[];\n metadata?: Record<string, unknown>;\n };\n };\n\nexport type SocketClientDebugOptions<K extends string = string> = {\n verbose?: boolean;\n only?: K[];\n logger?: (e: SocketClientDebugEvent<K>) => void;\n} & {\n [P in SocketClientDebugEvent['type']]?: boolean;\n};\n\n/** === Heartbeat config (enforced) === */\nexport type HeartbeatClientOptions<Ping extends ZodType, Pong extends ZodType> = {\n /** Event names. Defaults are 'sys:ping' and 'sys:pong'. */\n pingEvent?: string;\n pongEvent?: string;\n /** Interval between pings. Default 15_000. */\n intervalMs?: number;\n /** Give up waiting for pong after this many ms. Default 7_500. */\n timeoutMs?: number;\n\n /** Schema of the ping payload you will emit. */\n pingSchema: Ping;\n /** Produce the ping payload on each tick. */\n makePingPayload: (ctx: { socket: Socket }) => NoInfer<z.infer<Ping>>;\n\n /** Optional validation of the pong payload you receive. */\n pongSchema?: Pong;\n /** Optional hook called on each pong. */\n onPong?: (args: { latencyMs: number; payload?: NoInfer<z.infer<Pong>>; socket: Socket }) => void;\n};\n\nexport type SocketClientOptions<\n Ping extends ZodType,\n Pong extends ZodType,\n T extends EventMap = EventMap\n> = {\n /** Inject an existing socket.io-client Socket. Required. */\n socket: Socket;\n roomJoinEvent?: string;\n roomLeaveEvent?: string;\n environment?: 'development' | 'production';\n debug?: SocketClientDebugOptions<keyof T & string>;\n /** required heartbeat config */\n heartbeat: HeartbeatClientOptions<Ping, Pong>;\n};\n\ntype HandlerEntry<T extends EventMap, K extends keyof T & string> = {\n orig: (payload: Payload<T, K>, meta: { envelope: ServerEnvelope<T, K>; ctx: ClientCtx }) => void;\n wrapped: (envelopeOrRaw: ServerEnvelope<T, K> | Payload<T, K>) => void;\n errorWrapped: (e: unknown) => void;\n};\n\nexport class SocketClient<Ping extends ZodType, Pong extends ZodType, T extends EventMap> {\n readonly socket: Socket;\n private readonly events: T;\n private readonly roomJoinEvent: string;\n private readonly roomLeaveEvent: string;\n private readonly environment: 'development' | 'production';\n private readonly debug: SocketClientDebugOptions<keyof T & string>;\n\n // heartbeat\n private readonly hb: Required<Omit<HeartbeatClientOptions<Ping, Pong>, 'pongSchema' | 'onPong'>> & {\n pongSchema?: z.ZodTypeAny;\n onPong?: HeartbeatClientOptions<Ping, Pong>['onPong'];\n };\n private hbTimer: ReturnType<typeof setInterval> | null = null;\n\n /** keep references so we can .off() later */\n private readonly onConnect: () => void;\n private readonly onReconnect: (attempt: number) => void;\n private readonly onDisconnect: (reason: unknown) => void;\n private readonly onConnectError: (err: unknown) => void;\n private readonly onPong: (raw: any) => void;\n\n // stats\n private readonly roomCounts = new Map<string, number>();\n private readonly handlerMap = new Map<string, Set<HandlerEntry<T, any>>>();\n\n constructor(events: T, opts: SocketClientOptions<Ping, Pong, T>) {\n this.events = events;\n this.socket = opts.socket;\n\n this.roomJoinEvent = opts.roomJoinEvent ?? 'room:join';\n this.roomLeaveEvent = opts.roomLeaveEvent ?? 'room:leave';\n this.environment = opts.environment ?? 'development';\n this.debug = opts.debug ?? {};\n // heartbeat fixed config\n const hb = opts.heartbeat;\n this.hb = {\n pingEvent: hb.pingEvent ?? 'sys:ping',\n pongEvent: hb.pongEvent ?? 'sys:pong',\n intervalMs: hb.intervalMs ?? 15_000,\n timeoutMs: hb.timeoutMs ?? 7_500,\n pingSchema: hb.pingSchema,\n makePingPayload: hb.makePingPayload,\n pongSchema: hb.pongSchema,\n onPong: hb.onPong,\n };\n\n /* socket lifecycle → connection bucket */\n this.onConnect = () => {\n this.dbg({\n type: 'connection',\n phase: 'connect',\n id: this.socket.id ?? '',\n });\n this.startHeartbeat();\n };\n\n this.onReconnect = (attempt) => {\n this.dbg({\n type: 'connection',\n phase: 'reconnect',\n attempt,\n });\n };\n\n this.onDisconnect = (reason) => {\n this.dbg({\n type: 'connection',\n phase: 'disconnect',\n reason: String(reason),\n });\n this.stopHeartbeat();\n };\n\n this.onConnectError = (err) => {\n this.dbg({\n type: 'connection',\n phase: 'connect_error',\n err: String(err),\n });\n };\n\n // wire pong listener → pingpong bucket\n this.onPong = (raw: any) => {\n const receivedAt = Date.now();\n const clientSentIso: string | undefined = raw?.clientEcho?.__clientSentAt;\n let latencyMs: number | undefined;\n\n if (clientSentIso) {\n const sent = Date.parse(clientSentIso);\n if (!Number.isNaN(sent)) latencyMs = Math.max(0, receivedAt - sent);\n }\n\n if (this.hb.pongSchema) {\n const ok = this.hb.pongSchema.safeParse(raw);\n if (!ok.success) return; // drop invalid\n }\n\n const latency = latencyMs ?? raw?.sinceMs ?? 0;\n\n this.dbg({\n type: 'heartbeat',\n action: 'pong_recv',\n latencyMs: latency,\n payload: raw,\n });\n\n this.hb.onPong?.({ latencyMs: latency, payload: raw, socket: this.socket });\n };\n\n // register top-level listeners with stored refs\n this.socket.on('connect', this.onConnect);\n this.socket.on('reconnect', this.onReconnect);\n this.socket.on('disconnect', this.onDisconnect);\n this.socket.on('connect_error', this.onConnectError);\n this.socket.on(this.hb.pongEvent, this.onPong);\n }\n\n private dbg(e: SocketClientDebugEvent<any>) {\n const d = this.debug;\n if (!d.logger) return;\n if (!d[e.type]) return;\n if (d.only && 'event' in e && !d.only.includes(e.event as any)) return;\n d.logger(e);\n }\n\n /** internal stats snapshot */\n stats(): ClientStatsSnapshot {\n const rooms = Array.from(this.roomCounts.entries()).map(([room, count]) => ({ room, count }));\n const handlers = Array.from(this.handlerMap.entries()).map(([event, set]) => ({\n event,\n handlers: set.size,\n }));\n return {\n roomsCount: rooms.length,\n totalHandlers: handlers.reduce((a, b) => a + b.handlers, 0),\n rooms,\n handlers,\n };\n }\n\n private toArray(rooms?: string[] | string): string[] {\n return rooms == null ? [] : Array.isArray(rooms) ? rooms : [rooms];\n }\n\n private startHeartbeat() {\n this.stopHeartbeat();\n\n const tick = () => {\n const basePayload = this.hb.makePingPayload({ socket: this.socket }) ?? {};\n const candidate = { ...basePayload, __clientSentAt: new Date().toISOString() };\n\n const check = this.hb.pingSchema.safeParse(candidate);\n if (!check.success) {\n if (this.environment === 'development')\n console.warn('[socket] ping schema validation failed', check.error.issues);\n return;\n }\n\n const timer = setTimeout(() => {\n /* timeout, no-op here */\n }, this.hb.timeoutMs);\n\n this.socket.timeout(this.hb.timeoutMs).emit(this.hb.pingEvent, { payload: check.data }, () => {\n clearTimeout(timer);\n });\n\n this.dbg({\n type: 'heartbeat',\n action: 'ping_emit',\n payload: check.data,\n });\n };\n\n this.hbTimer = setInterval(tick, this.hb.intervalMs);\n tick();\n }\n\n private stopHeartbeat() {\n if (this.hbTimer) {\n clearInterval(this.hbTimer as any);\n this.hbTimer = null;\n }\n }\n\n emit<K extends keyof T & string>(\n event: K,\n payload: Payload<T, K>,\n metadata?: Record<string, unknown>,\n onAck?: (ack: unknown) => void,\n timeoutMs?: number,\n ): void {\n const schema = this.events[event].message;\n const parsed = schema.safeParse(payload);\n if (!parsed.success) throw new Error(`Invalid payload for \"${event}\": ${parsed.error.message}`);\n\n if (onAck) {\n this.socket.timeout(timeoutMs ?? this.hb.timeoutMs).emit(String(event), parsed.data, (ack: unknown) => {\n try {\n onAck(ack);\n } catch {\n /* noop */\n }\n });\n } else {\n this.socket.emit(String(event), parsed.data);\n }\n\n this.dbg({\n type: 'emit',\n event,\n metadata: this.debug.verbose ? metadata : undefined,\n });\n }\n\n joinRooms(rooms?: string[] | string): void {\n const list = this.toArray(rooms);\n const toJoin: string[] = [];\n for (const r of list) {\n const next = (this.roomCounts.get(r) ?? 0) + 1;\n this.roomCounts.set(r, next);\n if (next === 1) toJoin.push(r);\n }\n if (toJoin.length > 0) {\n this.socket.emit(this.roomJoinEvent, { rooms: toJoin });\n this.dbg({ type: 'room', action: 'join', rooms: toJoin });\n }\n }\n\n leaveRooms(rooms?: string[] | string): void {\n const list = this.toArray(rooms);\n const toLeave: string[] = [];\n for (const r of list) {\n const curr = this.roomCounts.get(r) ?? 0;\n const next = Math.max(0, curr - 1);\n if (next === 0 && curr > 0) toLeave.push(r);\n if (next === 0) this.roomCounts.delete(r);\n else this.roomCounts.set(r, next);\n }\n if (toLeave.length > 0) {\n this.socket.emit(this.roomLeaveEvent, { rooms: toLeave });\n this.dbg({ type: 'room', action: 'leave', rooms: toLeave });\n }\n }\n\n on<K extends keyof T & string>(\n event: K,\n handler: (payload: Payload<T, K>, meta: { envelope: ServerEnvelope<T, K>; ctx: ClientCtx }) => void,\n ): () => void {\n const schema = this.events[event].message;\n\n this.dbg({ type: 'register', action: 'register', event });\n\n const wrapped = (\n envelopeOrRaw: ServerEnvelope<T, K> | Payload<T, K>,\n maybeAck?: (data?: unknown) => void,\n ) => {\n const maybeEnvelope = envelopeOrRaw as any;\n const rawData = maybeEnvelope?.data ?? maybeEnvelope;\n\n const parsed = schema.safeParse(rawData);\n if (!parsed.success) return;\n\n const receivedAt = new Date();\n const sentAt = maybeEnvelope?.sentAt ? new Date(maybeEnvelope.sentAt) : undefined;\n\n const meta = {\n envelope: {\n eventName: (maybeEnvelope?.eventName ?? event) as K,\n sentAt: maybeEnvelope?.sentAt ?? receivedAt.toISOString(),\n sentTo: maybeEnvelope?.sentTo ?? [],\n data: undefined,\n metadata: maybeEnvelope?.metadata,\n },\n ctx: {\n receivedAt,\n latencyMs: sentAt ? Math.max(0, receivedAt.getTime() - sentAt.getTime()) : undefined,\n nsp: (this.socket as any).nsp,\n socketId: this.socket.id,\n socket: this.socket,\n reply:\n typeof maybeAck === 'function'\n ? (d?: unknown) => {\n try {\n maybeAck(d);\n } catch {\n /* noop */\n }\n }\n : undefined,\n },\n } as const;\n\n this.dbg({\n type: 'receive',\n event,\n envelope: this.debug.verbose\n ? {\n eventName: meta.envelope.eventName,\n sentAt: meta.envelope.sentAt,\n sentTo: meta.envelope.sentTo,\n metadata: meta.envelope.metadata,\n }\n : undefined,\n });\n\n handler(parsed.data as any, meta as any);\n };\n\n const errorWrapped = (e: unknown) => {\n if (this.environment === 'development') {\n // eslint-disable-next-line no-console\n console.warn(`[socket] ${String(event)}:error`, e);\n }\n };\n\n this.socket.on(String(event), wrapped);\n this.socket.on(`${String(event)}:error`, errorWrapped);\n\n let set = this.handlerMap.get(String(event));\n if (!set) {\n set = new Set();\n this.handlerMap.set(String(event), set);\n }\n const entry: HandlerEntry<T, K> = { orig: handler, wrapped, errorWrapped };\n set.add(entry);\n\n return () => {\n this.socket.off(String(event), wrapped);\n this.socket.off(`${String(event)}:error`, errorWrapped);\n const s = this.handlerMap.get(String(event));\n if (s) {\n s.delete(entry);\n if (s.size === 0) this.handlerMap.delete(String(event));\n }\n this.dbg({ type: 'register', action: 'unregister', event });\n };\n }\n\n /**\n * Remove all listeners, stop timers, and leave rooms.\n * Call when disposing the client instance.\n */\n destroy(): void {\n // stop heartbeat timer\n this.stopHeartbeat();\n\n // remove top-level socket listeners\n this.socket.off('connect', this.onConnect);\n this.socket.off('reconnect', this.onReconnect);\n this.socket.off('disconnect', this.onDisconnect);\n this.socket.off('connect_error', this.onConnectError);\n this.socket.off(this.hb.pongEvent, this.onPong);\n\n // unsubscribe all per-event handlers\n for (const [event, set] of this.handlerMap.entries()) {\n for (const entry of set) {\n this.socket.off(String(event), entry.wrapped);\n this.socket.off(`${String(event)}:error`, entry.errorWrapped);\n }\n }\n this.handlerMap.clear();\n\n // leave any rooms we joined via ref-count\n const toLeave = Array.from(this.roomCounts.entries())\n .filter(([, count]) => count > 0)\n .map(([room]) => room);\n if (toLeave.length > 0) {\n this.socket.emit(this.roomLeaveEvent, { rooms: toLeave });\n this.dbg({ type: 'room', action: 'leave', rooms: toLeave });\n }\n this.roomCounts.clear();\n }\n\n /** Pass-throughs. Managing connection is the caller’s responsibility. */\n disconnect(): void {\n this.stopHeartbeat();\n this.socket.disconnect();\n this.dbg({ type: 'connection', phase: 'disconnect', reason: 'client_disconnect' });\n }\n\n connect(): void {\n this.socket.connect();\n this.dbg({ type: 'connection', phase: 'connect', id: this.socket.id ?? '' });\n }\n}\n\nexport * from './socket.client.context';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACSO,IAAM,iBAA0B,OAAU,QAAgC;AAC/E,QAAM,UAAkC,EAAE,GAAI,IAAI,WAAW,CAAC,EAAG;AACjE,QAAM,aAAa,OAAO,aAAa,eAAe,IAAI,gBAAgB;AAC1E,MAAI,CAAC,YAAY;AACf,0DAA4B;AAC5B,8CAAsB;AAAA,EACxB;AAEA,QAAM,MAAM,MAAM,MAAM,IAAI,KAAK;AAAA,IAC/B,QAAQ,IAAI;AAAA,IACZ;AAAA,IACA,MAAM,aAAc,IAAI,OAAe,IAAI,QAAQ,OAAO,SAAY,KAAK,UAAU,IAAI,IAAI;AAAA,EAC/F,CAAC;AAED,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,UAAU,KAAK,MAAM,GAAG,GAAG;AACjC,UAAM,IAAI,MAAM,IAAI,IAAI,MAAM,KAAK,IAAI,UAAU,WAAM,OAAO,EAAE;AAAA,EAClE;AAEA,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACjCA,yBAOO;AAEP,+BAIO;AAwCP,IAAM,UAAU,CAAC,MAAyC,EAAE,YAAY;AAQxE,SAAS,OAAU,OAAgB,QAAqB;AACtD,SAAO,SAAU,OAAO,MAAM,KAAK,IAAW;AAChD;AAOA,SAAS,eAAe,OAA4C;AAClE,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,SAAS,IAAI,gBAAgB;AACnC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC1C,QAAI,KAAK,KAAM;AACf,QAAI,MAAM,QAAQ,CAAC,GAAG;AACpB,QAAE,QAAQ,CAAC,MAAM;AACf,YAAI,KAAK,KAAM;AACf,YAAI,OAAO,MAAM,UAAU;AACzB,iBAAO,OAAO,GAAG,KAAK,UAAU,CAAC,CAAC;AAAA,QACpC,OAAO;AACL,iBAAO,OAAO,GAAG,OAAO,CAAC,CAAC;AAAA,QAC5B;AAAA,MACF,CAAC;AACD;AAAA,IACF;AACA,QAAI,OAAO,MAAM,UAAU;AACzB,aAAO,IAAI,GAAG,KAAK,UAAU,CAAC,CAAC;AAC/B;AAAA,IACF;AACA,WAAO,IAAI,GAAG,OAAO,CAAC,CAAC;AAAA,EACzB;AACA,QAAM,IAAI,OAAO,SAAS;AAC1B,SAAO,IAAI,IAAI,CAAC,KAAK;AACvB;AAQA,SAAS,SAAwD,KAAQ,KAAgB;AACvF,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,EAAE,CAAC,GAAG,GAAG,OAAO,GAAG,KAAK,IAAI;AAClC,SAAO;AACT;AAOA,IAAM,uBAAuB,CAAC,MAC5B,KAAK,OAAO,MAAM,YAAY,gBAAgB,IAAK,EAAU,aAAa;AAK5E,IAAM,qBAA6C,CAAC,UAAiC;AACnF,MAAI,OAAO,YAAY,YAAa;AACpC,QAAM,KAAK,QAAQ,SAAS,QAAQ;AACpC,MAAI,KAAK,SAAS,qBAAqB,KAAK;AAC9C;AAEA,IAAM,kBAAmD;AAAA,EACvD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAOA,IAAM,WAAW,MAAM;AAAC;AAExB,SAAS,mBACP,QACA,aACqB;AACrB,QAAM,WAAgC,EAAE,MAAM,UAAU,MAAM,UAAU;AAExE,MAAI,eAAe,YAAY,YAAY,MAAM,cAAc;AAC7D,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AACA,MAAI,WAAW,QAAQ,WAAW,WAAW;AAC3C,WAAO;AAAA,MACL,MAAM,CAAC,OAAO,SAAS,mBAAmB,OAAO,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK;AAAA,MAC3E,MAAM;AAAA,IACR;AAAA,EACF;AACA,MAAI,WAAW,YAAY;AACzB,WAAO;AAAA,MACL,MAAM,CAAC,OAAO,SAAS,mBAAmB,OAAO,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK;AAAA,MAC3E,MAAM;AAAA,IACR;AAAA,EACF;AACA,MAAI,OAAO,WAAW,YAAY;AAChC,WAAO;AAAA,MACL,MAAM,CAAC,OAAO,SAAS,OAAO,OAAO,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK;AAAA,MAC/D,MAAM;AAAA,IACR;AAAA,EACF;AACA,MAAI,OAAO,WAAW,UAAU;AAC9B,UAAM,UAAU;AAChB,UAAM,UAAU,QAAQ,QAAQ,OAAO;AACvC,UAAM,eAAe,gBAAgB,OAAO,CAAC,SAAS,QAAQ,IAAI,CAAC;AACnE,QAAI,aAAa,WAAW,GAAG;AAC7B,aAAO,EAAE,MAAM,UAAU,MAAM,UAAU,aAAa,UAAU;AAAA,IAClE;AACA,UAAM,YAAY,IAAI,IAAmC,YAAY;AACrE,UAAM,UACJ,QAAQ,QAAQ,QAAQ,KAAK,SAAS,IAAI,IAAI,IAAW,QAAQ,IAAI,IAAI;AAC3E,UAAM,SAAS,QAAQ,UAAU;AACjC,UAAM,OAAoC,CAAC,OAAO,SAAS;AACzD,UAAI,CAAC,UAAU,IAAI,MAAM,IAAI,EAAG;AAChC,UAAI,SAAS;AACX,YAAI,CAAC,QAAQ,CAAC,QAAQ,IAAI,IAAI,EAAG;AAAA,MACnC;AACA,aAAO,OAAO,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK;AAAA,IAC1C;AACA,WAAO,EAAE,MAAM,MAAM,UAAU,aAAa,UAAU;AAAA,EACxD;AAEA,SAAO;AACT;AAQA,SAAS,YAA+B,MAA4C;AAClF,SAAQ,KAA0B,CAAC;AACrC;AAUA,SAAS,SACP,MACA,SACA,QACA,OACA;AACA,QAAM,mBAAmB,OAAuB,QAAQ,KAAK,IAAI,YAAY;AAC7E,QAAM,kBAAkB,OAAsB,OAAO,KAAK,IAAI,WAAW;AACzE,QAAM,WAAO,sCAAuB,KAAK,MAAO,oBAAoB,CAAC,CAAS;AAC9E,QAAM,MAAM,GAAG,WAAW,EAAE,GAAG,IAAI,GAAG,eAAe,eAAsB,CAAC;AAC5E,SAAO,EAAE,KAAK,iBAAiB,iBAAiB;AAClD;AAUO,SAAS,kBACd,MACoB;AACpB,QAAM,cAAc,KAAK;AACzB,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,UAAU,KAAK;AACrB,QAAM,cAAc,KAAK,eAAe;AACxC,QAAM,gBAAgB,KAAK,iBAAiB;AAC5C,QAAM,cACJ,KAAK,eAAe;AACtB,QAAM,EAAE,MAAM,WAAW,MAAM,UAAU,IAAI,mBAA0B,KAAK,OAAO,WAAW;AAC9F,QAAM,iBAAiB,cAAc;AACrC,QAAM,qBAAqB,CACzB,OACA,YAC0B;AAC1B,QAAI,CAAC,kBAAkB,CAAC,QAAS,QAAO;AACxC,WAAO,EAAE,GAAG,OAAO,GAAG,QAAQ;AAAA,EAChC;AAOA,iBAAe,WAAW,QAAkB,QAAQ,OAAO;AACzD,UAAM,WAAW;AACjB,UAAM,YAAY,kBAAkB,EAAE,UAAU,MAAM,CAAC;AACvD,cAAU,EAAE,MAAM,cAAc,KAAK,UAAU,MAAM,CAAC;AAAA,EACxD;AAQA,WAAS,cACP,MACA,QACA,MACiB;AACjB,UAAM,QAAQ,KAAK,WAAW;AAC9B,UAAM,SAAS,CAAC,CAAC,KAAK,IAAI;AAC1B,UAAM,SAAS,QAAQ,KAAK,MAAM;AAClC,UAAM,YAAY,GAAG,KAAK,OAAO,YAAY,CAAC,IAAI,OAAO,KAAK,IAAI,CAAC;AACnE,UAAM,YAAY,MAAM;AACxB,UAAM,OAAO,CAAC,UAAiC,UAAU,OAAO,SAAS;AACzE,SAAK,EAAE,MAAM,SAAS,MAAM,UAAU,CAAC;AAGvC,UAAM,MAAM,IAAI,UAAkC;AAChD,YAAM,IAAI,YAAe,KAAK;AAC9B,YAAM,SAAU,GAAW;AAC3B,YAAM,QAAS,GAAW;AAC1B,YAAM,UAAU,SAAS,SAAS,SAAS,OAAc,WAAW,IAAK;AACzE,iBAAO,wCAAc,EAAE,MAAM,QAAuB,OAAO,QAAQ,CAAC;AAAA,IACtE;AAMA,UAAM,kBAAkB,UAAU,UAAwB;AACxD,YAAM,WAAW,IAAI,GAAG,KAAK;AAC7B,YAAM,YAAY,kBAAkB,EAAE,UAAU,OAAO,KAAK,CAAC;AAC7D,WAAK,EAAE,MAAM,cAAc,KAAK,UAAU,OAAO,KAAK,CAAC;AAAA,IACzD;AAMA,UAAM,UAAU,IAAI,SAAyD;AAC3E,YAAM,CAAC,SAAS,GAAG,IAAI,IAAI;AAC3B,YAAM,IAAI,IAAI,GAAI,IAAqB;AACvC,UAAI,SAAS,QAAQ;AACnB,oBAAY;AAAA,UAAuD;AAAA,UAAG,CAAC,SACrE,OAAO,YAAY,aAAc,QAAgB,IAAI,IAAK;AAAA,QAC5D;AAAA,MACF,OAAO;AACL,oBAAY;AAAA,UAAyC;AAAA,UAAG,CAAC,SACvD,OAAO,YAAY,aAAc,QAAgB,IAAI,IAAK;AAAA,QAC5D;AAAA,MACF;AACA,WAAK,EAAE,MAAM,WAAW,KAAK,EAAE,CAAC;AAAA,IAClC;AAGA,QAAI,SAAS,QAAQ;AACnB,YAAMA,eAA+C,IAAI,UAAU;AACjE,aAAK,EAAE,MAAM,eAAe,MAAM,WAAW,SAAS,cAAc,CAAC;AACrE,cAAM,IAAI,YAAe,KAAK;AAC9B,cAAM,SAAU,GAAW;AAC3B,cAAM,QAAS,GAAW;AAG1B,cAAM,EAAE,iBAAiB,iBAAiB,IAAI,SAAS,MAAM,SAAS,QAAQ,KAAK;AACnF,mBAAO,qCAML;AAAA,UACA,GAAI;AAAA,UACJ,UAAU,IAAI,GAAG,KAAK;AAAA,UACtB,kBAAkB;AAAA,UAClB,kBAAkB,CAAC,aAAa,cAAc,QAAQ;AAAA,UACtD,iBAAiB;AAAA,UACjB,SAAS,OAAO,EAAE,UAAU,MAAM;AAChC,kBAAM,YAAY;AAAA,cAChB,GAAI;AAAA,cACJ,GAAI,YAAY,EAAE,CAAC,WAAW,GAAG,UAAU,IAAI,CAAC;AAAA,YAClD;AACA,kBAAM,EAAE,IAAI,IAAI,SAAS,MAAM,SAAS,QAAQ,SAAS;AACzD,kBAAM,YAAY,KAAK,IAAI;AAC3B,kBAAM,SAAS,iBAAiB,EAAE,QAAQ,kBAAkB,OAAO,UAAU,IAAI;AACjF;AAAA,cACE;AAAA,gBACE,EAAE,MAAM,SAAS,OAAO,SAAS,QAAQ,KAAK,MAAM,UAAU;AAAA,gBAC9D;AAAA,cACF;AAAA,YACF;AACA,gBAAI;AACF,oBAAM,MAAM,MAAM,QAAiB,EAAE,KAAK,OAAO,CAAC;AAClD,oBAAM,SAAS,OAAuB,KAAK,KAAK,IAAI,YAAY;AAGhE,cAAC,QACG,YAAY,MAAM;AAEtB;AAAA,gBACE;AAAA,kBACE;AAAA,oBACE,MAAM;AAAA,oBACN,OAAO;AAAA,oBACP;AAAA,oBACA;AAAA,oBACA,MAAM;AAAA,oBACN,YAAY,KAAK,IAAI,IAAI;AAAA,kBAC3B;AAAA,kBACA,iBAAiB,EAAE,QAAQ,kBAAkB,OAAO,WAAW,QAAQ,OAAO,IAAI;AAAA,gBACpF;AAAA,cACF;AACA,qBAAO;AAAA,YACT,SAAS,OAAO;AACd;AAAA,gBACE;AAAA,kBACE;AAAA,oBACE,MAAM;AAAA,oBACN,OAAO;AAAA,oBACP;AAAA,oBACA;AAAA,oBACA,MAAM;AAAA,oBACN,YAAY,KAAK,IAAI,IAAI;AAAA,oBACzB;AAAA,kBACF;AAAA,kBACA;AAAA,gBACF;AAAA,cACF;AACA,oBAAM;AAAA,YACR;AAAA,UACF;AAAA;AAAA,QAEF,GAAG,WAAW;AAAA,MAChB;AAEA,aAAO;AAAA,QACL;AAAA,QACA,YAAY;AAAA,QACZ;AAAA,QACA,aAAAA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,OAAO;AACT,YAAMA,eAA4C,IAAI,UAAU;AAC9D,aAAK,EAAE,MAAM,eAAe,MAAM,WAAW,SAAS,MAAM,CAAC;AAC7D,cAAM,IAAI,YAAe,KAAK;AAC9B,cAAM,SAAU,GAAW;AAC3B,cAAM,QAAS,GAAW;AAE1B,cAAM,EAAE,KAAK,iBAAiB,iBAAiB,IAAI,SAAS,MAAM,SAAS,QAAQ,KAAK;AACxF,mBAAO,6BAA4D;AAAA,UACjE,GAAI;AAAA,UACJ,UAAU,IAAI,GAAG,KAAK;AAAA,UACtB,iBAAiB;AAAA,UACjB,SAAS,YAAY;AACnB,kBAAM,YAAY,KAAK,IAAI;AAC3B,kBAAM,SAAS,iBACX,EAAE,QAAQ,kBAAkB,OAAO,gBAAgB,IACnD;AACJ;AAAA,cACE;AAAA,gBACE,EAAE,MAAM,SAAS,OAAO,SAAS,QAAQ,KAAK,MAAM,UAAU;AAAA,gBAC9D;AAAA,cACF;AAAA,YACF;AACA,gBAAI;AACF,oBAAM,MAAM,MAAM,QAAiB,EAAE,KAAK,OAAO,CAAC;AAClD,oBAAM,SAAS,OAAuB,KAAK,KAAK,IAAI,YAAY;AAGhE,cAAC,QACG,YAAY,MAAM;AAEtB;AAAA,gBACE;AAAA,kBACE;AAAA,oBACE,MAAM;AAAA,oBACN,OAAO;AAAA,oBACP;AAAA,oBACA;AAAA,oBACA,MAAM;AAAA,oBACN,YAAY,KAAK,IAAI,IAAI;AAAA,kBAC3B;AAAA,kBACA,iBACI,EAAE,QAAQ,kBAAkB,OAAO,iBAAiB,QAAQ,OAAO,IACnE;AAAA,gBACN;AAAA,cACF;AACA,qBAAO;AAAA,YACT,SAAS,OAAO;AACd;AAAA,gBACE;AAAA,kBACE;AAAA,oBACE,MAAM;AAAA,oBACN,OAAO;AAAA,oBACP;AAAA,oBACA;AAAA,oBACA,MAAM;AAAA,oBACN,YAAY,KAAK,IAAI,IAAI;AAAA,oBACzB;AAAA,kBACF;AAAA,kBACA;AAAA,gBACF;AAAA,cACF;AACA,oBAAM;AAAA,YACR;AAAA,UACF;AAAA,QACF,GAAG,WAAW;AAAA,MAChB;AAEA,aAAO;AAAA,QACL;AAAA,QACA,YAAY;AAAA,QACZ;AAAA,QACA,aAAAA;AAAA,MACF;AAAA,IACF;AAGA,UAAM,gBAA2C,UAC5C,kBACA;AACH,UAAI,cAAc,WAAW,GAAG;AAC9B,cAAM,IAAI,MAAM,kDAAkD;AAAA,MACpE;AACA,YAAM,YAAY,cAAc,SAAS;AACzC,YAAM,QAAQ,cAAc,MAAM,GAAG,SAAS;AAC9C,YAAM,OAAO,cAAc,SAAS;AACpC,YAAM,OAAO,YAAe,KAAK;AACjC,YAAM,SAAU,MAAc;AAC9B,YAAM,QAAS,MAAc;AAE7B,YAAM,EAAE,KAAK,iBAAiB,iBAAiB,IAAI,SAAS,MAAM,SAAS,QAAQ,KAAK;AACxF,YAAM,iBAAiB,OAAqB,MAAM,KAAK,IAAI,UAAU;AAErE,YAAM,cAAc,MAAM,QAAQ,KAAK,IAAI,SAAS,KAAK,KAAK,IAAI,UAAU,SAAS;AACrF,YAAM,UAAU,cAAc,WAAW,cAAqB,IAAI;AAElE,YAAM,YAAY,KAAK,IAAI;AAC3B,YAAM,SAAS,iBACX,EAAE,QAAQ,kBAAkB,OAAO,gBAAgB,IACnD;AACJ;AAAA,QACE;AAAA,UACE;AAAA,YACE,MAAM;AAAA,YACN,OAAO;AAAA,YACP;AAAA,YACA;AAAA,YACA,MAAM;AAAA,YACN,MAAM;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,UAAI;AACF,cAAM,MAAM,MAAM,QAAiB,EAAE,KAAK,QAAQ,MAAM,QAAQ,CAAC;AACjE,cAAM,SAAS,OAAuB,KAAK,KAAK,IAAI,YAAY;AAGhE,QAAC,QACG,YAAY,MAAM;AAEtB;AAAA,UACE;AAAA,YACE;AAAA,cACE,MAAM;AAAA,cACN,OAAO;AAAA,cACP;AAAA,cACA;AAAA,cACA,MAAM;AAAA,cACN,YAAY,KAAK,IAAI,IAAI;AAAA,YAC3B;AAAA,YACA,iBACI,EAAE,QAAQ,kBAAkB,OAAO,iBAAiB,QAAQ,OAAO,IACnE;AAAA,UACN;AAAA,QACF;AACA,eAAO;AAAA,MACT,SAAS,OAAO;AACd;AAAA,UACE;AAAA,YACE;AAAA,cACE,MAAM;AAAA,cACN,OAAO;AAAA,cACP;AAAA,cACA;AAAA,cACA,MAAM;AAAA,cACN,YAAY,KAAK,IAAI,IAAI;AAAA,cACzB,MAAM;AAAA,cACN;AAAA,YACF;AAAA,YACA;AAAA,UACF;AAAA,QACF;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAEA,UAAM,cAA+C,IAAI,UAAU;AACjE,WAAK,EAAE,MAAM,eAAe,MAAM,WAAW,SAAS,WAAW,CAAC;AAClE,iBAAO,gCAA4D;AAAA,QACjE,GAAI;AAAA,QACJ,aAAa,IAAI,GAAG,KAAK;AAAA,QACzB,YAAY,CAAC,SACX,cAAc,GAAI,CAAC,GAAG,OAAO,IAAI,CAAqC;AAAA,MAC1E,GAAG,WAAW;AAAA,IAChB;AAEA,WAAO;AAAA,MACL;AAAA,MACA,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO;AAAA,EACT;AACF;AAKA,SAAS,WAAW,MAAqC;AACvD,QAAM,KAAK,IAAI,SAAS;AACxB,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,QAAQ,CAAC,CAAC,GAAG;AAC/C,QAAI,KAAK,KAAM;AACf,QAAI,MAAM,QAAQ,CAAC,EAAG,GAAE,QAAQ,CAAC,MAAM,MAAM,GAAG,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,IAAW,CAAC;AAAA,QAC5E,IAAG,OAAO,GAAG,CAAQ;AAAA,EAC5B;AACA,SAAO;AACT;;;AC3lBA,YAAuB;AAgEjB;AApBN,IAAM,YAAkB,oBAA0D,IAAI;AAEtF,SAAS,IAAI,SAAiD,GAA6B;AACzF,MAAI,CAAC,SAAS,OAAQ;AACtB,MAAI,CAAC,QAAQ,EAAE,IAAI,EAAG;AACtB,UAAQ,OAAO,CAAC;AAClB;AAEO,SAAS,oBAAoF,MAGjG;AACD,QAAM,EAAE,QAAQ,SAAS,YAAY,IAAI;AAEzC,SAAO;AAAA,IACL,gBAAgB,CACd,UAIA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACC,GAAG;AAAA;AAAA,IACN;AAAA,IAEF,iBAAiB,MAAM,gBAA+B;AAAA,IACtD,qBAAqB,CACnB,MACG,oBAA0B,CAAC;AAAA,EAClC;AACF;AAEA,SAAS,eACP,OACA;AACA,QAAM,EAAE,QAAQ,aAAa,UAAU,UAAU,cAAc,IAAI;AAEnE,QAAM,CAAC,QAAQ,SAAS,IAAU;AAAA,IAChC,YAAY,QAAQ,MAAM,SAAS;AAAA,EACrC;AAEA,EAAM,gBAAU,MAAM;AACpB,QAAI,YAAY;AAEhB,QAAI,CAAC,UAAU,eAAe,OAAO;AACnC,UAAI,eAAe,EAAE,MAAM,WAAW,OAAO,QAAQ,CAAC;AACtD,cAAQ,QAAQ,MAAM,UAAU,CAAC,EAC9B,KAAK,CAAC,MAAM;AACX,YAAI,UAAW;AACf,kBAAU,CAAC;AACX,YAAI,eAAe,EAAE,MAAM,WAAW,OAAO,KAAK,CAAC;AAAA,MACrD,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,YAAI,UAAW;AACf,YAAI,eAAe,EAAE,MAAM,WAAW,OAAO,SAAS,KAAK,OAAO,GAAG,EAAE,CAAC;AAAA,MAC1E,CAAC;AAAA,IACL;AAEA,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EAEF,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,SAAe,cAAQ,MAAM;AACjC,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,IAAI,IAAI,aAAa,QAAQ,EAAE,GAAG,aAAa,OAAO,CAAC;AAC7D,QAAI,eAAe,EAAE,MAAM,UAAU,OAAO,QAAQ,CAAC;AACrD,WAAO;AAAA,EACT,GAAG,CAAC,QAAQ,aAAa,QAAQ,aAAa,CAAC;AAE/C,EAAM,gBAAU,MAAM;AACpB,WAAO,MAAM;AACX,UAAI,QAAQ;AACV,eAAO,QAAQ;AACf,YAAI,eAAe,EAAE,MAAM,UAAU,OAAO,UAAU,CAAC;AAAA,MACzD;AAAA,IACF;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,CAAC;AAE1B,MAAI,CAAC,QAAQ;AACX,QAAI,eAAe,EAAE,MAAM,UAAU,OAAO,qBAAqB,CAAC;AAClE,WAAO,2EAAG,sBAAY,UAAS;AAAA,EACjC;AAEA,MAAI,eAAe,EAAE,MAAM,UAAU,OAAO,UAAU,CAAC;AACvD,SAAO,4CAAC,UAAU,UAAV,EAAmB,OAAO,QAAS,UAAS;AACtD;AAEA,SAAS,kBAIP;AACA,QAAM,MAAY,iBAAW,SAAS;AACtC,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,qDAAqD;AAC/E,SAAO;AACT;AAiBA,SAAS,oBACP,MACA;AACA,QAAM,EAAE,OAAO,OAAO,WAAW,WAAW,WAAW,MAAM,YAAY,KAAK,IAAI;AAClF,QAAM,SAAS,gBAAqC;AAEpD,QAAM,kBAAwB;AAAA,IAC5B,MAAO,SAAS,OAAO,CAAC,IAAI,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAAA,IACjE,CAAC,KAAK;AAAA,EACR;AAEA,EAAM,gBAAU,MAAM;AACpB,QAAI,YAAY,gBAAgB,SAAS,EAAG,QAAO,UAAU,eAAe;AAC5E,UAAM,cAAc,OAAO,GAAG,OAAO,SAAS;AAE9C,WAAO,MAAM;AACX,kBAAY;AACZ,UAAI,aAAa,gBAAgB,SAAS,EAAG,QAAO,WAAW,eAAe;AAC9E,UAAI,UAAW,WAAU;AAAA,IAC3B;AAAA,EACF,GAAG,KAAK,QAAQ,CAAC,QAAQ,OAAO,WAAW,UAAU,WAAW,GAAG,eAAe,CAAC;AACrF;;;AC1CO,IAAM,eAAN,MAAmF;AAAA,EA0BxF,YAAY,QAAW,MAA0C;AAbjE,SAAQ,UAAiD;AAUzD;AAAA,SAAiB,aAAa,oBAAI,IAAoB;AACtD,SAAiB,aAAa,oBAAI,IAAuC;AAGvE,SAAK,SAAS;AACd,SAAK,SAAS,KAAK;AAEnB,SAAK,gBAAgB,KAAK,iBAAiB;AAC3C,SAAK,iBAAiB,KAAK,kBAAkB;AAC7C,SAAK,cAAc,KAAK,eAAe;AACvC,SAAK,QAAQ,KAAK,SAAS,CAAC;AAE5B,UAAM,KAAK,KAAK;AAChB,SAAK,KAAK;AAAA,MACR,WAAW,GAAG,aAAa;AAAA,MAC3B,WAAW,GAAG,aAAa;AAAA,MAC3B,YAAY,GAAG,cAAc;AAAA,MAC7B,WAAW,GAAG,aAAa;AAAA,MAC3B,YAAY,GAAG;AAAA,MACf,iBAAiB,GAAG;AAAA,MACpB,YAAY,GAAG;AAAA,MACf,QAAQ,GAAG;AAAA,IACb;AAGA,SAAK,YAAY,MAAM;AACrB,WAAK,IAAI;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,QACP,IAAI,KAAK,OAAO,MAAM;AAAA,MACxB,CAAC;AACD,WAAK,eAAe;AAAA,IACtB;AAEA,SAAK,cAAc,CAAC,YAAY;AAC9B,WAAK,IAAI;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,QACP;AAAA,MACF,CAAC;AAAA,IACH;AAEA,SAAK,eAAe,CAAC,WAAW;AAC9B,WAAK,IAAI;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,QACP,QAAQ,OAAO,MAAM;AAAA,MACvB,CAAC;AACD,WAAK,cAAc;AAAA,IACrB;AAEA,SAAK,iBAAiB,CAAC,QAAQ;AAC7B,WAAK,IAAI;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,QACP,KAAK,OAAO,GAAG;AAAA,MACjB,CAAC;AAAA,IACH;AAGA,SAAK,SAAS,CAAC,QAAa;AAC1B,YAAM,aAAa,KAAK,IAAI;AAC5B,YAAM,gBAAoC,KAAK,YAAY;AAC3D,UAAI;AAEJ,UAAI,eAAe;AACjB,cAAM,OAAO,KAAK,MAAM,aAAa;AACrC,YAAI,CAAC,OAAO,MAAM,IAAI,EAAG,aAAY,KAAK,IAAI,GAAG,aAAa,IAAI;AAAA,MACpE;AAEA,UAAI,KAAK,GAAG,YAAY;AACtB,cAAM,KAAK,KAAK,GAAG,WAAW,UAAU,GAAG;AAC3C,YAAI,CAAC,GAAG,QAAS;AAAA,MACnB;AAEA,YAAM,UAAU,aAAa,KAAK,WAAW;AAE7C,WAAK,IAAI;AAAA,QACP,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,SAAS;AAAA,MACX,CAAC;AAED,WAAK,GAAG,SAAS,EAAE,WAAW,SAAS,SAAS,KAAK,QAAQ,KAAK,OAAO,CAAC;AAAA,IAC5E;AAGA,SAAK,OAAO,GAAG,WAAW,KAAK,SAAS;AACxC,SAAK,OAAO,GAAG,aAAa,KAAK,WAAW;AAC5C,SAAK,OAAO,GAAG,cAAc,KAAK,YAAY;AAC9C,SAAK,OAAO,GAAG,iBAAiB,KAAK,cAAc;AACnD,SAAK,OAAO,GAAG,KAAK,GAAG,WAAW,KAAK,MAAM;AAAA,EAC/C;AAAA,EAEQ,IAAI,GAAgC;AAC1C,UAAM,IAAI,KAAK;AACf,QAAI,CAAC,EAAE,OAAQ;AACf,QAAI,CAAC,EAAE,EAAE,IAAI,EAAG;AAChB,QAAI,EAAE,QAAQ,WAAW,KAAK,CAAC,EAAE,KAAK,SAAS,EAAE,KAAY,EAAG;AAChE,MAAE,OAAO,CAAC;AAAA,EACZ;AAAA;AAAA,EAGA,QAA6B;AAC3B,UAAM,QAAQ,MAAM,KAAK,KAAK,WAAW,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO,EAAE,MAAM,MAAM,EAAE;AAC5F,UAAM,WAAW,MAAM,KAAK,KAAK,WAAW,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,GAAG,OAAO;AAAA,MAC5E;AAAA,MACA,UAAU,IAAI;AAAA,IAChB,EAAE;AACF,WAAO;AAAA,MACL,YAAY,MAAM;AAAA,MAClB,eAAe,SAAS,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,UAAU,CAAC;AAAA,MAC1D;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,QAAQ,OAAqC;AACnD,WAAO,SAAS,OAAO,CAAC,IAAI,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAAA,EACnE;AAAA,EAEQ,iBAAiB;AACvB,SAAK,cAAc;AAEnB,UAAM,OAAO,MAAM;AACjB,YAAM,cAAc,KAAK,GAAG,gBAAgB,EAAE,QAAQ,KAAK,OAAO,CAAC,KAAK,CAAC;AACzE,YAAM,YAAY,EAAE,GAAG,aAAa,iBAAgB,oBAAI,KAAK,GAAE,YAAY,EAAE;AAE7E,YAAM,QAAQ,KAAK,GAAG,WAAW,UAAU,SAAS;AACpD,UAAI,CAAC,MAAM,SAAS;AAClB,YAAI,KAAK,gBAAgB;AACvB,kBAAQ,KAAK,0CAA0C,MAAM,MAAM,MAAM;AAC3E;AAAA,MACF;AAEA,YAAM,QAAQ,WAAW,MAAM;AAAA,MAE/B,GAAG,KAAK,GAAG,SAAS;AAEpB,WAAK,OAAO,QAAQ,KAAK,GAAG,SAAS,EAAE,KAAK,KAAK,GAAG,WAAW,EAAE,SAAS,MAAM,KAAK,GAAG,MAAM;AAC5F,qBAAa,KAAK;AAAA,MACpB,CAAC;AAED,WAAK,IAAI;AAAA,QACP,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS,MAAM;AAAA,MACjB,CAAC;AAAA,IACH;AAEA,SAAK,UAAU,YAAY,MAAM,KAAK,GAAG,UAAU;AACnD,SAAK;AAAA,EACP;AAAA,EAEQ,gBAAgB;AACtB,QAAI,KAAK,SAAS;AAChB,oBAAc,KAAK,OAAc;AACjC,WAAK,UAAU;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,KACE,OACA,SACA,UACA,OACA,WACM;AACN,UAAM,SAAS,KAAK,OAAO,KAAK,EAAE;AAClC,UAAM,SAAS,OAAO,UAAU,OAAO;AACvC,QAAI,CAAC,OAAO,QAAS,OAAM,IAAI,MAAM,wBAAwB,KAAK,MAAM,OAAO,MAAM,OAAO,EAAE;AAE9F,QAAI,OAAO;AACT,WAAK,OAAO,QAAQ,aAAa,KAAK,GAAG,SAAS,EAAE,KAAK,OAAO,KAAK,GAAG,OAAO,MAAM,CAAC,QAAiB;AACrG,YAAI;AACF,gBAAM,GAAG;AAAA,QACX,QAAQ;AAAA,QAER;AAAA,MACF,CAAC;AAAA,IACH,OAAO;AACL,WAAK,OAAO,KAAK,OAAO,KAAK,GAAG,OAAO,IAAI;AAAA,IAC7C;AAEA,SAAK,IAAI;AAAA,MACP,MAAM;AAAA,MACN;AAAA,MACA,UAAU,KAAK,MAAM,UAAU,WAAW;AAAA,IAC5C,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,OAAiC;AACzC,UAAM,OAAO,KAAK,QAAQ,KAAK;AAC/B,UAAM,SAAmB,CAAC;AAC1B,eAAW,KAAK,MAAM;AACpB,YAAM,QAAQ,KAAK,WAAW,IAAI,CAAC,KAAK,KAAK;AAC7C,WAAK,WAAW,IAAI,GAAG,IAAI;AAC3B,UAAI,SAAS,EAAG,QAAO,KAAK,CAAC;AAAA,IAC/B;AACA,QAAI,OAAO,SAAS,GAAG;AACrB,WAAK,OAAO,KAAK,KAAK,eAAe,EAAE,OAAO,OAAO,CAAC;AACtD,WAAK,IAAI,EAAE,MAAM,QAAQ,QAAQ,QAAQ,OAAO,OAAO,CAAC;AAAA,IAC1D;AAAA,EACF;AAAA,EAEA,WAAW,OAAiC;AAC1C,UAAM,OAAO,KAAK,QAAQ,KAAK;AAC/B,UAAM,UAAoB,CAAC;AAC3B,eAAW,KAAK,MAAM;AACpB,YAAM,OAAO,KAAK,WAAW,IAAI,CAAC,KAAK;AACvC,YAAM,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC;AACjC,UAAI,SAAS,KAAK,OAAO,EAAG,SAAQ,KAAK,CAAC;AAC1C,UAAI,SAAS,EAAG,MAAK,WAAW,OAAO,CAAC;AAAA,UACnC,MAAK,WAAW,IAAI,GAAG,IAAI;AAAA,IAClC;AACA,QAAI,QAAQ,SAAS,GAAG;AACtB,WAAK,OAAO,KAAK,KAAK,gBAAgB,EAAE,OAAO,QAAQ,CAAC;AACxD,WAAK,IAAI,EAAE,MAAM,QAAQ,QAAQ,SAAS,OAAO,QAAQ,CAAC;AAAA,IAC5D;AAAA,EACF;AAAA,EAEA,GACE,OACA,SACY;AACZ,UAAM,SAAS,KAAK,OAAO,KAAK,EAAE;AAElC,SAAK,IAAI,EAAE,MAAM,YAAY,QAAQ,YAAY,MAAM,CAAC;AAExD,UAAM,UAAU,CACd,eACA,aACG;AACH,YAAM,gBAAgB;AACtB,YAAM,UAAU,eAAe,QAAQ;AAEvC,YAAM,SAAS,OAAO,UAAU,OAAO;AACvC,UAAI,CAAC,OAAO,QAAS;AAErB,YAAM,aAAa,oBAAI,KAAK;AAC5B,YAAM,SAAS,eAAe,SAAS,IAAI,KAAK,cAAc,MAAM,IAAI;AAExE,YAAM,OAAO;AAAA,QACX,UAAU;AAAA,UACR,WAAY,eAAe,aAAa;AAAA,UACxC,QAAQ,eAAe,UAAU,WAAW,YAAY;AAAA,UACxD,QAAQ,eAAe,UAAU,CAAC;AAAA,UAClC,MAAM;AAAA,UACN,UAAU,eAAe;AAAA,QAC3B;AAAA,QACA,KAAK;AAAA,UACH;AAAA,UACA,WAAW,SAAS,KAAK,IAAI,GAAG,WAAW,QAAQ,IAAI,OAAO,QAAQ,CAAC,IAAI;AAAA,UAC3E,KAAM,KAAK,OAAe;AAAA,UAC1B,UAAU,KAAK,OAAO;AAAA,UACtB,QAAQ,KAAK;AAAA,UACb,OACE,OAAO,aAAa,aAChB,CAAC,MAAgB;AACf,gBAAI;AACF,uBAAS,CAAC;AAAA,YACZ,QAAQ;AAAA,YAER;AAAA,UACF,IACA;AAAA,QACR;AAAA,MACF;AAEA,WAAK,IAAI;AAAA,QACP,MAAM;AAAA,QACN;AAAA,QACA,UAAU,KAAK,MAAM,UACjB;AAAA,UACE,WAAW,KAAK,SAAS;AAAA,UACzB,QAAQ,KAAK,SAAS;AAAA,UACtB,QAAQ,KAAK,SAAS;AAAA,UACtB,UAAU,KAAK,SAAS;AAAA,QAC1B,IACA;AAAA,MACN,CAAC;AAED,cAAQ,OAAO,MAAa,IAAW;AAAA,IACzC;AAEA,UAAM,eAAe,CAAC,MAAe;AACnC,UAAI,KAAK,gBAAgB,eAAe;AAEtC,gBAAQ,KAAK,YAAY,OAAO,KAAK,CAAC,UAAU,CAAC;AAAA,MACnD;AAAA,IACF;AAEA,SAAK,OAAO,GAAG,OAAO,KAAK,GAAG,OAAO;AACrC,SAAK,OAAO,GAAG,GAAG,OAAO,KAAK,CAAC,UAAU,YAAY;AAErD,QAAI,MAAM,KAAK,WAAW,IAAI,OAAO,KAAK,CAAC;AAC3C,QAAI,CAAC,KAAK;AACR,YAAM,oBAAI,IAAI;AACd,WAAK,WAAW,IAAI,OAAO,KAAK,GAAG,GAAG;AAAA,IACxC;AACA,UAAM,QAA4B,EAAE,MAAM,SAAS,SAAS,aAAa;AACzE,QAAI,IAAI,KAAK;AAEb,WAAO,MAAM;AACX,WAAK,OAAO,IAAI,OAAO,KAAK,GAAG,OAAO;AACtC,WAAK,OAAO,IAAI,GAAG,OAAO,KAAK,CAAC,UAAU,YAAY;AACtD,YAAM,IAAI,KAAK,WAAW,IAAI,OAAO,KAAK,CAAC;AAC3C,UAAI,GAAG;AACL,UAAE,OAAO,KAAK;AACd,YAAI,EAAE,SAAS,EAAG,MAAK,WAAW,OAAO,OAAO,KAAK,CAAC;AAAA,MACxD;AACA,WAAK,IAAI,EAAE,MAAM,YAAY,QAAQ,cAAc,MAAM,CAAC;AAAA,IAC5D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAgB;AAEd,SAAK,cAAc;AAGnB,SAAK,OAAO,IAAI,WAAW,KAAK,SAAS;AACzC,SAAK,OAAO,IAAI,aAAa,KAAK,WAAW;AAC7C,SAAK,OAAO,IAAI,cAAc,KAAK,YAAY;AAC/C,SAAK,OAAO,IAAI,iBAAiB,KAAK,cAAc;AACpD,SAAK,OAAO,IAAI,KAAK,GAAG,WAAW,KAAK,MAAM;AAG9C,eAAW,CAAC,OAAO,GAAG,KAAK,KAAK,WAAW,QAAQ,GAAG;AACpD,iBAAW,SAAS,KAAK;AACvB,aAAK,OAAO,IAAI,OAAO,KAAK,GAAG,MAAM,OAAO;AAC5C,aAAK,OAAO,IAAI,GAAG,OAAO,KAAK,CAAC,UAAU,MAAM,YAAY;AAAA,MAC9D;AAAA,IACF;AACA,SAAK,WAAW,MAAM;AAGtB,UAAM,UAAU,MAAM,KAAK,KAAK,WAAW,QAAQ,CAAC,EACjD,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,QAAQ,CAAC,EAC/B,IAAI,CAAC,CAAC,IAAI,MAAM,IAAI;AACvB,QAAI,QAAQ,SAAS,GAAG;AACtB,WAAK,OAAO,KAAK,KAAK,gBAAgB,EAAE,OAAO,QAAQ,CAAC;AACxD,WAAK,IAAI,EAAE,MAAM,QAAQ,QAAQ,SAAS,OAAO,QAAQ,CAAC;AAAA,IAC5D;AACA,SAAK,WAAW,MAAM;AAAA,EACxB;AAAA;AAAA,EAGA,aAAmB;AACjB,SAAK,cAAc;AACnB,SAAK,OAAO,WAAW;AACvB,SAAK,IAAI,EAAE,MAAM,cAAc,OAAO,cAAc,QAAQ,oBAAoB,CAAC;AAAA,EACnF;AAAA,EAEA,UAAgB;AACd,SAAK,OAAO,QAAQ;AACpB,SAAK,IAAI,EAAE,MAAM,cAAc,OAAO,WAAW,IAAI,KAAK,OAAO,MAAM,GAAG,CAAC;AAAA,EAC7E;AACF;","names":["useEndpoint"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/routesV3.client.fetch.ts","../src/routesV3.client.index.ts","../src/sockets/socket.client.context.tsx","../src/sockets/socket.client.index.ts"],"sourcesContent":["/**\n * This package exports React Query hooks, so we mark it as client-only to keep Next.js happy.\n */\n'use client';\n\nexport * from './routesV3.client.types';\nexport * from './routesV3.client.fetch';\nexport * from './routesV3.client.index';\nexport * from './sockets/socket.client.index';","// routesV3.client.fetch.ts\n\nimport { Fetcher, FetchInput } from './routesV3.client.types';\n\n/**\n * Default fetch implementation used by the route client helper.\n * @param req Normalized request information (URL, method, body, headers).\n * @returns Parsed JSON (or text fallback) from the server response.\n */\nexport const defaultFetcher: Fetcher = async <T>(req: FetchInput): Promise<T> => {\n const headers: Record<string, string> = { ...(req.headers ?? {}) };\n const isFormData = typeof FormData !== 'undefined' && req.body instanceof FormData;\n if (!isFormData) {\n headers['Content-Type'] ||= 'application/json';\n headers['Accept'] ||= 'application/json';\n }\n\n const res = await fetch(req.url, {\n method: req.method,\n headers,\n body: isFormData ? (req.body as any) : req.body == null ? undefined : JSON.stringify(req.body),\n });\n\n const text = await res.text();\n if (!res.ok) {\n const snippet = text.slice(0, 400);\n throw new Error(`[${res.status}] ${res.statusText} — ${snippet}`);\n }\n\n try {\n return JSON.parse(text) as T;\n } catch {\n return text as unknown as T;\n }\n};\n","// routesV3.client.ts\nimport {\n keepPreviousData,\n useInfiniteQuery,\n useMutation,\n useQuery,\n type InfiniteData,\n type QueryKey,\n} from '@tanstack/react-query';\nimport type { ZodType } from 'zod';\nimport {\n HttpMethod,\n buildCacheKey,\n compilePath,\n} from '@emeryld/rrroutes-contract';\nimport type {\n AnyLeaf,\n InferBody,\n InferOutput,\n InferParams,\n InferQuery,\n} from '@emeryld/rrroutes-contract';\nimport { defaultFetcher } from './routesV3.client.fetch';\nimport type {\n ArgsFor,\n ArgsTuple,\n BuildMeta,\n BuiltForLeaf,\n BuiltInfinite,\n BuiltMutation,\n BuiltQuery,\n Cursor,\n DataShape,\n InfiniteBuildOptionsFor,\n MutationBuildOptionsFor,\n QueryBuildOptionsFor,\n RouteClient,\n RouteClientOptions,\n RouteClientDebugEvent,\n RouteClientDebugLogger,\n RouteClientDebugMode,\n RouteClientDebugOptions,\n RouteClientDebugToggleOptions,\n Updater,\n} from './routesV3.client.types';\n\n// -------------------------------------------------------------------------------------\n// Tiny helpers\n// -------------------------------------------------------------------------------------\n/**\n * Convert an HTTP method to uppercase (as expected by fetch).\n * @param m Lowercase HTTP method.\n * @returns Uppercase method string.\n */\nconst toUpper = (m: HttpMethod): Uppercase<HttpMethod> => m.toUpperCase() as Uppercase<HttpMethod>;\n\n/**\n * Parse the given value with the supplied schema (if present).\n * @param value Raw value to validate.\n * @param schema Optional Zod schema used for validation/coercion.\n * @returns The validated or original value.\n */\nfunction zParse<T>(value: unknown, schema?: ZodType): T {\n return schema ? (schema.parse(value) as T) : (value as T);\n}\n\n/**\n * Serialize a query object into a search string.\n * @param query Query params object (possibly undefined).\n * @returns Query string prefixed with `?`, or empty string.\n */\nfunction toSearchString(query: Record<string, unknown> | undefined) {\n if (!query) return '';\n const params = new URLSearchParams();\n for (const [k, v] of Object.entries(query)) {\n if (v == null) continue;\n if (Array.isArray(v)) {\n v.forEach((x) => {\n if (x == null) return;\n if (typeof x === 'object') {\n params.append(k, JSON.stringify(x));\n } else {\n params.append(k, String(x));\n }\n });\n continue;\n }\n if (typeof v === 'object') {\n params.set(k, JSON.stringify(v));\n continue;\n }\n params.set(k, String(v));\n }\n const s = params.toString();\n return s ? `?${s}` : '';\n}\n\n/**\n * Remove the given key from an object (used to drop cursors from cache keys).\n * @param obj Source object.\n * @param key Property name to omit.\n * @returns Copy of the object without the specified key.\n */\nfunction stripKey<Q extends Record<string, unknown> | undefined>(obj: Q, key: string): Q {\n if (!obj) return obj;\n const { [key]: _omit, ...rest } = obj as any;\n return rest as Q;\n}\n\n/**\n * Default cursor extractor used by infinite queries.\n * @param p Page result returned from the server.\n * @returns Next cursor string, if present.\n */\nconst defaultGetNextCursor = (p: unknown): Cursor =>\n p && typeof p === 'object' && 'nextCursor' in p ? (p as any).nextCursor : undefined;\n\n// Debug logging --------------------------------------------------------------\nconst noopDebugLogger: RouteClientDebugLogger = () => {};\n\nconst defaultDebugLogger: RouteClientDebugLogger = (event: RouteClientDebugEvent) => {\n if (typeof console === 'undefined') return;\n const fn = console.debug ?? console.log;\n fn?.call(console, '[rrroutes-client]', event);\n};\n\nconst debugEventTypes: RouteClientDebugEvent['type'][] = [\n 'fetch',\n 'invalidate',\n 'setData',\n 'build',\n 'useEndpoint',\n];\n\ntype DebugEmitter<Names extends string> = {\n emit: (event: RouteClientDebugEvent, name?: Names) => void;\n mode: RouteClientDebugMode;\n};\n\nconst noopEmit = () => {};\n\nfunction createDebugEmitter<Names extends string>(\n option?: RouteClientDebugOptions<Names>,\n environment?: string,\n): DebugEmitter<Names> {\n const disabled: DebugEmitter<Names> = { emit: noopEmit, mode: 'minimal' };\n\n if (environment && environment.toLowerCase() === 'production') {\n return disabled;\n }\n\n if (!option) {\n return disabled;\n }\n if (option === true || option === 'minimal') {\n return {\n emit: (event, name) => defaultDebugLogger(name ? { ...event, name } : event),\n mode: 'minimal',\n };\n }\n if (option === 'complete') {\n return {\n emit: (event, name) => defaultDebugLogger(name ? { ...event, name } : event),\n mode: 'complete',\n };\n }\n if (typeof option === 'function') {\n return {\n emit: (event, name) => option(name ? { ...event, name } : event),\n mode: 'minimal',\n };\n }\n if (typeof option === 'object') {\n const toggles = option as RouteClientDebugToggleOptions<Names>;\n const verbose = Boolean(toggles.verbose);\n const enabledTypes = debugEventTypes.filter((type) => toggles[type]);\n if (enabledTypes.length === 0) {\n return { emit: noopEmit, mode: verbose ? 'complete' : 'minimal' };\n }\n const whitelist = new Set<RouteClientDebugEvent['type']>(enabledTypes);\n const onlySet =\n toggles.only && toggles.only.length > 0 ? new Set<Names>(toggles.only) : undefined;\n const logger = toggles.logger ?? defaultDebugLogger;\n const emit: DebugEmitter<Names>['emit'] = (event, name) => {\n if (!whitelist.has(event.type)) return;\n if (onlySet) {\n if (!name || !onlySet.has(name)) return;\n }\n logger(name ? { ...event, name } : event);\n };\n return { emit, mode: verbose ? 'complete' : 'minimal' };\n }\n\n return disabled;\n}\n\n// Split the variadic tuple at runtime\n/**\n * Extract the optional argument object from a variadic tuple.\n * @param args Tuple passed to a built endpoint helper.\n * @returns The argument object if present.\n */\nfunction extractArgs<L extends AnyLeaf>(args: ArgsTuple<L>): ArgsFor<L> | undefined {\n return (args as unknown as any[])[0] as any;\n}\n\n/**\n * Normalize params and query values, then construct a request URL for the given leaf.\n * @param leaf Leaf describing the endpoint.\n * @param baseUrl Optional base URL prepended to the path.\n * @param params Route parameters supplied by the caller.\n * @param query Query parameters supplied by the caller.\n * @returns Object containing the composed URL plus normalized params/query payloads.\n */\nfunction buildUrl<L extends AnyLeaf>(\n leaf: L,\n baseUrl: string,\n params: InferParams<L> | undefined,\n query: InferQuery<L> | undefined,\n) {\n const normalizedParams = zParse<InferParams<L>>(params, leaf.cfg.paramsSchema);\n const normalizedQuery = zParse<InferQuery<L>>(query, leaf.cfg.querySchema);\n const path = compilePath<L['path']>(leaf.path, (normalizedParams ?? {}) as any);\n const url = `${baseUrl ?? ''}${path}${toSearchString(normalizedQuery as any)}`;\n return { url, normalizedQuery, normalizedParams };\n}\n\n// -------------------------------------------------------------------------------------\n// Client factory\n// -------------------------------------------------------------------------------------\n/**\n * Construct typed React Query helpers backed by a routes-v3 registry leaf.\n * @param opts Route client configuration (query client, fetcher overrides, etc).\n * @returns Object that can build endpoint hooks/mutations from leaves.\n */\nexport function createRouteClient<Names extends string = string>(\n opts: RouteClientOptions<Names>,\n): RouteClient<Names> {\n const queryClient = opts.queryClient;\n const fetcher = opts.fetcher ?? defaultFetcher;\n const baseUrl = opts.baseUrl;\n const cursorParam = opts.cursorParam ?? 'cursor';\n const getNextCursor = opts.getNextCursor ?? defaultGetNextCursor;\n const environment =\n opts.environment ?? undefined;\n const { emit: emitDebug, mode: debugMode } = createDebugEmitter<Names>(opts.debug, environment);\n const isVerboseDebug = debugMode === 'complete';\n const decorateDebugEvent = <T extends RouteClientDebugEvent>(\n event: T,\n details?: Partial<RouteClientDebugEvent>,\n ): RouteClientDebugEvent => {\n if (!isVerboseDebug || !details) return event;\n return { ...event, ...details } as RouteClientDebugEvent;\n };\n\n /**\n * Invalidate a set of queries sharing the given prefix.\n * @param prefix Key parts shared by matching endpoints.\n * @param exact When true, invalidate only exact key matches.\n */\n async function invalidate(prefix: string[], exact = false) {\n const queryKey = prefix as unknown as QueryKey;\n await queryClient.invalidateQueries({ queryKey, exact });\n emitDebug({ type: 'invalidate', key: queryKey, exact });\n }\n\n /**\n * Build the client surface for a single leaf (query/mutation/infinite query).\n * @param leaf Leaf describing the endpoint.\n * @param rqOpts Optional React Query configuration.\n * @returns Helper object exposing key/invalidate/setData/useEndpoint.\n */\n function buildInternal<L extends AnyLeaf>(\n leaf: L,\n rqOpts?: QueryBuildOptionsFor<L> | InfiniteBuildOptionsFor<L> | MutationBuildOptionsFor<L>,\n meta?: BuildMeta<Names>,\n ): BuiltForLeaf<L> {\n const isGet = leaf.method === 'get';\n const isFeed = !!leaf.cfg.feed;\n const method = toUpper(leaf.method);\n const leafLabel = `${leaf.method.toUpperCase()} ${String(leaf.path)}`;\n const debugName = meta?.name;\n const emit = (event: RouteClientDebugEvent) => emitDebug(event, debugName);\n emit({ type: 'build', leaf: leafLabel });\n\n // --- key/invalidate/setData shared helpers ---\n const key = (...tuple: ArgsTuple<L>): QueryKey => {\n const a = extractArgs<L>(tuple);\n const params = (a as any)?.params as InferParams<L> | undefined;\n const query = (a as any)?.query as InferQuery<L> | undefined;\n const qForKey = isGet && isFeed ? stripKey(query as any, cursorParam) : (query as any);\n return buildCacheKey({ leaf, params: params as any, query: qForKey }) as unknown as QueryKey;\n };\n\n /**\n * Invalidate the React Query cache for this exact leaf invocation.\n * @param tuple Optional params/query tuple.\n */\n const invalidateExact = async (...tuple: ArgsTuple<L>) => {\n const queryKey = key(...tuple);\n await queryClient.invalidateQueries({ queryKey, exact: true });\n emit({ type: 'invalidate', key: queryKey, exact: true });\n };\n\n /**\n * Update the cache entries for this leaf.\n * @param args Tuple whose first entry is the updater and optional params/query follow.\n */\n const setData = (...args: [Updater<DataShape<L>>, ...rest: ArgsTuple<L>]) => {\n const [updater, ...rest] = args;\n const k = key(...(rest as ArgsTuple<L>));\n if (isGet && isFeed) {\n queryClient.setQueryData<InfiniteData<InferOutput<L>> | undefined>(k, (prev) =>\n typeof updater === 'function' ? (updater as any)(prev) : (updater as any),\n );\n } else {\n queryClient.setQueryData<InferOutput<L> | undefined>(k, (prev) =>\n typeof updater === 'function' ? (updater as any)(prev) : (updater as any),\n );\n }\n emit({ type: 'setData', key: k });\n };\n\n // --- Infinite GET ---\n if (isGet && isFeed) {\n const useEndpoint: BuiltInfinite<L>['useEndpoint'] = (...tuple) => {\n emit({ type: 'useEndpoint', leaf: leafLabel, variant: 'infiniteGet' });\n const a = extractArgs<L>(tuple);\n const params = (a as any)?.params as InferParams<L> | undefined;\n const query = (a as any)?.query as InferQuery<L> | undefined;\n\n // Normalize once; we’ll inject the cursor per page below.\n const { normalizedQuery, normalizedParams } = buildUrl(leaf, baseUrl, params, query);\n return useInfiniteQuery<\n InferOutput<L>,\n unknown,\n InfiniteData<InferOutput<L>>,\n QueryKey,\n Cursor\n >({\n ...(rqOpts as InfiniteBuildOptionsFor<L>),\n queryKey: key(...tuple),\n initialPageParam: undefined,\n getNextPageParam: (lastPage) => getNextCursor(lastPage),\n placeholderData: keepPreviousData,\n queryFn: async ({ pageParam }) => {\n const pageQuery = {\n ...(normalizedQuery as any),\n ...(pageParam ? { [cursorParam]: pageParam } : {}),\n };\n const { url } = buildUrl(leaf, baseUrl, params, pageQuery);\n const startedAt = Date.now();\n const detail = isVerboseDebug ? { params: normalizedParams, query: pageQuery } : undefined;\n emit(\n decorateDebugEvent(\n { type: 'fetch', stage: 'start', method, url, leaf: leafLabel },\n detail,\n ),\n );\n try {\n const out = await fetcher<unknown>({ url, method });\n const parsed = zParse<InferOutput<L>>(out, leaf.cfg.outputSchema);\n\n // call onReceive after fetch and validation\n (rqOpts as InfiniteBuildOptionsFor<L> & { onReceive?: (data: InferOutput<L>) => void })\n ?.onReceive?.(parsed);\n\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'success',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n },\n isVerboseDebug ? { params: normalizedParams, query: pageQuery, output: parsed } : undefined,\n ),\n );\n return parsed;\n } catch (error) {\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'error',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n error,\n },\n detail,\n ),\n );\n throw error;\n }\n },\n // NOTE: TData is InfiniteData<T>, so we don't need a select here.\n }, queryClient);\n };\n\n return {\n key,\n invalidate: invalidateExact,\n setData: setData as any,\n useEndpoint,\n } as BuiltForLeaf<L>;\n }\n // --- Plain GET ---\n if (isGet) {\n const useEndpoint: BuiltQuery<L>['useEndpoint'] = (...tuple) => {\n emit({ type: 'useEndpoint', leaf: leafLabel, variant: 'get' });\n const a = extractArgs<L>(tuple);\n const params = (a as any)?.params as InferParams<L> | undefined;\n const query = (a as any)?.query as InferQuery<L> | undefined;\n\n const { url, normalizedQuery, normalizedParams } = buildUrl(leaf, baseUrl, params, query);\n return useQuery<InferOutput<L>, unknown, InferOutput<L>, QueryKey>({\n ...(rqOpts as QueryBuildOptionsFor<L>),\n queryKey: key(...tuple),\n placeholderData: keepPreviousData,\n queryFn: async () => {\n const startedAt = Date.now();\n const detail = isVerboseDebug\n ? { params: normalizedParams, query: normalizedQuery }\n : undefined;\n emit(\n decorateDebugEvent(\n { type: 'fetch', stage: 'start', method, url, leaf: leafLabel },\n detail,\n ),\n );\n try {\n const out = await fetcher<unknown>({ url, method });\n const parsed = zParse<InferOutput<L>>(out, leaf.cfg.outputSchema);\n\n // call onReceive after fetch and validation\n (rqOpts as QueryBuildOptionsFor<L> & { onReceive?: (data: InferOutput<L>) => void })\n ?.onReceive?.(parsed);\n\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'success',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n },\n isVerboseDebug\n ? { params: normalizedParams, query: normalizedQuery, output: parsed }\n : undefined,\n ),\n );\n return parsed;\n } catch (error) {\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'error',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n error,\n },\n detail,\n ),\n );\n throw error;\n }\n },\n }, queryClient);\n };\n\n return {\n key,\n invalidate: invalidateExact,\n setData: setData as any,\n useEndpoint,\n } as BuiltForLeaf<L>;\n }\n\n // --- Mutation (POST/PUT/PATCH/DELETE) ---\n const fetchEndpoint: BuiltMutation<L>['fetch'] = async (\n ...tupleWithBody: [...ArgsTuple<L>, InferBody<L>]\n ) => {\n if (tupleWithBody.length === 0) {\n throw new Error('Body is required when invoking a mutation fetch.');\n }\n const bodyIndex = tupleWithBody.length - 1;\n const tuple = tupleWithBody.slice(0, bodyIndex) as ArgsTuple<L>;\n const body = tupleWithBody[bodyIndex] as InferBody<L>;\n const args = extractArgs<L>(tuple);\n const params = (args as any)?.params as InferParams<L> | undefined;\n const query = (args as any)?.query as InferQuery<L> | undefined;\n\n const { url, normalizedQuery, normalizedParams } = buildUrl(leaf, baseUrl, params, query);\n const normalizedBody = zParse<InferBody<L>>(body, leaf.cfg.bodySchema);\n\n const isMultipart = Array.isArray(leaf.cfg.bodyFiles) && leaf.cfg.bodyFiles.length > 0;\n const payload = isMultipart ? toFormData(normalizedBody as any) : normalizedBody;\n\n const startedAt = Date.now();\n const detail = isVerboseDebug\n ? { params: normalizedParams, query: normalizedQuery }\n : undefined;\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'start',\n method,\n url,\n leaf: leafLabel,\n body: payload,\n },\n detail,\n ),\n );\n try {\n const out = await fetcher<unknown>({ url, method, body: payload });\n const parsed = zParse<InferOutput<L>>(out, leaf.cfg.outputSchema);\n\n // call onReceive after fetch and validation\n (rqOpts as MutationBuildOptionsFor<L> & { onReceive?: (data: InferOutput<L>) => void })\n ?.onReceive?.(parsed);\n\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'success',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n },\n isVerboseDebug\n ? { params: normalizedParams, query: normalizedQuery, output: parsed }\n : undefined,\n ),\n );\n return parsed;\n } catch (error) {\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'error',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n body: payload,\n error,\n },\n detail,\n ),\n );\n throw error;\n }\n };\n\n const useEndpoint: BuiltMutation<L>['useEndpoint'] = (...tuple) => {\n emit({ type: 'useEndpoint', leaf: leafLabel, variant: 'mutation' });\n return useMutation<InferOutput<L>, unknown, InferBody<L>, unknown>({\n ...(rqOpts as MutationBuildOptionsFor<L>),\n mutationKey: key(...tuple),\n mutationFn: (body: InferBody<L>) =>\n fetchEndpoint(...([...tuple, body] as [...ArgsTuple<L>, InferBody<L>])),\n }, queryClient);\n };\n\n return {\n key,\n invalidate: invalidateExact,\n setData: setData as any,\n useEndpoint,\n fetch: fetchEndpoint,\n } as BuiltForLeaf<L>;\n }\n\n return {\n queryClient,\n invalidate,\n build: buildInternal as RouteClient<Names>['build'],\n };\n}\n\n// -------------------------------------------------------------------------------------\n// Multipart helper\n// -------------------------------------------------------------------------------------\nfunction toFormData(body: Record<string, any>): FormData {\n const fd = new FormData();\n for (const [k, v] of Object.entries(body ?? {})) {\n if (v == null) continue;\n if (Array.isArray(v)) v.forEach((item, i) => fd.append(`${k}[${i}]`, item as any));\n else fd.append(k, v as any);\n }\n return fd;\n}\n","// socket.client.context.tsx\n\nimport * as React from 'react';\nimport { Socket } from 'socket.io-client';\nimport {\n SocketClient,\n SocketClientOptions,\n EventMap,\n ClientCtx,\n Payload,\n ServerEnvelope,\n} from './socket.client.index';\nimport { ZodType } from 'zod';\n\n/** === Provider-side debug === */\nexport type SocketProviderDebugEvent =\n | { type: 'resolve'; phase: 'start' | 'ok' | 'error' | 'missing' | 'cancelled'; err?: string }\n | { type: 'client'; phase: 'ready' | 'destroy' | 'missing' }\n | { type: 'render'; phase: 'waiting_for_socket' | 'provide' };\n\nexport type SocketProviderDebugOptions = {\n verbose?: boolean;\n logger?: (e: SocketProviderDebugEvent) => void;\n} & {\n [P in SocketProviderDebugEvent['type']]?: boolean;\n};\n\n/** === Types for runtime socket injection === */\ntype BaseOptions<Ping extends ZodType, Pong extends ZodType, T extends EventMap> = Omit<\n SocketClientOptions<Ping, Pong, T>,\n 'socket'\n>;\n\ntype ProviderRuntimeSocket =\n | { socket: Socket | null } // CHANGED: may be null\n | { getSocket: () => Socket | Promise<Socket> }; // lazy/async socket\n\ntype SocketProviderProps<Ping extends ZodType, Pong extends ZodType, T extends EventMap> =\n React.PropsWithChildren<{\n events: T;\n baseOptions: BaseOptions<Ping, Pong, T>;\n /** show while waiting for async socket; should not use the socket context */\n fallback?: React.ReactNode;\n providerDebug?: SocketProviderDebugOptions;\n } & ProviderRuntimeSocket>;\n\nconst SocketCtx = React.createContext<SocketClient<ZodType, ZodType, any> | null>(null);\n\nfunction dbg(dbgOpts: SocketProviderDebugOptions | undefined, e: SocketProviderDebugEvent) {\n if (!dbgOpts?.logger) return;\n if (!dbgOpts[e.type]) return;\n dbgOpts.logger(e);\n}\n\nexport function buildSocketProvider<Ping extends ZodType, Pong extends ZodType, T extends EventMap>(args: {\n events: T;\n options: BaseOptions<Ping, Pong, T>;\n}) {\n const { events, options: baseOptions } = args;\n\n return {\n SocketProvider: (\n props: React.PropsWithChildren<\n ProviderRuntimeSocket & { fallback?: React.ReactNode; providerDebug?: SocketProviderDebugOptions }\n >\n ) => (\n <SocketProvider<Ping, Pong, T>\n events={events}\n baseOptions={baseOptions}\n {...props}\n />\n ),\n useSocketClient: () => useSocketClient<Ping, Pong, T>(),\n useSocketConnection: <K extends keyof T & string>(\n p: Parameters<typeof useSocketConnection<T, K>>[0]\n ) => useSocketConnection<T, K>(p),\n };\n}\n\nfunction SocketProvider<Ping extends ZodType, Pong extends ZodType, T extends EventMap>(\n props: SocketProviderProps<Ping, Pong, T>\n) {\n const { events, baseOptions, children, fallback, providerDebug } = props;\n\n // Async sockets are resolved into this state.\n const [resolvedSocket, setResolvedSocket] = React.useState<Socket | null>(null); // CHANGED\n\n // Single source of truth for \"the socket we should use right now\".\n const socket: Socket | null =\n 'socket' in props ? props.socket ?? null : resolvedSocket; // CHANGED\n\n React.useEffect(() => {\n if (!('getSocket' in props)) return;\n\n let cancelled = false;\n dbg(providerDebug, { type: 'resolve', phase: 'start' });\n\n if (!resolvedSocket) {\n Promise.resolve(props.getSocket())\n .then((s) => {\n if (cancelled) {\n dbg(providerDebug, { type: 'resolve', phase: 'cancelled' });\n return; // CHANGED: don't set state after cancel\n }\n if (!s) {\n dbg(providerDebug, { type: 'resolve', phase: 'missing' });\n return;\n }\n setResolvedSocket(s);\n dbg(providerDebug, { type: 'resolve', phase: 'ok' });\n })\n .catch((err) => {\n if (cancelled) return;\n dbg(providerDebug, { type: 'resolve', phase: 'error', err: String(err) });\n });\n }\n\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [resolvedSocket]); // run once per lazy resolution\n\n const client = React.useMemo(() => {\n if (!socket) {\n dbg(providerDebug, { type: 'client', phase: 'missing' }); // CHANGED\n return null;\n }\n const c = new SocketClient(events, { ...baseOptions, socket });\n dbg(providerDebug, { type: 'client', phase: 'ready' });\n return c;\n }, [events, baseOptions, socket, providerDebug]);\n\n React.useEffect(() => {\n return () => {\n if (client) {\n client.destroy();\n dbg(providerDebug, { type: 'client', phase: 'destroy' });\n }\n };\n }, [client, providerDebug]);\n\n if (!client) {\n dbg(providerDebug, { type: 'render', phase: 'waiting_for_socket' });\n return <>{fallback ?? children}</>;\n }\n\n dbg(providerDebug, { type: 'render', phase: 'provide' });\n return <SocketCtx.Provider value={client}>{children}</SocketCtx.Provider>;\n}\n\n// useSocketClient / useSocketConnection unchanged\nfunction useSocketClient<Ping extends ZodType, Pong extends ZodType, T extends EventMap>(): SocketClient<\n Ping,\n Pong,\n T\n> {\n const ctx = React.useContext(SocketCtx);\n if (!ctx) throw new Error('SocketClient not found. Wrap with <SocketProvider>.');\n return ctx as unknown as SocketClient<Ping, Pong, T>;\n}\n\ntype Rooms = string[] | string | undefined;\n\nexport type UseSocketConnectionArgs<T extends EventMap, K extends keyof T & string> = {\n event: K;\n rooms?: Rooms;\n onMessage: (\n payload: Payload<T, K>,\n meta: { envelope: ServerEnvelope<T, K>; ctx: ClientCtx }\n ) => void;\n onCleanup?: () => void;\n autoJoin?: boolean;\n autoLeave?: boolean;\n deps?: React.DependencyList;\n};\n\nfunction useSocketConnection<T extends EventMap, K extends keyof T & string>(\n args: UseSocketConnectionArgs<T, K>\n) {\n const { event, rooms, onMessage, onCleanup, autoJoin = true, autoLeave = true } = args;\n const client = useSocketClient<ZodType, ZodType, T>();\n\n const normalizedRooms = React.useMemo(\n () => (rooms == null ? [] : Array.isArray(rooms) ? rooms : [rooms]),\n [rooms]\n );\n\n React.useEffect(() => {\n if (autoJoin && normalizedRooms.length > 0) client.joinRooms(normalizedRooms);\n const unsubscribe = client.on(event, onMessage);\n\n return () => {\n unsubscribe();\n if (autoLeave && normalizedRooms.length > 0) client.leaveRooms(normalizedRooms);\n if (onCleanup) onCleanup();\n };\n }, args.deps ?? [client, event, onMessage, autoJoin, autoLeave, ...normalizedRooms]);\n}\n","// socket.client.index.ts\nimport { Socket } from 'socket.io-client';\nimport { z, ZodType } from 'zod';\nimport type { SocketEvent } from '@emeryld/rrroutes-contract';\n\ntype MaybeSocket = Socket | null;\n\nexport type EventMap = Record<string, SocketEvent>;\nexport type Payload<T extends EventMap, K extends keyof T> = z.infer<T[K]['message']>;\n\nexport type ServerEnvelope<T extends EventMap, K extends keyof T & string> = {\n eventName: K;\n sentAt: string | Date;\n sentTo: string[];\n data?: Payload<T, K>;\n metadata?: Record<string, unknown>;\n};\n\nexport type ClientCtx = {\n receivedAt: Date;\n latencyMs?: number;\n nsp?: string;\n socketId?: string;\n rooms?: string[];\n socket?: MaybeSocket; // CHANGED\n reply?: (data?: unknown) => void;\n};\n\nexport type ClientStatsSnapshot = {\n roomsCount: number;\n totalHandlers: number;\n rooms: { room: string; count: number }[];\n handlers: { event: string; handlers: number }[];\n};\n\n// helper, since original code used NoInfer\ntype NoInfer<T> = [T][T extends any ? 0 : never];\n\nexport type SocketClientDebugEvent<K extends string = string> =\n | {\n type: 'connection';\n phase: 'connect' | 'reconnect' | 'disconnect' | 'connect_error';\n id?: string;\n attempt?: number;\n reason?: string;\n err?: string;\n }\n | {\n type: 'register';\n action: 'register' | 'unregister';\n event: K;\n }\n | {\n type: 'heartbeat';\n action: 'ping_emit' | 'pong_recv';\n latencyMs?: number;\n payload?: unknown;\n }\n | {\n type: 'room';\n action: 'join' | 'leave';\n rooms: string[];\n }\n | {\n type: 'emit';\n event: K;\n metadata?: Record<string, unknown>;\n }\n | {\n type: 'receive';\n event: K;\n envelope?: {\n eventName: K;\n sentAt: string | Date;\n sentTo: string[];\n metadata?: Record<string, unknown>;\n };\n };\n\nexport type SocketClientDebugOptions<K extends string = string> = {\n verbose?: boolean;\n only?: K[];\n logger?: (e: SocketClientDebugEvent<K>) => void;\n} & {\n [P in SocketClientDebugEvent['type']]?: boolean;\n};\n\n/** === Heartbeat config (enforced) === */\nexport type HeartbeatClientOptions<Ping extends ZodType, Pong extends ZodType> = {\n /** Event names. Defaults are 'sys:ping' and 'sys:pong'. */\n pingEvent?: string;\n pongEvent?: string;\n /** Interval between pings. Default 15_000. */\n intervalMs?: number;\n /** Give up waiting for pong after this many ms. Default 7_500. */\n timeoutMs?: number;\n\n /** Schema of the ping payload you will emit. */\n pingSchema: Ping;\n /** Produce the ping payload on each tick. */\n makePingPayload: (ctx: { socket: MaybeSocket }) => NoInfer<z.infer<Ping>>; // CHANGED\n\n /** Optional validation of the pong payload you receive. */\n pongSchema?: Pong;\n /** Optional hook called on each pong. */\n onPong?: (args: {\n latencyMs: number;\n payload?: NoInfer<z.infer<Pong>>;\n socket: MaybeSocket; // CHANGED\n }) => void;\n};\n\nexport type SocketClientOptions<\n Ping extends ZodType,\n Pong extends ZodType,\n T extends EventMap = EventMap\n> = {\n /** Inject an existing socket.io-client Socket. Can be null while bootstrapping. */\n socket: MaybeSocket; // CHANGED\n roomJoinEvent?: string;\n roomLeaveEvent?: string;\n environment?: 'development' | 'production';\n debug?: SocketClientDebugOptions<keyof T & string>;\n /** required heartbeat config */\n heartbeat: HeartbeatClientOptions<Ping, Pong>;\n};\n\ntype HandlerEntry<T extends EventMap, K extends keyof T & string> = {\n orig: (payload: Payload<T, K>, meta: { envelope: ServerEnvelope<T, K>; ctx: ClientCtx }) => void;\n wrapped: (envelopeOrRaw: ServerEnvelope<T, K> | Payload<T, K>) => void;\n errorWrapped: (e: unknown) => void;\n};\n\nexport class SocketClient<Ping extends ZodType, Pong extends ZodType, T extends EventMap> {\n readonly socket: MaybeSocket; // CHANGED\n private readonly events: T;\n private readonly roomJoinEvent: string;\n private readonly roomLeaveEvent: string;\n private readonly environment: 'development' | 'production';\n private readonly debug: SocketClientDebugOptions<keyof T & string>;\n\n // heartbeat\n private readonly hb: Required<Omit<HeartbeatClientOptions<Ping, Pong>, 'pongSchema' | 'onPong'>> & {\n pongSchema?: z.ZodTypeAny;\n onPong?: HeartbeatClientOptions<Ping, Pong>['onPong'];\n };\n private hbTimer: ReturnType<typeof setInterval> | null = null;\n\n /** keep references so we can .off() later */\n private readonly onConnect: () => void;\n private readonly onReconnect: (attempt: number) => void;\n private readonly onDisconnect: (reason: unknown) => void;\n private readonly onConnectError: (err: unknown) => void;\n private readonly onPong: (raw: any) => void;\n\n // stats\n private readonly roomCounts = new Map<string, number>();\n private readonly handlerMap = new Map<string, Set<HandlerEntry<T, any>>>();\n\n constructor(events: T, opts: SocketClientOptions<Ping, Pong, T>) {\n this.events = events;\n this.socket = opts.socket ?? null; // CHANGED\n\n this.roomJoinEvent = opts.roomJoinEvent ?? 'room:join';\n this.roomLeaveEvent = opts.roomLeaveEvent ?? 'room:leave';\n this.environment = opts.environment ?? 'development';\n this.debug = opts.debug ?? {};\n // heartbeat fixed config\n const hb = opts.heartbeat;\n this.hb = {\n pingEvent: hb.pingEvent ?? 'sys:ping',\n pongEvent: hb.pongEvent ?? 'sys:pong',\n intervalMs: hb.intervalMs ?? 15_000,\n timeoutMs: hb.timeoutMs ?? 7_500,\n pingSchema: hb.pingSchema,\n makePingPayload: hb.makePingPayload,\n pongSchema: hb.pongSchema,\n onPong: hb.onPong,\n };\n\n /* socket lifecycle → connection bucket */\n this.onConnect = () => {\n this.dbg({\n type: 'connection',\n phase: 'connect',\n id: this.socket?.id ?? '', // CHANGED\n });\n this.startHeartbeat();\n };\n\n this.onReconnect = (attempt) => {\n this.dbg({\n type: 'connection',\n phase: 'reconnect',\n attempt,\n });\n };\n\n this.onDisconnect = (reason) => {\n this.dbg({\n type: 'connection',\n phase: 'disconnect',\n reason: String(reason),\n });\n this.stopHeartbeat();\n };\n\n this.onConnectError = (err) => {\n this.dbg({\n type: 'connection',\n phase: 'connect_error',\n err: String(err),\n });\n };\n\n // wire pong listener → pingpong bucket\n this.onPong = (raw: any) => {\n const receivedAt = Date.now();\n const clientSentIso: string | undefined = raw?.clientEcho?.__clientSentAt;\n let latencyMs: number | undefined;\n\n if (clientSentIso) {\n const sent = Date.parse(clientSentIso);\n if (!Number.isNaN(sent)) latencyMs = Math.max(0, receivedAt - sent);\n }\n\n if (this.hb.pongSchema) {\n const ok = this.hb.pongSchema.safeParse(raw);\n if (!ok.success) return; // drop invalid\n }\n\n const latency = latencyMs ?? raw?.sinceMs ?? 0;\n\n this.dbg({\n type: 'heartbeat',\n action: 'pong_recv',\n latencyMs: latency,\n payload: raw,\n });\n\n this.hb.onPong?.({ latencyMs: latency, payload: raw, socket: this.socket }); // CHANGED\n };\n\n // register top-level listeners with stored refs (only if we have a socket)\n if (this.socket) {\n this.socket.on('connect', this.onConnect);\n this.socket.on('reconnect', this.onReconnect);\n this.socket.on('disconnect', this.onDisconnect);\n this.socket.on('connect_error', this.onConnectError);\n this.socket.on(this.hb.pongEvent, this.onPong);\n }\n }\n\n private dbg(e: SocketClientDebugEvent<any>) {\n const d = this.debug;\n if (!d.logger) return;\n if (!d[e.type]) return;\n if (d.only && 'event' in e && !d.only.includes(e.event as any)) return;\n d.logger(e);\n }\n\n /** internal stats snapshot */\n stats(): ClientStatsSnapshot {\n const rooms = Array.from(this.roomCounts.entries()).map(([room, count]) => ({ room, count }));\n const handlers = Array.from(this.handlerMap.entries()).map(([event, set]) => ({\n event,\n handlers: set.size,\n }));\n return {\n roomsCount: rooms.length,\n totalHandlers: handlers.reduce((a, b) => a + b.handlers, 0),\n rooms,\n handlers,\n };\n }\n\n private toArray(rooms?: string[] | string): string[] {\n return rooms == null ? [] : Array.isArray(rooms) ? rooms : [rooms];\n }\n\n private startHeartbeat() {\n this.stopHeartbeat();\n if (!this.socket) return; // CHANGED\n\n const tick = () => {\n if (!this.socket) return; // CHANGED: extra safety\n\n const basePayload = this.hb.makePingPayload({ socket: this.socket }) ?? {};\n const candidate = { ...basePayload, __clientSentAt: new Date().toISOString() };\n\n const check = this.hb.pingSchema.safeParse(candidate);\n if (!check.success) {\n if (this.environment === 'development')\n // eslint-disable-next-line no-console\n console.warn('[socket] ping schema validation failed', check.error.issues);\n return;\n }\n\n const timer = setTimeout(() => {\n /* timeout, no-op here */\n }, this.hb.timeoutMs);\n\n this.socket\n .timeout(this.hb.timeoutMs)\n .emit(this.hb.pingEvent, { payload: check.data }, () => {\n clearTimeout(timer);\n });\n\n this.dbg({\n type: 'heartbeat',\n action: 'ping_emit',\n payload: check.data,\n });\n };\n\n this.hbTimer = setInterval(tick, this.hb.intervalMs);\n tick();\n }\n\n private stopHeartbeat() {\n if (this.hbTimer) {\n clearInterval(this.hbTimer as any);\n this.hbTimer = null;\n }\n }\n\n emit<K extends keyof T & string>(\n event: K,\n payload: Payload<T, K>,\n metadata?: Record<string, unknown>,\n onAck?: (ack: unknown) => void,\n timeoutMs?: number,\n ): void {\n const schema = this.events[event].message;\n const parsed = schema.safeParse(payload);\n if (!parsed.success) throw new Error(`Invalid payload for \"${event}\": ${parsed.error.message}`);\n\n if (!this.socket) {\n if (this.environment === 'development') {\n // eslint-disable-next-line no-console\n console.warn(`[socket] emit(\"${String(event)}\") skipped because socket is null`); // CHANGED\n }\n return;\n }\n\n if (onAck) {\n this.socket\n .timeout(timeoutMs ?? this.hb.timeoutMs)\n .emit(String(event), parsed.data, (ack: unknown) => {\n try {\n onAck(ack);\n } catch {\n /* noop */\n }\n });\n } else {\n this.socket.emit(String(event), parsed.data);\n }\n\n this.dbg({\n type: 'emit',\n event,\n metadata: this.debug.verbose ? metadata : undefined,\n });\n }\n\n joinRooms(rooms?: string[] | string): void {\n const list = this.toArray(rooms);\n const toJoin: string[] = [];\n for (const r of list) {\n const next = (this.roomCounts.get(r) ?? 0) + 1;\n this.roomCounts.set(r, next);\n if (next === 1) toJoin.push(r);\n }\n if (toJoin.length > 0 && this.socket) { // CHANGED\n this.socket.emit(this.roomJoinEvent, { rooms: toJoin });\n this.dbg({ type: 'room', action: 'join', rooms: toJoin });\n }\n }\n\n leaveRooms(rooms?: string[] | string): void {\n const list = this.toArray(rooms);\n const toLeave: string[] = [];\n for (const r of list) {\n const curr = this.roomCounts.get(r) ?? 0;\n const next = Math.max(0, curr - 1);\n if (next === 0 && curr > 0) toLeave.push(r);\n if (next === 0) this.roomCounts.delete(r);\n else this.roomCounts.set(r, next);\n }\n if (toLeave.length > 0 && this.socket) { // CHANGED\n this.socket.emit(this.roomLeaveEvent, { rooms: toLeave });\n this.dbg({ type: 'room', action: 'leave', rooms: toLeave });\n }\n }\n\n on<K extends keyof T & string>(\n event: K,\n handler: (payload: Payload<T, K>, meta: { envelope: ServerEnvelope<T, K>; ctx: ClientCtx }) => void,\n ): () => void {\n const schema = this.events[event].message;\n\n this.dbg({ type: 'register', action: 'register', event });\n\n if (!this.socket) {\n if (this.environment === 'development') {\n // eslint-disable-next-line no-console\n console.warn(`[socket] on(\"${String(event)}\") skipped because socket is null`); // CHANGED\n }\n return () => {};\n }\n\n const socket = this.socket; // CHANGED: capture non-null\n\n const wrapped = (\n envelopeOrRaw: ServerEnvelope<T, K> | Payload<T, K>,\n maybeAck?: (data?: unknown) => void,\n ) => {\n const maybeEnvelope = envelopeOrRaw as any;\n const rawData = maybeEnvelope?.data ?? maybeEnvelope;\n\n const parsed = schema.safeParse(rawData);\n if (!parsed.success) return;\n\n const receivedAt = new Date();\n const sentAt = maybeEnvelope?.sentAt ? new Date(maybeEnvelope.sentAt) : undefined;\n\n const meta = {\n envelope: {\n eventName: (maybeEnvelope?.eventName ?? event) as K,\n sentAt: maybeEnvelope?.sentAt ?? receivedAt.toISOString(),\n sentTo: maybeEnvelope?.sentTo ?? [],\n data: undefined,\n metadata: maybeEnvelope?.metadata,\n },\n ctx: {\n receivedAt,\n latencyMs: sentAt ? Math.max(0, receivedAt.getTime() - sentAt.getTime()) : undefined,\n nsp: (socket as any).nsp,\n socketId: socket.id,\n socket,\n reply:\n typeof maybeAck === 'function'\n ? (d?: unknown) => {\n try {\n maybeAck(d);\n } catch {\n /* noop */\n }\n }\n : undefined,\n },\n } as const;\n\n this.dbg({\n type: 'receive',\n event,\n envelope: this.debug.verbose\n ? {\n eventName: meta.envelope.eventName,\n sentAt: meta.envelope.sentAt,\n sentTo: meta.envelope.sentTo,\n metadata: meta.envelope.metadata,\n }\n : undefined,\n });\n\n handler(parsed.data as any, meta as any);\n };\n\n const errorWrapped = (e: unknown) => {\n if (this.environment === 'development') {\n // eslint-disable-next-line no-console\n console.warn(`[socket] ${String(event)}:error`, e);\n }\n };\n\n socket.on(String(event), wrapped);\n socket.on(`${String(event)}:error`, errorWrapped);\n\n let set = this.handlerMap.get(String(event));\n if (!set) {\n set = new Set();\n this.handlerMap.set(String(event), set);\n }\n const entry: HandlerEntry<T, K> = { orig: handler, wrapped, errorWrapped };\n set.add(entry);\n\n return () => {\n socket.off(String(event), wrapped);\n socket.off(`${String(event)}:error`, errorWrapped);\n const s = this.handlerMap.get(String(event));\n if (s) {\n s.delete(entry);\n if (s.size === 0) this.handlerMap.delete(String(event));\n }\n this.dbg({ type: 'register', action: 'unregister', event });\n };\n }\n\n /**\n * Remove all listeners, stop timers, and leave rooms.\n * Call when disposing the client instance.\n */\n destroy(): void {\n // stop heartbeat timer\n this.stopHeartbeat();\n\n const socket = this.socket; // CHANGED\n\n // remove top-level socket listeners\n if (socket) {\n socket.off('connect', this.onConnect);\n socket.off('reconnect', this.onReconnect);\n socket.off('disconnect', this.onDisconnect);\n socket.off('connect_error', this.onConnectError);\n socket.off(this.hb.pongEvent, this.onPong);\n\n // unsubscribe all per-event handlers\n for (const [event, set] of this.handlerMap.entries()) {\n for (const entry of set) {\n socket.off(String(event), entry.wrapped);\n socket.off(`${String(event)}:error`, entry.errorWrapped);\n }\n }\n }\n this.handlerMap.clear();\n\n // leave any rooms we joined via ref-count\n const toLeave = Array.from(this.roomCounts.entries())\n .filter(([, count]) => count > 0)\n .map(([room]) => room);\n if (toLeave.length > 0 && socket) { // CHANGED\n socket.emit(this.roomLeaveEvent, { rooms: toLeave });\n this.dbg({ type: 'room', action: 'leave', rooms: toLeave });\n }\n this.roomCounts.clear();\n }\n\n /** Pass-throughs. Managing connection is the caller’s responsibility. */\n disconnect(): void {\n if (!this.socket) return; // CHANGED\n this.stopHeartbeat();\n this.socket.disconnect();\n this.dbg({ type: 'connection', phase: 'disconnect', reason: 'client_disconnect' });\n }\n\n connect(): void {\n if (!this.socket) return; // CHANGED\n this.socket.connect();\n this.dbg({ type: 'connection', phase: 'connect', id: this.socket.id ?? '' });\n }\n}\n\nexport * from './socket.client.context';\n"],"mappings":"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","names":["useEndpoint"]}
package/dist/index.mjs CHANGED
@@ -458,16 +458,23 @@ function buildSocketProvider(args) {
458
458
  }
459
459
  function SocketProvider(props) {
460
460
  const { events, baseOptions, children, fallback, providerDebug } = props;
461
- const [socket, setSocket] = React.useState(
462
- "socket" in props ? props.socket : null
463
- );
461
+ const [resolvedSocket, setResolvedSocket] = React.useState(null);
462
+ const socket = "socket" in props ? props.socket ?? null : resolvedSocket;
464
463
  React.useEffect(() => {
464
+ if (!("getSocket" in props)) return;
465
465
  let cancelled = false;
466
- if (!socket && "getSocket" in props) {
467
- dbg(providerDebug, { type: "resolve", phase: "start" });
466
+ dbg(providerDebug, { type: "resolve", phase: "start" });
467
+ if (!resolvedSocket) {
468
468
  Promise.resolve(props.getSocket()).then((s) => {
469
- if (cancelled) return;
470
- setSocket(s);
469
+ if (cancelled) {
470
+ dbg(providerDebug, { type: "resolve", phase: "cancelled" });
471
+ return;
472
+ }
473
+ if (!s) {
474
+ dbg(providerDebug, { type: "resolve", phase: "missing" });
475
+ return;
476
+ }
477
+ setResolvedSocket(s);
471
478
  dbg(providerDebug, { type: "resolve", phase: "ok" });
472
479
  }).catch((err) => {
473
480
  if (cancelled) return;
@@ -477,9 +484,12 @@ function SocketProvider(props) {
477
484
  return () => {
478
485
  cancelled = true;
479
486
  };
480
- }, [socket]);
487
+ }, [resolvedSocket]);
481
488
  const client = React.useMemo(() => {
482
- if (!socket) return null;
489
+ if (!socket) {
490
+ dbg(providerDebug, { type: "client", phase: "missing" });
491
+ return null;
492
+ }
483
493
  const c = new SocketClient(events, { ...baseOptions, socket });
484
494
  dbg(providerDebug, { type: "client", phase: "ready" });
485
495
  return c;
@@ -530,7 +540,7 @@ var SocketClient = class {
530
540
  this.roomCounts = /* @__PURE__ */ new Map();
531
541
  this.handlerMap = /* @__PURE__ */ new Map();
532
542
  this.events = events;
533
- this.socket = opts.socket;
543
+ this.socket = opts.socket ?? null;
534
544
  this.roomJoinEvent = opts.roomJoinEvent ?? "room:join";
535
545
  this.roomLeaveEvent = opts.roomLeaveEvent ?? "room:leave";
536
546
  this.environment = opts.environment ?? "development";
@@ -550,7 +560,8 @@ var SocketClient = class {
550
560
  this.dbg({
551
561
  type: "connection",
552
562
  phase: "connect",
553
- id: this.socket.id ?? ""
563
+ id: this.socket?.id ?? ""
564
+ // CHANGED
554
565
  });
555
566
  this.startHeartbeat();
556
567
  };
@@ -597,11 +608,13 @@ var SocketClient = class {
597
608
  });
598
609
  this.hb.onPong?.({ latencyMs: latency, payload: raw, socket: this.socket });
599
610
  };
600
- this.socket.on("connect", this.onConnect);
601
- this.socket.on("reconnect", this.onReconnect);
602
- this.socket.on("disconnect", this.onDisconnect);
603
- this.socket.on("connect_error", this.onConnectError);
604
- this.socket.on(this.hb.pongEvent, this.onPong);
611
+ if (this.socket) {
612
+ this.socket.on("connect", this.onConnect);
613
+ this.socket.on("reconnect", this.onReconnect);
614
+ this.socket.on("disconnect", this.onDisconnect);
615
+ this.socket.on("connect_error", this.onConnectError);
616
+ this.socket.on(this.hb.pongEvent, this.onPong);
617
+ }
605
618
  }
606
619
  dbg(e) {
607
620
  const d = this.debug;
@@ -629,7 +642,9 @@ var SocketClient = class {
629
642
  }
630
643
  startHeartbeat() {
631
644
  this.stopHeartbeat();
645
+ if (!this.socket) return;
632
646
  const tick = () => {
647
+ if (!this.socket) return;
633
648
  const basePayload = this.hb.makePingPayload({ socket: this.socket }) ?? {};
634
649
  const candidate = { ...basePayload, __clientSentAt: (/* @__PURE__ */ new Date()).toISOString() };
635
650
  const check = this.hb.pingSchema.safeParse(candidate);
@@ -662,6 +677,12 @@ var SocketClient = class {
662
677
  const schema = this.events[event].message;
663
678
  const parsed = schema.safeParse(payload);
664
679
  if (!parsed.success) throw new Error(`Invalid payload for "${event}": ${parsed.error.message}`);
680
+ if (!this.socket) {
681
+ if (this.environment === "development") {
682
+ console.warn(`[socket] emit("${String(event)}") skipped because socket is null`);
683
+ }
684
+ return;
685
+ }
665
686
  if (onAck) {
666
687
  this.socket.timeout(timeoutMs ?? this.hb.timeoutMs).emit(String(event), parsed.data, (ack) => {
667
688
  try {
@@ -686,7 +707,7 @@ var SocketClient = class {
686
707
  this.roomCounts.set(r, next);
687
708
  if (next === 1) toJoin.push(r);
688
709
  }
689
- if (toJoin.length > 0) {
710
+ if (toJoin.length > 0 && this.socket) {
690
711
  this.socket.emit(this.roomJoinEvent, { rooms: toJoin });
691
712
  this.dbg({ type: "room", action: "join", rooms: toJoin });
692
713
  }
@@ -701,7 +722,7 @@ var SocketClient = class {
701
722
  if (next === 0) this.roomCounts.delete(r);
702
723
  else this.roomCounts.set(r, next);
703
724
  }
704
- if (toLeave.length > 0) {
725
+ if (toLeave.length > 0 && this.socket) {
705
726
  this.socket.emit(this.roomLeaveEvent, { rooms: toLeave });
706
727
  this.dbg({ type: "room", action: "leave", rooms: toLeave });
707
728
  }
@@ -709,6 +730,14 @@ var SocketClient = class {
709
730
  on(event, handler) {
710
731
  const schema = this.events[event].message;
711
732
  this.dbg({ type: "register", action: "register", event });
733
+ if (!this.socket) {
734
+ if (this.environment === "development") {
735
+ console.warn(`[socket] on("${String(event)}") skipped because socket is null`);
736
+ }
737
+ return () => {
738
+ };
739
+ }
740
+ const socket = this.socket;
712
741
  const wrapped = (envelopeOrRaw, maybeAck) => {
713
742
  const maybeEnvelope = envelopeOrRaw;
714
743
  const rawData = maybeEnvelope?.data ?? maybeEnvelope;
@@ -727,9 +756,9 @@ var SocketClient = class {
727
756
  ctx: {
728
757
  receivedAt,
729
758
  latencyMs: sentAt ? Math.max(0, receivedAt.getTime() - sentAt.getTime()) : void 0,
730
- nsp: this.socket.nsp,
731
- socketId: this.socket.id,
732
- socket: this.socket,
759
+ nsp: socket.nsp,
760
+ socketId: socket.id,
761
+ socket,
733
762
  reply: typeof maybeAck === "function" ? (d) => {
734
763
  try {
735
764
  maybeAck(d);
@@ -755,8 +784,8 @@ var SocketClient = class {
755
784
  console.warn(`[socket] ${String(event)}:error`, e);
756
785
  }
757
786
  };
758
- this.socket.on(String(event), wrapped);
759
- this.socket.on(`${String(event)}:error`, errorWrapped);
787
+ socket.on(String(event), wrapped);
788
+ socket.on(`${String(event)}:error`, errorWrapped);
760
789
  let set = this.handlerMap.get(String(event));
761
790
  if (!set) {
762
791
  set = /* @__PURE__ */ new Set();
@@ -765,8 +794,8 @@ var SocketClient = class {
765
794
  const entry = { orig: handler, wrapped, errorWrapped };
766
795
  set.add(entry);
767
796
  return () => {
768
- this.socket.off(String(event), wrapped);
769
- this.socket.off(`${String(event)}:error`, errorWrapped);
797
+ socket.off(String(event), wrapped);
798
+ socket.off(`${String(event)}:error`, errorWrapped);
770
799
  const s = this.handlerMap.get(String(event));
771
800
  if (s) {
772
801
  s.delete(entry);
@@ -781,32 +810,37 @@ var SocketClient = class {
781
810
  */
782
811
  destroy() {
783
812
  this.stopHeartbeat();
784
- this.socket.off("connect", this.onConnect);
785
- this.socket.off("reconnect", this.onReconnect);
786
- this.socket.off("disconnect", this.onDisconnect);
787
- this.socket.off("connect_error", this.onConnectError);
788
- this.socket.off(this.hb.pongEvent, this.onPong);
789
- for (const [event, set] of this.handlerMap.entries()) {
790
- for (const entry of set) {
791
- this.socket.off(String(event), entry.wrapped);
792
- this.socket.off(`${String(event)}:error`, entry.errorWrapped);
813
+ const socket = this.socket;
814
+ if (socket) {
815
+ socket.off("connect", this.onConnect);
816
+ socket.off("reconnect", this.onReconnect);
817
+ socket.off("disconnect", this.onDisconnect);
818
+ socket.off("connect_error", this.onConnectError);
819
+ socket.off(this.hb.pongEvent, this.onPong);
820
+ for (const [event, set] of this.handlerMap.entries()) {
821
+ for (const entry of set) {
822
+ socket.off(String(event), entry.wrapped);
823
+ socket.off(`${String(event)}:error`, entry.errorWrapped);
824
+ }
793
825
  }
794
826
  }
795
827
  this.handlerMap.clear();
796
828
  const toLeave = Array.from(this.roomCounts.entries()).filter(([, count]) => count > 0).map(([room]) => room);
797
- if (toLeave.length > 0) {
798
- this.socket.emit(this.roomLeaveEvent, { rooms: toLeave });
829
+ if (toLeave.length > 0 && socket) {
830
+ socket.emit(this.roomLeaveEvent, { rooms: toLeave });
799
831
  this.dbg({ type: "room", action: "leave", rooms: toLeave });
800
832
  }
801
833
  this.roomCounts.clear();
802
834
  }
803
835
  /** Pass-throughs. Managing connection is the caller’s responsibility. */
804
836
  disconnect() {
837
+ if (!this.socket) return;
805
838
  this.stopHeartbeat();
806
839
  this.socket.disconnect();
807
840
  this.dbg({ type: "connection", phase: "disconnect", reason: "client_disconnect" });
808
841
  }
809
842
  connect() {
843
+ if (!this.socket) return;
810
844
  this.socket.connect();
811
845
  this.dbg({ type: "connection", phase: "connect", id: this.socket.id ?? "" });
812
846
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/routesV3.client.fetch.ts","../src/routesV3.client.index.ts","../src/sockets/socket.client.context.tsx","../src/sockets/socket.client.index.ts"],"sourcesContent":["// routesV3.client.fetch.ts\n\nimport { Fetcher, FetchInput } from './routesV3.client.types';\n\n/**\n * Default fetch implementation used by the route client helper.\n * @param req Normalized request information (URL, method, body, headers).\n * @returns Parsed JSON (or text fallback) from the server response.\n */\nexport const defaultFetcher: Fetcher = async <T>(req: FetchInput): Promise<T> => {\n const headers: Record<string, string> = { ...(req.headers ?? {}) };\n const isFormData = typeof FormData !== 'undefined' && req.body instanceof FormData;\n if (!isFormData) {\n headers['Content-Type'] ||= 'application/json';\n headers['Accept'] ||= 'application/json';\n }\n\n const res = await fetch(req.url, {\n method: req.method,\n headers,\n body: isFormData ? (req.body as any) : req.body == null ? undefined : JSON.stringify(req.body),\n });\n\n const text = await res.text();\n if (!res.ok) {\n const snippet = text.slice(0, 400);\n throw new Error(`[${res.status}] ${res.statusText} — ${snippet}`);\n }\n\n try {\n return JSON.parse(text) as T;\n } catch {\n return text as unknown as T;\n }\n};\n","// routesV3.client.ts\nimport {\n keepPreviousData,\n useInfiniteQuery,\n useMutation,\n useQuery,\n type InfiniteData,\n type QueryKey,\n} from '@tanstack/react-query';\nimport type { ZodType } from 'zod';\nimport {\n HttpMethod,\n buildCacheKey,\n compilePath,\n} from '@emeryld/rrroutes-contract';\nimport type {\n AnyLeaf,\n InferBody,\n InferOutput,\n InferParams,\n InferQuery,\n} from '@emeryld/rrroutes-contract';\nimport { defaultFetcher } from './routesV3.client.fetch';\nimport type {\n ArgsFor,\n ArgsTuple,\n BuildMeta,\n BuiltForLeaf,\n BuiltInfinite,\n BuiltMutation,\n BuiltQuery,\n Cursor,\n DataShape,\n InfiniteBuildOptionsFor,\n MutationBuildOptionsFor,\n QueryBuildOptionsFor,\n RouteClient,\n RouteClientOptions,\n RouteClientDebugEvent,\n RouteClientDebugLogger,\n RouteClientDebugMode,\n RouteClientDebugOptions,\n RouteClientDebugToggleOptions,\n Updater,\n} from './routesV3.client.types';\n\n// -------------------------------------------------------------------------------------\n// Tiny helpers\n// -------------------------------------------------------------------------------------\n/**\n * Convert an HTTP method to uppercase (as expected by fetch).\n * @param m Lowercase HTTP method.\n * @returns Uppercase method string.\n */\nconst toUpper = (m: HttpMethod): Uppercase<HttpMethod> => m.toUpperCase() as Uppercase<HttpMethod>;\n\n/**\n * Parse the given value with the supplied schema (if present).\n * @param value Raw value to validate.\n * @param schema Optional Zod schema used for validation/coercion.\n * @returns The validated or original value.\n */\nfunction zParse<T>(value: unknown, schema?: ZodType): T {\n return schema ? (schema.parse(value) as T) : (value as T);\n}\n\n/**\n * Serialize a query object into a search string.\n * @param query Query params object (possibly undefined).\n * @returns Query string prefixed with `?`, or empty string.\n */\nfunction toSearchString(query: Record<string, unknown> | undefined) {\n if (!query) return '';\n const params = new URLSearchParams();\n for (const [k, v] of Object.entries(query)) {\n if (v == null) continue;\n if (Array.isArray(v)) {\n v.forEach((x) => {\n if (x == null) return;\n if (typeof x === 'object') {\n params.append(k, JSON.stringify(x));\n } else {\n params.append(k, String(x));\n }\n });\n continue;\n }\n if (typeof v === 'object') {\n params.set(k, JSON.stringify(v));\n continue;\n }\n params.set(k, String(v));\n }\n const s = params.toString();\n return s ? `?${s}` : '';\n}\n\n/**\n * Remove the given key from an object (used to drop cursors from cache keys).\n * @param obj Source object.\n * @param key Property name to omit.\n * @returns Copy of the object without the specified key.\n */\nfunction stripKey<Q extends Record<string, unknown> | undefined>(obj: Q, key: string): Q {\n if (!obj) return obj;\n const { [key]: _omit, ...rest } = obj as any;\n return rest as Q;\n}\n\n/**\n * Default cursor extractor used by infinite queries.\n * @param p Page result returned from the server.\n * @returns Next cursor string, if present.\n */\nconst defaultGetNextCursor = (p: unknown): Cursor =>\n p && typeof p === 'object' && 'nextCursor' in p ? (p as any).nextCursor : undefined;\n\n// Debug logging --------------------------------------------------------------\nconst noopDebugLogger: RouteClientDebugLogger = () => {};\n\nconst defaultDebugLogger: RouteClientDebugLogger = (event: RouteClientDebugEvent) => {\n if (typeof console === 'undefined') return;\n const fn = console.debug ?? console.log;\n fn?.call(console, '[rrroutes-client]', event);\n};\n\nconst debugEventTypes: RouteClientDebugEvent['type'][] = [\n 'fetch',\n 'invalidate',\n 'setData',\n 'build',\n 'useEndpoint',\n];\n\ntype DebugEmitter<Names extends string> = {\n emit: (event: RouteClientDebugEvent, name?: Names) => void;\n mode: RouteClientDebugMode;\n};\n\nconst noopEmit = () => {};\n\nfunction createDebugEmitter<Names extends string>(\n option?: RouteClientDebugOptions<Names>,\n environment?: string,\n): DebugEmitter<Names> {\n const disabled: DebugEmitter<Names> = { emit: noopEmit, mode: 'minimal' };\n\n if (environment && environment.toLowerCase() === 'production') {\n return disabled;\n }\n\n if (!option) {\n return disabled;\n }\n if (option === true || option === 'minimal') {\n return {\n emit: (event, name) => defaultDebugLogger(name ? { ...event, name } : event),\n mode: 'minimal',\n };\n }\n if (option === 'complete') {\n return {\n emit: (event, name) => defaultDebugLogger(name ? { ...event, name } : event),\n mode: 'complete',\n };\n }\n if (typeof option === 'function') {\n return {\n emit: (event, name) => option(name ? { ...event, name } : event),\n mode: 'minimal',\n };\n }\n if (typeof option === 'object') {\n const toggles = option as RouteClientDebugToggleOptions<Names>;\n const verbose = Boolean(toggles.verbose);\n const enabledTypes = debugEventTypes.filter((type) => toggles[type]);\n if (enabledTypes.length === 0) {\n return { emit: noopEmit, mode: verbose ? 'complete' : 'minimal' };\n }\n const whitelist = new Set<RouteClientDebugEvent['type']>(enabledTypes);\n const onlySet =\n toggles.only && toggles.only.length > 0 ? new Set<Names>(toggles.only) : undefined;\n const logger = toggles.logger ?? defaultDebugLogger;\n const emit: DebugEmitter<Names>['emit'] = (event, name) => {\n if (!whitelist.has(event.type)) return;\n if (onlySet) {\n if (!name || !onlySet.has(name)) return;\n }\n logger(name ? { ...event, name } : event);\n };\n return { emit, mode: verbose ? 'complete' : 'minimal' };\n }\n\n return disabled;\n}\n\n// Split the variadic tuple at runtime\n/**\n * Extract the optional argument object from a variadic tuple.\n * @param args Tuple passed to a built endpoint helper.\n * @returns The argument object if present.\n */\nfunction extractArgs<L extends AnyLeaf>(args: ArgsTuple<L>): ArgsFor<L> | undefined {\n return (args as unknown as any[])[0] as any;\n}\n\n/**\n * Normalize params and query values, then construct a request URL for the given leaf.\n * @param leaf Leaf describing the endpoint.\n * @param baseUrl Optional base URL prepended to the path.\n * @param params Route parameters supplied by the caller.\n * @param query Query parameters supplied by the caller.\n * @returns Object containing the composed URL plus normalized params/query payloads.\n */\nfunction buildUrl<L extends AnyLeaf>(\n leaf: L,\n baseUrl: string,\n params: InferParams<L> | undefined,\n query: InferQuery<L> | undefined,\n) {\n const normalizedParams = zParse<InferParams<L>>(params, leaf.cfg.paramsSchema);\n const normalizedQuery = zParse<InferQuery<L>>(query, leaf.cfg.querySchema);\n const path = compilePath<L['path']>(leaf.path, (normalizedParams ?? {}) as any);\n const url = `${baseUrl ?? ''}${path}${toSearchString(normalizedQuery as any)}`;\n return { url, normalizedQuery, normalizedParams };\n}\n\n// -------------------------------------------------------------------------------------\n// Client factory\n// -------------------------------------------------------------------------------------\n/**\n * Construct typed React Query helpers backed by a routes-v3 registry leaf.\n * @param opts Route client configuration (query client, fetcher overrides, etc).\n * @returns Object that can build endpoint hooks/mutations from leaves.\n */\nexport function createRouteClient<Names extends string = string>(\n opts: RouteClientOptions<Names>,\n): RouteClient<Names> {\n const queryClient = opts.queryClient;\n const fetcher = opts.fetcher ?? defaultFetcher;\n const baseUrl = opts.baseUrl;\n const cursorParam = opts.cursorParam ?? 'cursor';\n const getNextCursor = opts.getNextCursor ?? defaultGetNextCursor;\n const environment =\n opts.environment ?? undefined;\n const { emit: emitDebug, mode: debugMode } = createDebugEmitter<Names>(opts.debug, environment);\n const isVerboseDebug = debugMode === 'complete';\n const decorateDebugEvent = <T extends RouteClientDebugEvent>(\n event: T,\n details?: Partial<RouteClientDebugEvent>,\n ): RouteClientDebugEvent => {\n if (!isVerboseDebug || !details) return event;\n return { ...event, ...details } as RouteClientDebugEvent;\n };\n\n /**\n * Invalidate a set of queries sharing the given prefix.\n * @param prefix Key parts shared by matching endpoints.\n * @param exact When true, invalidate only exact key matches.\n */\n async function invalidate(prefix: string[], exact = false) {\n const queryKey = prefix as unknown as QueryKey;\n await queryClient.invalidateQueries({ queryKey, exact });\n emitDebug({ type: 'invalidate', key: queryKey, exact });\n }\n\n /**\n * Build the client surface for a single leaf (query/mutation/infinite query).\n * @param leaf Leaf describing the endpoint.\n * @param rqOpts Optional React Query configuration.\n * @returns Helper object exposing key/invalidate/setData/useEndpoint.\n */\n function buildInternal<L extends AnyLeaf>(\n leaf: L,\n rqOpts?: QueryBuildOptionsFor<L> | InfiniteBuildOptionsFor<L> | MutationBuildOptionsFor<L>,\n meta?: BuildMeta<Names>,\n ): BuiltForLeaf<L> {\n const isGet = leaf.method === 'get';\n const isFeed = !!leaf.cfg.feed;\n const method = toUpper(leaf.method);\n const leafLabel = `${leaf.method.toUpperCase()} ${String(leaf.path)}`;\n const debugName = meta?.name;\n const emit = (event: RouteClientDebugEvent) => emitDebug(event, debugName);\n emit({ type: 'build', leaf: leafLabel });\n\n // --- key/invalidate/setData shared helpers ---\n const key = (...tuple: ArgsTuple<L>): QueryKey => {\n const a = extractArgs<L>(tuple);\n const params = (a as any)?.params as InferParams<L> | undefined;\n const query = (a as any)?.query as InferQuery<L> | undefined;\n const qForKey = isGet && isFeed ? stripKey(query as any, cursorParam) : (query as any);\n return buildCacheKey({ leaf, params: params as any, query: qForKey }) as unknown as QueryKey;\n };\n\n /**\n * Invalidate the React Query cache for this exact leaf invocation.\n * @param tuple Optional params/query tuple.\n */\n const invalidateExact = async (...tuple: ArgsTuple<L>) => {\n const queryKey = key(...tuple);\n await queryClient.invalidateQueries({ queryKey, exact: true });\n emit({ type: 'invalidate', key: queryKey, exact: true });\n };\n\n /**\n * Update the cache entries for this leaf.\n * @param args Tuple whose first entry is the updater and optional params/query follow.\n */\n const setData = (...args: [Updater<DataShape<L>>, ...rest: ArgsTuple<L>]) => {\n const [updater, ...rest] = args;\n const k = key(...(rest as ArgsTuple<L>));\n if (isGet && isFeed) {\n queryClient.setQueryData<InfiniteData<InferOutput<L>> | undefined>(k, (prev) =>\n typeof updater === 'function' ? (updater as any)(prev) : (updater as any),\n );\n } else {\n queryClient.setQueryData<InferOutput<L> | undefined>(k, (prev) =>\n typeof updater === 'function' ? (updater as any)(prev) : (updater as any),\n );\n }\n emit({ type: 'setData', key: k });\n };\n\n // --- Infinite GET ---\n if (isGet && isFeed) {\n const useEndpoint: BuiltInfinite<L>['useEndpoint'] = (...tuple) => {\n emit({ type: 'useEndpoint', leaf: leafLabel, variant: 'infiniteGet' });\n const a = extractArgs<L>(tuple);\n const params = (a as any)?.params as InferParams<L> | undefined;\n const query = (a as any)?.query as InferQuery<L> | undefined;\n\n // Normalize once; we’ll inject the cursor per page below.\n const { normalizedQuery, normalizedParams } = buildUrl(leaf, baseUrl, params, query);\n return useInfiniteQuery<\n InferOutput<L>,\n unknown,\n InfiniteData<InferOutput<L>>,\n QueryKey,\n Cursor\n >({\n ...(rqOpts as InfiniteBuildOptionsFor<L>),\n queryKey: key(...tuple),\n initialPageParam: undefined,\n getNextPageParam: (lastPage) => getNextCursor(lastPage),\n placeholderData: keepPreviousData,\n queryFn: async ({ pageParam }) => {\n const pageQuery = {\n ...(normalizedQuery as any),\n ...(pageParam ? { [cursorParam]: pageParam } : {}),\n };\n const { url } = buildUrl(leaf, baseUrl, params, pageQuery);\n const startedAt = Date.now();\n const detail = isVerboseDebug ? { params: normalizedParams, query: pageQuery } : undefined;\n emit(\n decorateDebugEvent(\n { type: 'fetch', stage: 'start', method, url, leaf: leafLabel },\n detail,\n ),\n );\n try {\n const out = await fetcher<unknown>({ url, method });\n const parsed = zParse<InferOutput<L>>(out, leaf.cfg.outputSchema);\n\n // call onReceive after fetch and validation\n (rqOpts as InfiniteBuildOptionsFor<L> & { onReceive?: (data: InferOutput<L>) => void })\n ?.onReceive?.(parsed);\n\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'success',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n },\n isVerboseDebug ? { params: normalizedParams, query: pageQuery, output: parsed } : undefined,\n ),\n );\n return parsed;\n } catch (error) {\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'error',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n error,\n },\n detail,\n ),\n );\n throw error;\n }\n },\n // NOTE: TData is InfiniteData<T>, so we don't need a select here.\n }, queryClient);\n };\n\n return {\n key,\n invalidate: invalidateExact,\n setData: setData as any,\n useEndpoint,\n } as BuiltForLeaf<L>;\n }\n // --- Plain GET ---\n if (isGet) {\n const useEndpoint: BuiltQuery<L>['useEndpoint'] = (...tuple) => {\n emit({ type: 'useEndpoint', leaf: leafLabel, variant: 'get' });\n const a = extractArgs<L>(tuple);\n const params = (a as any)?.params as InferParams<L> | undefined;\n const query = (a as any)?.query as InferQuery<L> | undefined;\n\n const { url, normalizedQuery, normalizedParams } = buildUrl(leaf, baseUrl, params, query);\n return useQuery<InferOutput<L>, unknown, InferOutput<L>, QueryKey>({\n ...(rqOpts as QueryBuildOptionsFor<L>),\n queryKey: key(...tuple),\n placeholderData: keepPreviousData,\n queryFn: async () => {\n const startedAt = Date.now();\n const detail = isVerboseDebug\n ? { params: normalizedParams, query: normalizedQuery }\n : undefined;\n emit(\n decorateDebugEvent(\n { type: 'fetch', stage: 'start', method, url, leaf: leafLabel },\n detail,\n ),\n );\n try {\n const out = await fetcher<unknown>({ url, method });\n const parsed = zParse<InferOutput<L>>(out, leaf.cfg.outputSchema);\n\n // call onReceive after fetch and validation\n (rqOpts as QueryBuildOptionsFor<L> & { onReceive?: (data: InferOutput<L>) => void })\n ?.onReceive?.(parsed);\n\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'success',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n },\n isVerboseDebug\n ? { params: normalizedParams, query: normalizedQuery, output: parsed }\n : undefined,\n ),\n );\n return parsed;\n } catch (error) {\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'error',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n error,\n },\n detail,\n ),\n );\n throw error;\n }\n },\n }, queryClient);\n };\n\n return {\n key,\n invalidate: invalidateExact,\n setData: setData as any,\n useEndpoint,\n } as BuiltForLeaf<L>;\n }\n\n // --- Mutation (POST/PUT/PATCH/DELETE) ---\n const fetchEndpoint: BuiltMutation<L>['fetch'] = async (\n ...tupleWithBody: [...ArgsTuple<L>, InferBody<L>]\n ) => {\n if (tupleWithBody.length === 0) {\n throw new Error('Body is required when invoking a mutation fetch.');\n }\n const bodyIndex = tupleWithBody.length - 1;\n const tuple = tupleWithBody.slice(0, bodyIndex) as ArgsTuple<L>;\n const body = tupleWithBody[bodyIndex] as InferBody<L>;\n const args = extractArgs<L>(tuple);\n const params = (args as any)?.params as InferParams<L> | undefined;\n const query = (args as any)?.query as InferQuery<L> | undefined;\n\n const { url, normalizedQuery, normalizedParams } = buildUrl(leaf, baseUrl, params, query);\n const normalizedBody = zParse<InferBody<L>>(body, leaf.cfg.bodySchema);\n\n const isMultipart = Array.isArray(leaf.cfg.bodyFiles) && leaf.cfg.bodyFiles.length > 0;\n const payload = isMultipart ? toFormData(normalizedBody as any) : normalizedBody;\n\n const startedAt = Date.now();\n const detail = isVerboseDebug\n ? { params: normalizedParams, query: normalizedQuery }\n : undefined;\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'start',\n method,\n url,\n leaf: leafLabel,\n body: payload,\n },\n detail,\n ),\n );\n try {\n const out = await fetcher<unknown>({ url, method, body: payload });\n const parsed = zParse<InferOutput<L>>(out, leaf.cfg.outputSchema);\n\n // call onReceive after fetch and validation\n (rqOpts as MutationBuildOptionsFor<L> & { onReceive?: (data: InferOutput<L>) => void })\n ?.onReceive?.(parsed);\n\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'success',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n },\n isVerboseDebug\n ? { params: normalizedParams, query: normalizedQuery, output: parsed }\n : undefined,\n ),\n );\n return parsed;\n } catch (error) {\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'error',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n body: payload,\n error,\n },\n detail,\n ),\n );\n throw error;\n }\n };\n\n const useEndpoint: BuiltMutation<L>['useEndpoint'] = (...tuple) => {\n emit({ type: 'useEndpoint', leaf: leafLabel, variant: 'mutation' });\n return useMutation<InferOutput<L>, unknown, InferBody<L>, unknown>({\n ...(rqOpts as MutationBuildOptionsFor<L>),\n mutationKey: key(...tuple),\n mutationFn: (body: InferBody<L>) =>\n fetchEndpoint(...([...tuple, body] as [...ArgsTuple<L>, InferBody<L>])),\n }, queryClient);\n };\n\n return {\n key,\n invalidate: invalidateExact,\n setData: setData as any,\n useEndpoint,\n fetch: fetchEndpoint,\n } as BuiltForLeaf<L>;\n }\n\n return {\n queryClient,\n invalidate,\n build: buildInternal as RouteClient<Names>['build'],\n };\n}\n\n// -------------------------------------------------------------------------------------\n// Multipart helper\n// -------------------------------------------------------------------------------------\nfunction toFormData(body: Record<string, any>): FormData {\n const fd = new FormData();\n for (const [k, v] of Object.entries(body ?? {})) {\n if (v == null) continue;\n if (Array.isArray(v)) v.forEach((item, i) => fd.append(`${k}[${i}]`, item as any));\n else fd.append(k, v as any);\n }\n return fd;\n}\n","// packages/rrroutes-client/src/socket.client.context.tsx\n\nimport * as React from 'react';\nimport { Socket } from 'socket.io-client';\nimport {\n SocketClient,\n SocketClientOptions,\n EventMap,\n ClientCtx,\n Payload,\n ServerEnvelope,\n} from './socket.client.index';\nimport { ZodType } from 'zod';\n\n/** === Provider-side debug === */\nexport type SocketProviderDebugEvent =\n | { type: 'resolve'; phase: 'start' | 'ok' | 'error'; err?: string }\n | { type: 'client'; phase: 'ready' | 'destroy' }\n | { type: 'render'; phase: 'waiting_for_socket' | 'provide' };\n\nexport type SocketProviderDebugOptions = {\n verbose?: boolean;\n logger?: (e: SocketProviderDebugEvent) => void;\n} & {\n [P in SocketProviderDebugEvent['type']]?: boolean;\n};\n\n/** === Types for runtime socket injection === */\ntype BaseOptions<Ping extends ZodType, Pong extends ZodType, T extends EventMap> = Omit<\n SocketClientOptions<Ping, Pong, T>,\n 'socket'\n>;\n\ntype ProviderRuntimeSocket =\n | { socket: Socket } // sync socket\n | { getSocket: () => Socket | Promise<Socket> }; // lazy/async socket\n\ntype SocketProviderProps<Ping extends ZodType, Pong extends ZodType, T extends EventMap> =\n React.PropsWithChildren<{\n events: T;\n baseOptions: BaseOptions<Ping, Pong, T>;\n /** show while waiting for async socket; should not use the socket context */\n fallback?: React.ReactNode;\n providerDebug?: SocketProviderDebugOptions;\n } & ProviderRuntimeSocket>;\n\nconst SocketCtx = React.createContext<SocketClient<ZodType, ZodType, any> | null>(null);\n\nfunction dbg(dbgOpts: SocketProviderDebugOptions | undefined, e: SocketProviderDebugEvent) {\n if (!dbgOpts?.logger) return;\n if (!dbgOpts[e.type]) return;\n dbgOpts.logger(e);\n}\n\nexport function buildSocketProvider<Ping extends ZodType, Pong extends ZodType, T extends EventMap>(args: {\n events: T;\n options: BaseOptions<Ping, Pong, T>;\n}) {\n const { events, options: baseOptions } = args;\n\n return {\n SocketProvider: (\n props: React.PropsWithChildren<\n ProviderRuntimeSocket & { fallback?: React.ReactNode; providerDebug?: SocketProviderDebugOptions }\n >\n ) => (\n <SocketProvider<Ping, Pong, T>\n events={events}\n baseOptions={baseOptions}\n {...props}\n />\n ),\n useSocketClient: () => useSocketClient<Ping, Pong, T>(),\n useSocketConnection: <K extends keyof T & string>(\n p: Parameters<typeof useSocketConnection<T, K>>[0]\n ) => useSocketConnection<T, K>(p),\n };\n}\n\nfunction SocketProvider<Ping extends ZodType, Pong extends ZodType, T extends EventMap>(\n props: SocketProviderProps<Ping, Pong, T>\n) {\n const { events, baseOptions, children, fallback, providerDebug } = props;\n\n const [socket, setSocket] = React.useState<Socket | null>(\n 'socket' in props ? props.socket : null\n );\n\n React.useEffect(() => {\n let cancelled = false;\n\n if (!socket && 'getSocket' in props) {\n dbg(providerDebug, { type: 'resolve', phase: 'start' });\n Promise.resolve(props.getSocket())\n .then((s) => {\n if (cancelled) return;\n setSocket(s);\n dbg(providerDebug, { type: 'resolve', phase: 'ok' });\n })\n .catch((err) => {\n if (cancelled) return;\n dbg(providerDebug, { type: 'resolve', phase: 'error', err: String(err) });\n });\n }\n\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [socket]); // run once per lifecycle\n\n const client = React.useMemo(() => {\n if (!socket) return null;\n const c = new SocketClient(events, { ...baseOptions, socket });\n dbg(providerDebug, { type: 'client', phase: 'ready' });\n return c;\n }, [events, baseOptions, socket, providerDebug]);\n\n React.useEffect(() => {\n return () => {\n if (client) {\n client.destroy();\n dbg(providerDebug, { type: 'client', phase: 'destroy' });\n }\n };\n }, [client, providerDebug]);\n\n if (!client) {\n dbg(providerDebug, { type: 'render', phase: 'waiting_for_socket' });\n return <>{fallback ?? children}</>;\n }\n\n dbg(providerDebug, { type: 'render', phase: 'provide' });\n return <SocketCtx.Provider value={client}>{children}</SocketCtx.Provider>;\n}\n\nfunction useSocketClient<Ping extends ZodType, Pong extends ZodType, T extends EventMap>(): SocketClient<\n Ping,\n Pong,\n T\n> {\n const ctx = React.useContext(SocketCtx);\n if (!ctx) throw new Error('SocketClient not found. Wrap with <SocketProvider>.');\n return ctx as unknown as SocketClient<Ping, Pong, T>;\n}\n\ntype Rooms = string[] | string | undefined;\n\nexport type UseSocketConnectionArgs<T extends EventMap, K extends keyof T & string> = {\n event: K;\n rooms?: Rooms;\n onMessage: (\n payload: Payload<T, K>,\n meta: { envelope: ServerEnvelope<T, K>; ctx: ClientCtx }\n ) => void;\n onCleanup?: () => void;\n autoJoin?: boolean;\n autoLeave?: boolean;\n deps?: React.DependencyList;\n};\n\nfunction useSocketConnection<T extends EventMap, K extends keyof T & string>(\n args: UseSocketConnectionArgs<T, K>\n) {\n const { event, rooms, onMessage, onCleanup, autoJoin = true, autoLeave = true } = args;\n const client = useSocketClient<ZodType, ZodType, T>();\n\n const normalizedRooms = React.useMemo(\n () => (rooms == null ? [] : Array.isArray(rooms) ? rooms : [rooms]),\n [rooms]\n );\n\n React.useEffect(() => {\n if (autoJoin && normalizedRooms.length > 0) client.joinRooms(normalizedRooms);\n const unsubscribe = client.on(event, onMessage);\n\n return () => {\n unsubscribe();\n if (autoLeave && normalizedRooms.length > 0) client.leaveRooms(normalizedRooms);\n if (onCleanup) onCleanup();\n };\n }, args.deps ?? [client, event, onMessage, autoJoin, autoLeave, ...normalizedRooms]);\n}\n","// socket.client.index.ts\n\nimport { Socket } from 'socket.io-client';\nimport { z, ZodType } from 'zod';\nimport type { SocketEvent } from '@emeryld/rrroutes-contract';\n\nexport type EventMap = Record<string, SocketEvent>;\nexport type Payload<T extends EventMap, K extends keyof T> = z.infer<T[K]['message']>;\n\nexport type ServerEnvelope<T extends EventMap, K extends keyof T & string> = {\n eventName: K;\n sentAt: string | Date;\n sentTo: string[];\n data?: Payload<T, K>;\n metadata?: Record<string, unknown>;\n};\n\nexport type ClientCtx = {\n receivedAt: Date;\n latencyMs?: number;\n nsp?: string;\n socketId?: string;\n rooms?: string[];\n socket?: Socket;\n reply?: (data?: unknown) => void;\n};\n\nexport type ClientStatsSnapshot = {\n roomsCount: number;\n totalHandlers: number;\n rooms: { room: string; count: number }[];\n handlers: { event: string; handlers: number }[];\n};\n\n// helper, since original code used NoInfer\ntype NoInfer<T> = [T][T extends any ? 0 : never];\n\n/**\n * Merged/logically grouped debug events.\n *\n * Buckets:\n * - connection: connect, reconnect, disconnect, connect_error\n * - register: register, unregister\n * - pingpong: ping_emit, pong_recv\n * - room: join, leave\n * - emit\n * - receive\n * - stats\n */\nexport type SocketClientDebugEvent<K extends string = string> =\n | {\n type: 'connection';\n phase: 'connect' | 'reconnect' | 'disconnect' | 'connect_error';\n id?: string;\n attempt?: number;\n reason?: string;\n err?: string;\n }\n | {\n type: 'register';\n action: 'register' | 'unregister';\n event: K;\n }\n | {\n type: 'heartbeat';\n action: 'ping_emit' | 'pong_recv';\n latencyMs?: number;\n payload?: unknown;\n }\n | {\n type: 'room';\n action: 'join' | 'leave';\n rooms: string[];\n }\n | {\n type: 'emit';\n event: K;\n metadata?: Record<string, unknown>;\n }\n | {\n type: 'receive';\n event: K;\n envelope?: {\n eventName: K;\n sentAt: string | Date;\n sentTo: string[];\n metadata?: Record<string, unknown>;\n };\n };\n\nexport type SocketClientDebugOptions<K extends string = string> = {\n verbose?: boolean;\n only?: K[];\n logger?: (e: SocketClientDebugEvent<K>) => void;\n} & {\n [P in SocketClientDebugEvent['type']]?: boolean;\n};\n\n/** === Heartbeat config (enforced) === */\nexport type HeartbeatClientOptions<Ping extends ZodType, Pong extends ZodType> = {\n /** Event names. Defaults are 'sys:ping' and 'sys:pong'. */\n pingEvent?: string;\n pongEvent?: string;\n /** Interval between pings. Default 15_000. */\n intervalMs?: number;\n /** Give up waiting for pong after this many ms. Default 7_500. */\n timeoutMs?: number;\n\n /** Schema of the ping payload you will emit. */\n pingSchema: Ping;\n /** Produce the ping payload on each tick. */\n makePingPayload: (ctx: { socket: Socket }) => NoInfer<z.infer<Ping>>;\n\n /** Optional validation of the pong payload you receive. */\n pongSchema?: Pong;\n /** Optional hook called on each pong. */\n onPong?: (args: { latencyMs: number; payload?: NoInfer<z.infer<Pong>>; socket: Socket }) => void;\n};\n\nexport type SocketClientOptions<\n Ping extends ZodType,\n Pong extends ZodType,\n T extends EventMap = EventMap\n> = {\n /** Inject an existing socket.io-client Socket. Required. */\n socket: Socket;\n roomJoinEvent?: string;\n roomLeaveEvent?: string;\n environment?: 'development' | 'production';\n debug?: SocketClientDebugOptions<keyof T & string>;\n /** required heartbeat config */\n heartbeat: HeartbeatClientOptions<Ping, Pong>;\n};\n\ntype HandlerEntry<T extends EventMap, K extends keyof T & string> = {\n orig: (payload: Payload<T, K>, meta: { envelope: ServerEnvelope<T, K>; ctx: ClientCtx }) => void;\n wrapped: (envelopeOrRaw: ServerEnvelope<T, K> | Payload<T, K>) => void;\n errorWrapped: (e: unknown) => void;\n};\n\nexport class SocketClient<Ping extends ZodType, Pong extends ZodType, T extends EventMap> {\n readonly socket: Socket;\n private readonly events: T;\n private readonly roomJoinEvent: string;\n private readonly roomLeaveEvent: string;\n private readonly environment: 'development' | 'production';\n private readonly debug: SocketClientDebugOptions<keyof T & string>;\n\n // heartbeat\n private readonly hb: Required<Omit<HeartbeatClientOptions<Ping, Pong>, 'pongSchema' | 'onPong'>> & {\n pongSchema?: z.ZodTypeAny;\n onPong?: HeartbeatClientOptions<Ping, Pong>['onPong'];\n };\n private hbTimer: ReturnType<typeof setInterval> | null = null;\n\n /** keep references so we can .off() later */\n private readonly onConnect: () => void;\n private readonly onReconnect: (attempt: number) => void;\n private readonly onDisconnect: (reason: unknown) => void;\n private readonly onConnectError: (err: unknown) => void;\n private readonly onPong: (raw: any) => void;\n\n // stats\n private readonly roomCounts = new Map<string, number>();\n private readonly handlerMap = new Map<string, Set<HandlerEntry<T, any>>>();\n\n constructor(events: T, opts: SocketClientOptions<Ping, Pong, T>) {\n this.events = events;\n this.socket = opts.socket;\n\n this.roomJoinEvent = opts.roomJoinEvent ?? 'room:join';\n this.roomLeaveEvent = opts.roomLeaveEvent ?? 'room:leave';\n this.environment = opts.environment ?? 'development';\n this.debug = opts.debug ?? {};\n // heartbeat fixed config\n const hb = opts.heartbeat;\n this.hb = {\n pingEvent: hb.pingEvent ?? 'sys:ping',\n pongEvent: hb.pongEvent ?? 'sys:pong',\n intervalMs: hb.intervalMs ?? 15_000,\n timeoutMs: hb.timeoutMs ?? 7_500,\n pingSchema: hb.pingSchema,\n makePingPayload: hb.makePingPayload,\n pongSchema: hb.pongSchema,\n onPong: hb.onPong,\n };\n\n /* socket lifecycle → connection bucket */\n this.onConnect = () => {\n this.dbg({\n type: 'connection',\n phase: 'connect',\n id: this.socket.id ?? '',\n });\n this.startHeartbeat();\n };\n\n this.onReconnect = (attempt) => {\n this.dbg({\n type: 'connection',\n phase: 'reconnect',\n attempt,\n });\n };\n\n this.onDisconnect = (reason) => {\n this.dbg({\n type: 'connection',\n phase: 'disconnect',\n reason: String(reason),\n });\n this.stopHeartbeat();\n };\n\n this.onConnectError = (err) => {\n this.dbg({\n type: 'connection',\n phase: 'connect_error',\n err: String(err),\n });\n };\n\n // wire pong listener → pingpong bucket\n this.onPong = (raw: any) => {\n const receivedAt = Date.now();\n const clientSentIso: string | undefined = raw?.clientEcho?.__clientSentAt;\n let latencyMs: number | undefined;\n\n if (clientSentIso) {\n const sent = Date.parse(clientSentIso);\n if (!Number.isNaN(sent)) latencyMs = Math.max(0, receivedAt - sent);\n }\n\n if (this.hb.pongSchema) {\n const ok = this.hb.pongSchema.safeParse(raw);\n if (!ok.success) return; // drop invalid\n }\n\n const latency = latencyMs ?? raw?.sinceMs ?? 0;\n\n this.dbg({\n type: 'heartbeat',\n action: 'pong_recv',\n latencyMs: latency,\n payload: raw,\n });\n\n this.hb.onPong?.({ latencyMs: latency, payload: raw, socket: this.socket });\n };\n\n // register top-level listeners with stored refs\n this.socket.on('connect', this.onConnect);\n this.socket.on('reconnect', this.onReconnect);\n this.socket.on('disconnect', this.onDisconnect);\n this.socket.on('connect_error', this.onConnectError);\n this.socket.on(this.hb.pongEvent, this.onPong);\n }\n\n private dbg(e: SocketClientDebugEvent<any>) {\n const d = this.debug;\n if (!d.logger) return;\n if (!d[e.type]) return;\n if (d.only && 'event' in e && !d.only.includes(e.event as any)) return;\n d.logger(e);\n }\n\n /** internal stats snapshot */\n stats(): ClientStatsSnapshot {\n const rooms = Array.from(this.roomCounts.entries()).map(([room, count]) => ({ room, count }));\n const handlers = Array.from(this.handlerMap.entries()).map(([event, set]) => ({\n event,\n handlers: set.size,\n }));\n return {\n roomsCount: rooms.length,\n totalHandlers: handlers.reduce((a, b) => a + b.handlers, 0),\n rooms,\n handlers,\n };\n }\n\n private toArray(rooms?: string[] | string): string[] {\n return rooms == null ? [] : Array.isArray(rooms) ? rooms : [rooms];\n }\n\n private startHeartbeat() {\n this.stopHeartbeat();\n\n const tick = () => {\n const basePayload = this.hb.makePingPayload({ socket: this.socket }) ?? {};\n const candidate = { ...basePayload, __clientSentAt: new Date().toISOString() };\n\n const check = this.hb.pingSchema.safeParse(candidate);\n if (!check.success) {\n if (this.environment === 'development')\n console.warn('[socket] ping schema validation failed', check.error.issues);\n return;\n }\n\n const timer = setTimeout(() => {\n /* timeout, no-op here */\n }, this.hb.timeoutMs);\n\n this.socket.timeout(this.hb.timeoutMs).emit(this.hb.pingEvent, { payload: check.data }, () => {\n clearTimeout(timer);\n });\n\n this.dbg({\n type: 'heartbeat',\n action: 'ping_emit',\n payload: check.data,\n });\n };\n\n this.hbTimer = setInterval(tick, this.hb.intervalMs);\n tick();\n }\n\n private stopHeartbeat() {\n if (this.hbTimer) {\n clearInterval(this.hbTimer as any);\n this.hbTimer = null;\n }\n }\n\n emit<K extends keyof T & string>(\n event: K,\n payload: Payload<T, K>,\n metadata?: Record<string, unknown>,\n onAck?: (ack: unknown) => void,\n timeoutMs?: number,\n ): void {\n const schema = this.events[event].message;\n const parsed = schema.safeParse(payload);\n if (!parsed.success) throw new Error(`Invalid payload for \"${event}\": ${parsed.error.message}`);\n\n if (onAck) {\n this.socket.timeout(timeoutMs ?? this.hb.timeoutMs).emit(String(event), parsed.data, (ack: unknown) => {\n try {\n onAck(ack);\n } catch {\n /* noop */\n }\n });\n } else {\n this.socket.emit(String(event), parsed.data);\n }\n\n this.dbg({\n type: 'emit',\n event,\n metadata: this.debug.verbose ? metadata : undefined,\n });\n }\n\n joinRooms(rooms?: string[] | string): void {\n const list = this.toArray(rooms);\n const toJoin: string[] = [];\n for (const r of list) {\n const next = (this.roomCounts.get(r) ?? 0) + 1;\n this.roomCounts.set(r, next);\n if (next === 1) toJoin.push(r);\n }\n if (toJoin.length > 0) {\n this.socket.emit(this.roomJoinEvent, { rooms: toJoin });\n this.dbg({ type: 'room', action: 'join', rooms: toJoin });\n }\n }\n\n leaveRooms(rooms?: string[] | string): void {\n const list = this.toArray(rooms);\n const toLeave: string[] = [];\n for (const r of list) {\n const curr = this.roomCounts.get(r) ?? 0;\n const next = Math.max(0, curr - 1);\n if (next === 0 && curr > 0) toLeave.push(r);\n if (next === 0) this.roomCounts.delete(r);\n else this.roomCounts.set(r, next);\n }\n if (toLeave.length > 0) {\n this.socket.emit(this.roomLeaveEvent, { rooms: toLeave });\n this.dbg({ type: 'room', action: 'leave', rooms: toLeave });\n }\n }\n\n on<K extends keyof T & string>(\n event: K,\n handler: (payload: Payload<T, K>, meta: { envelope: ServerEnvelope<T, K>; ctx: ClientCtx }) => void,\n ): () => void {\n const schema = this.events[event].message;\n\n this.dbg({ type: 'register', action: 'register', event });\n\n const wrapped = (\n envelopeOrRaw: ServerEnvelope<T, K> | Payload<T, K>,\n maybeAck?: (data?: unknown) => void,\n ) => {\n const maybeEnvelope = envelopeOrRaw as any;\n const rawData = maybeEnvelope?.data ?? maybeEnvelope;\n\n const parsed = schema.safeParse(rawData);\n if (!parsed.success) return;\n\n const receivedAt = new Date();\n const sentAt = maybeEnvelope?.sentAt ? new Date(maybeEnvelope.sentAt) : undefined;\n\n const meta = {\n envelope: {\n eventName: (maybeEnvelope?.eventName ?? event) as K,\n sentAt: maybeEnvelope?.sentAt ?? receivedAt.toISOString(),\n sentTo: maybeEnvelope?.sentTo ?? [],\n data: undefined,\n metadata: maybeEnvelope?.metadata,\n },\n ctx: {\n receivedAt,\n latencyMs: sentAt ? Math.max(0, receivedAt.getTime() - sentAt.getTime()) : undefined,\n nsp: (this.socket as any).nsp,\n socketId: this.socket.id,\n socket: this.socket,\n reply:\n typeof maybeAck === 'function'\n ? (d?: unknown) => {\n try {\n maybeAck(d);\n } catch {\n /* noop */\n }\n }\n : undefined,\n },\n } as const;\n\n this.dbg({\n type: 'receive',\n event,\n envelope: this.debug.verbose\n ? {\n eventName: meta.envelope.eventName,\n sentAt: meta.envelope.sentAt,\n sentTo: meta.envelope.sentTo,\n metadata: meta.envelope.metadata,\n }\n : undefined,\n });\n\n handler(parsed.data as any, meta as any);\n };\n\n const errorWrapped = (e: unknown) => {\n if (this.environment === 'development') {\n // eslint-disable-next-line no-console\n console.warn(`[socket] ${String(event)}:error`, e);\n }\n };\n\n this.socket.on(String(event), wrapped);\n this.socket.on(`${String(event)}:error`, errorWrapped);\n\n let set = this.handlerMap.get(String(event));\n if (!set) {\n set = new Set();\n this.handlerMap.set(String(event), set);\n }\n const entry: HandlerEntry<T, K> = { orig: handler, wrapped, errorWrapped };\n set.add(entry);\n\n return () => {\n this.socket.off(String(event), wrapped);\n this.socket.off(`${String(event)}:error`, errorWrapped);\n const s = this.handlerMap.get(String(event));\n if (s) {\n s.delete(entry);\n if (s.size === 0) this.handlerMap.delete(String(event));\n }\n this.dbg({ type: 'register', action: 'unregister', event });\n };\n }\n\n /**\n * Remove all listeners, stop timers, and leave rooms.\n * Call when disposing the client instance.\n */\n destroy(): void {\n // stop heartbeat timer\n this.stopHeartbeat();\n\n // remove top-level socket listeners\n this.socket.off('connect', this.onConnect);\n this.socket.off('reconnect', this.onReconnect);\n this.socket.off('disconnect', this.onDisconnect);\n this.socket.off('connect_error', this.onConnectError);\n this.socket.off(this.hb.pongEvent, this.onPong);\n\n // unsubscribe all per-event handlers\n for (const [event, set] of this.handlerMap.entries()) {\n for (const entry of set) {\n this.socket.off(String(event), entry.wrapped);\n this.socket.off(`${String(event)}:error`, entry.errorWrapped);\n }\n }\n this.handlerMap.clear();\n\n // leave any rooms we joined via ref-count\n const toLeave = Array.from(this.roomCounts.entries())\n .filter(([, count]) => count > 0)\n .map(([room]) => room);\n if (toLeave.length > 0) {\n this.socket.emit(this.roomLeaveEvent, { rooms: toLeave });\n this.dbg({ type: 'room', action: 'leave', rooms: toLeave });\n }\n this.roomCounts.clear();\n }\n\n /** Pass-throughs. Managing connection is the caller’s responsibility. */\n disconnect(): void {\n this.stopHeartbeat();\n this.socket.disconnect();\n this.dbg({ type: 'connection', phase: 'disconnect', reason: 'client_disconnect' });\n }\n\n connect(): void {\n this.socket.connect();\n this.dbg({ type: 'connection', phase: 'connect', id: this.socket.id ?? '' });\n }\n}\n\nexport * from './socket.client.context';\n"],"mappings":"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","names":["useEndpoint"]}
1
+ {"version":3,"sources":["../src/routesV3.client.fetch.ts","../src/routesV3.client.index.ts","../src/sockets/socket.client.context.tsx","../src/sockets/socket.client.index.ts"],"sourcesContent":["// routesV3.client.fetch.ts\n\nimport { Fetcher, FetchInput } from './routesV3.client.types';\n\n/**\n * Default fetch implementation used by the route client helper.\n * @param req Normalized request information (URL, method, body, headers).\n * @returns Parsed JSON (or text fallback) from the server response.\n */\nexport const defaultFetcher: Fetcher = async <T>(req: FetchInput): Promise<T> => {\n const headers: Record<string, string> = { ...(req.headers ?? {}) };\n const isFormData = typeof FormData !== 'undefined' && req.body instanceof FormData;\n if (!isFormData) {\n headers['Content-Type'] ||= 'application/json';\n headers['Accept'] ||= 'application/json';\n }\n\n const res = await fetch(req.url, {\n method: req.method,\n headers,\n body: isFormData ? (req.body as any) : req.body == null ? undefined : JSON.stringify(req.body),\n });\n\n const text = await res.text();\n if (!res.ok) {\n const snippet = text.slice(0, 400);\n throw new Error(`[${res.status}] ${res.statusText} — ${snippet}`);\n }\n\n try {\n return JSON.parse(text) as T;\n } catch {\n return text as unknown as T;\n }\n};\n","// routesV3.client.ts\nimport {\n keepPreviousData,\n useInfiniteQuery,\n useMutation,\n useQuery,\n type InfiniteData,\n type QueryKey,\n} from '@tanstack/react-query';\nimport type { ZodType } from 'zod';\nimport {\n HttpMethod,\n buildCacheKey,\n compilePath,\n} from '@emeryld/rrroutes-contract';\nimport type {\n AnyLeaf,\n InferBody,\n InferOutput,\n InferParams,\n InferQuery,\n} from '@emeryld/rrroutes-contract';\nimport { defaultFetcher } from './routesV3.client.fetch';\nimport type {\n ArgsFor,\n ArgsTuple,\n BuildMeta,\n BuiltForLeaf,\n BuiltInfinite,\n BuiltMutation,\n BuiltQuery,\n Cursor,\n DataShape,\n InfiniteBuildOptionsFor,\n MutationBuildOptionsFor,\n QueryBuildOptionsFor,\n RouteClient,\n RouteClientOptions,\n RouteClientDebugEvent,\n RouteClientDebugLogger,\n RouteClientDebugMode,\n RouteClientDebugOptions,\n RouteClientDebugToggleOptions,\n Updater,\n} from './routesV3.client.types';\n\n// -------------------------------------------------------------------------------------\n// Tiny helpers\n// -------------------------------------------------------------------------------------\n/**\n * Convert an HTTP method to uppercase (as expected by fetch).\n * @param m Lowercase HTTP method.\n * @returns Uppercase method string.\n */\nconst toUpper = (m: HttpMethod): Uppercase<HttpMethod> => m.toUpperCase() as Uppercase<HttpMethod>;\n\n/**\n * Parse the given value with the supplied schema (if present).\n * @param value Raw value to validate.\n * @param schema Optional Zod schema used for validation/coercion.\n * @returns The validated or original value.\n */\nfunction zParse<T>(value: unknown, schema?: ZodType): T {\n return schema ? (schema.parse(value) as T) : (value as T);\n}\n\n/**\n * Serialize a query object into a search string.\n * @param query Query params object (possibly undefined).\n * @returns Query string prefixed with `?`, or empty string.\n */\nfunction toSearchString(query: Record<string, unknown> | undefined) {\n if (!query) return '';\n const params = new URLSearchParams();\n for (const [k, v] of Object.entries(query)) {\n if (v == null) continue;\n if (Array.isArray(v)) {\n v.forEach((x) => {\n if (x == null) return;\n if (typeof x === 'object') {\n params.append(k, JSON.stringify(x));\n } else {\n params.append(k, String(x));\n }\n });\n continue;\n }\n if (typeof v === 'object') {\n params.set(k, JSON.stringify(v));\n continue;\n }\n params.set(k, String(v));\n }\n const s = params.toString();\n return s ? `?${s}` : '';\n}\n\n/**\n * Remove the given key from an object (used to drop cursors from cache keys).\n * @param obj Source object.\n * @param key Property name to omit.\n * @returns Copy of the object without the specified key.\n */\nfunction stripKey<Q extends Record<string, unknown> | undefined>(obj: Q, key: string): Q {\n if (!obj) return obj;\n const { [key]: _omit, ...rest } = obj as any;\n return rest as Q;\n}\n\n/**\n * Default cursor extractor used by infinite queries.\n * @param p Page result returned from the server.\n * @returns Next cursor string, if present.\n */\nconst defaultGetNextCursor = (p: unknown): Cursor =>\n p && typeof p === 'object' && 'nextCursor' in p ? (p as any).nextCursor : undefined;\n\n// Debug logging --------------------------------------------------------------\nconst noopDebugLogger: RouteClientDebugLogger = () => {};\n\nconst defaultDebugLogger: RouteClientDebugLogger = (event: RouteClientDebugEvent) => {\n if (typeof console === 'undefined') return;\n const fn = console.debug ?? console.log;\n fn?.call(console, '[rrroutes-client]', event);\n};\n\nconst debugEventTypes: RouteClientDebugEvent['type'][] = [\n 'fetch',\n 'invalidate',\n 'setData',\n 'build',\n 'useEndpoint',\n];\n\ntype DebugEmitter<Names extends string> = {\n emit: (event: RouteClientDebugEvent, name?: Names) => void;\n mode: RouteClientDebugMode;\n};\n\nconst noopEmit = () => {};\n\nfunction createDebugEmitter<Names extends string>(\n option?: RouteClientDebugOptions<Names>,\n environment?: string,\n): DebugEmitter<Names> {\n const disabled: DebugEmitter<Names> = { emit: noopEmit, mode: 'minimal' };\n\n if (environment && environment.toLowerCase() === 'production') {\n return disabled;\n }\n\n if (!option) {\n return disabled;\n }\n if (option === true || option === 'minimal') {\n return {\n emit: (event, name) => defaultDebugLogger(name ? { ...event, name } : event),\n mode: 'minimal',\n };\n }\n if (option === 'complete') {\n return {\n emit: (event, name) => defaultDebugLogger(name ? { ...event, name } : event),\n mode: 'complete',\n };\n }\n if (typeof option === 'function') {\n return {\n emit: (event, name) => option(name ? { ...event, name } : event),\n mode: 'minimal',\n };\n }\n if (typeof option === 'object') {\n const toggles = option as RouteClientDebugToggleOptions<Names>;\n const verbose = Boolean(toggles.verbose);\n const enabledTypes = debugEventTypes.filter((type) => toggles[type]);\n if (enabledTypes.length === 0) {\n return { emit: noopEmit, mode: verbose ? 'complete' : 'minimal' };\n }\n const whitelist = new Set<RouteClientDebugEvent['type']>(enabledTypes);\n const onlySet =\n toggles.only && toggles.only.length > 0 ? new Set<Names>(toggles.only) : undefined;\n const logger = toggles.logger ?? defaultDebugLogger;\n const emit: DebugEmitter<Names>['emit'] = (event, name) => {\n if (!whitelist.has(event.type)) return;\n if (onlySet) {\n if (!name || !onlySet.has(name)) return;\n }\n logger(name ? { ...event, name } : event);\n };\n return { emit, mode: verbose ? 'complete' : 'minimal' };\n }\n\n return disabled;\n}\n\n// Split the variadic tuple at runtime\n/**\n * Extract the optional argument object from a variadic tuple.\n * @param args Tuple passed to a built endpoint helper.\n * @returns The argument object if present.\n */\nfunction extractArgs<L extends AnyLeaf>(args: ArgsTuple<L>): ArgsFor<L> | undefined {\n return (args as unknown as any[])[0] as any;\n}\n\n/**\n * Normalize params and query values, then construct a request URL for the given leaf.\n * @param leaf Leaf describing the endpoint.\n * @param baseUrl Optional base URL prepended to the path.\n * @param params Route parameters supplied by the caller.\n * @param query Query parameters supplied by the caller.\n * @returns Object containing the composed URL plus normalized params/query payloads.\n */\nfunction buildUrl<L extends AnyLeaf>(\n leaf: L,\n baseUrl: string,\n params: InferParams<L> | undefined,\n query: InferQuery<L> | undefined,\n) {\n const normalizedParams = zParse<InferParams<L>>(params, leaf.cfg.paramsSchema);\n const normalizedQuery = zParse<InferQuery<L>>(query, leaf.cfg.querySchema);\n const path = compilePath<L['path']>(leaf.path, (normalizedParams ?? {}) as any);\n const url = `${baseUrl ?? ''}${path}${toSearchString(normalizedQuery as any)}`;\n return { url, normalizedQuery, normalizedParams };\n}\n\n// -------------------------------------------------------------------------------------\n// Client factory\n// -------------------------------------------------------------------------------------\n/**\n * Construct typed React Query helpers backed by a routes-v3 registry leaf.\n * @param opts Route client configuration (query client, fetcher overrides, etc).\n * @returns Object that can build endpoint hooks/mutations from leaves.\n */\nexport function createRouteClient<Names extends string = string>(\n opts: RouteClientOptions<Names>,\n): RouteClient<Names> {\n const queryClient = opts.queryClient;\n const fetcher = opts.fetcher ?? defaultFetcher;\n const baseUrl = opts.baseUrl;\n const cursorParam = opts.cursorParam ?? 'cursor';\n const getNextCursor = opts.getNextCursor ?? defaultGetNextCursor;\n const environment =\n opts.environment ?? undefined;\n const { emit: emitDebug, mode: debugMode } = createDebugEmitter<Names>(opts.debug, environment);\n const isVerboseDebug = debugMode === 'complete';\n const decorateDebugEvent = <T extends RouteClientDebugEvent>(\n event: T,\n details?: Partial<RouteClientDebugEvent>,\n ): RouteClientDebugEvent => {\n if (!isVerboseDebug || !details) return event;\n return { ...event, ...details } as RouteClientDebugEvent;\n };\n\n /**\n * Invalidate a set of queries sharing the given prefix.\n * @param prefix Key parts shared by matching endpoints.\n * @param exact When true, invalidate only exact key matches.\n */\n async function invalidate(prefix: string[], exact = false) {\n const queryKey = prefix as unknown as QueryKey;\n await queryClient.invalidateQueries({ queryKey, exact });\n emitDebug({ type: 'invalidate', key: queryKey, exact });\n }\n\n /**\n * Build the client surface for a single leaf (query/mutation/infinite query).\n * @param leaf Leaf describing the endpoint.\n * @param rqOpts Optional React Query configuration.\n * @returns Helper object exposing key/invalidate/setData/useEndpoint.\n */\n function buildInternal<L extends AnyLeaf>(\n leaf: L,\n rqOpts?: QueryBuildOptionsFor<L> | InfiniteBuildOptionsFor<L> | MutationBuildOptionsFor<L>,\n meta?: BuildMeta<Names>,\n ): BuiltForLeaf<L> {\n const isGet = leaf.method === 'get';\n const isFeed = !!leaf.cfg.feed;\n const method = toUpper(leaf.method);\n const leafLabel = `${leaf.method.toUpperCase()} ${String(leaf.path)}`;\n const debugName = meta?.name;\n const emit = (event: RouteClientDebugEvent) => emitDebug(event, debugName);\n emit({ type: 'build', leaf: leafLabel });\n\n // --- key/invalidate/setData shared helpers ---\n const key = (...tuple: ArgsTuple<L>): QueryKey => {\n const a = extractArgs<L>(tuple);\n const params = (a as any)?.params as InferParams<L> | undefined;\n const query = (a as any)?.query as InferQuery<L> | undefined;\n const qForKey = isGet && isFeed ? stripKey(query as any, cursorParam) : (query as any);\n return buildCacheKey({ leaf, params: params as any, query: qForKey }) as unknown as QueryKey;\n };\n\n /**\n * Invalidate the React Query cache for this exact leaf invocation.\n * @param tuple Optional params/query tuple.\n */\n const invalidateExact = async (...tuple: ArgsTuple<L>) => {\n const queryKey = key(...tuple);\n await queryClient.invalidateQueries({ queryKey, exact: true });\n emit({ type: 'invalidate', key: queryKey, exact: true });\n };\n\n /**\n * Update the cache entries for this leaf.\n * @param args Tuple whose first entry is the updater and optional params/query follow.\n */\n const setData = (...args: [Updater<DataShape<L>>, ...rest: ArgsTuple<L>]) => {\n const [updater, ...rest] = args;\n const k = key(...(rest as ArgsTuple<L>));\n if (isGet && isFeed) {\n queryClient.setQueryData<InfiniteData<InferOutput<L>> | undefined>(k, (prev) =>\n typeof updater === 'function' ? (updater as any)(prev) : (updater as any),\n );\n } else {\n queryClient.setQueryData<InferOutput<L> | undefined>(k, (prev) =>\n typeof updater === 'function' ? (updater as any)(prev) : (updater as any),\n );\n }\n emit({ type: 'setData', key: k });\n };\n\n // --- Infinite GET ---\n if (isGet && isFeed) {\n const useEndpoint: BuiltInfinite<L>['useEndpoint'] = (...tuple) => {\n emit({ type: 'useEndpoint', leaf: leafLabel, variant: 'infiniteGet' });\n const a = extractArgs<L>(tuple);\n const params = (a as any)?.params as InferParams<L> | undefined;\n const query = (a as any)?.query as InferQuery<L> | undefined;\n\n // Normalize once; we’ll inject the cursor per page below.\n const { normalizedQuery, normalizedParams } = buildUrl(leaf, baseUrl, params, query);\n return useInfiniteQuery<\n InferOutput<L>,\n unknown,\n InfiniteData<InferOutput<L>>,\n QueryKey,\n Cursor\n >({\n ...(rqOpts as InfiniteBuildOptionsFor<L>),\n queryKey: key(...tuple),\n initialPageParam: undefined,\n getNextPageParam: (lastPage) => getNextCursor(lastPage),\n placeholderData: keepPreviousData,\n queryFn: async ({ pageParam }) => {\n const pageQuery = {\n ...(normalizedQuery as any),\n ...(pageParam ? { [cursorParam]: pageParam } : {}),\n };\n const { url } = buildUrl(leaf, baseUrl, params, pageQuery);\n const startedAt = Date.now();\n const detail = isVerboseDebug ? { params: normalizedParams, query: pageQuery } : undefined;\n emit(\n decorateDebugEvent(\n { type: 'fetch', stage: 'start', method, url, leaf: leafLabel },\n detail,\n ),\n );\n try {\n const out = await fetcher<unknown>({ url, method });\n const parsed = zParse<InferOutput<L>>(out, leaf.cfg.outputSchema);\n\n // call onReceive after fetch and validation\n (rqOpts as InfiniteBuildOptionsFor<L> & { onReceive?: (data: InferOutput<L>) => void })\n ?.onReceive?.(parsed);\n\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'success',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n },\n isVerboseDebug ? { params: normalizedParams, query: pageQuery, output: parsed } : undefined,\n ),\n );\n return parsed;\n } catch (error) {\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'error',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n error,\n },\n detail,\n ),\n );\n throw error;\n }\n },\n // NOTE: TData is InfiniteData<T>, so we don't need a select here.\n }, queryClient);\n };\n\n return {\n key,\n invalidate: invalidateExact,\n setData: setData as any,\n useEndpoint,\n } as BuiltForLeaf<L>;\n }\n // --- Plain GET ---\n if (isGet) {\n const useEndpoint: BuiltQuery<L>['useEndpoint'] = (...tuple) => {\n emit({ type: 'useEndpoint', leaf: leafLabel, variant: 'get' });\n const a = extractArgs<L>(tuple);\n const params = (a as any)?.params as InferParams<L> | undefined;\n const query = (a as any)?.query as InferQuery<L> | undefined;\n\n const { url, normalizedQuery, normalizedParams } = buildUrl(leaf, baseUrl, params, query);\n return useQuery<InferOutput<L>, unknown, InferOutput<L>, QueryKey>({\n ...(rqOpts as QueryBuildOptionsFor<L>),\n queryKey: key(...tuple),\n placeholderData: keepPreviousData,\n queryFn: async () => {\n const startedAt = Date.now();\n const detail = isVerboseDebug\n ? { params: normalizedParams, query: normalizedQuery }\n : undefined;\n emit(\n decorateDebugEvent(\n { type: 'fetch', stage: 'start', method, url, leaf: leafLabel },\n detail,\n ),\n );\n try {\n const out = await fetcher<unknown>({ url, method });\n const parsed = zParse<InferOutput<L>>(out, leaf.cfg.outputSchema);\n\n // call onReceive after fetch and validation\n (rqOpts as QueryBuildOptionsFor<L> & { onReceive?: (data: InferOutput<L>) => void })\n ?.onReceive?.(parsed);\n\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'success',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n },\n isVerboseDebug\n ? { params: normalizedParams, query: normalizedQuery, output: parsed }\n : undefined,\n ),\n );\n return parsed;\n } catch (error) {\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'error',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n error,\n },\n detail,\n ),\n );\n throw error;\n }\n },\n }, queryClient);\n };\n\n return {\n key,\n invalidate: invalidateExact,\n setData: setData as any,\n useEndpoint,\n } as BuiltForLeaf<L>;\n }\n\n // --- Mutation (POST/PUT/PATCH/DELETE) ---\n const fetchEndpoint: BuiltMutation<L>['fetch'] = async (\n ...tupleWithBody: [...ArgsTuple<L>, InferBody<L>]\n ) => {\n if (tupleWithBody.length === 0) {\n throw new Error('Body is required when invoking a mutation fetch.');\n }\n const bodyIndex = tupleWithBody.length - 1;\n const tuple = tupleWithBody.slice(0, bodyIndex) as ArgsTuple<L>;\n const body = tupleWithBody[bodyIndex] as InferBody<L>;\n const args = extractArgs<L>(tuple);\n const params = (args as any)?.params as InferParams<L> | undefined;\n const query = (args as any)?.query as InferQuery<L> | undefined;\n\n const { url, normalizedQuery, normalizedParams } = buildUrl(leaf, baseUrl, params, query);\n const normalizedBody = zParse<InferBody<L>>(body, leaf.cfg.bodySchema);\n\n const isMultipart = Array.isArray(leaf.cfg.bodyFiles) && leaf.cfg.bodyFiles.length > 0;\n const payload = isMultipart ? toFormData(normalizedBody as any) : normalizedBody;\n\n const startedAt = Date.now();\n const detail = isVerboseDebug\n ? { params: normalizedParams, query: normalizedQuery }\n : undefined;\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'start',\n method,\n url,\n leaf: leafLabel,\n body: payload,\n },\n detail,\n ),\n );\n try {\n const out = await fetcher<unknown>({ url, method, body: payload });\n const parsed = zParse<InferOutput<L>>(out, leaf.cfg.outputSchema);\n\n // call onReceive after fetch and validation\n (rqOpts as MutationBuildOptionsFor<L> & { onReceive?: (data: InferOutput<L>) => void })\n ?.onReceive?.(parsed);\n\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'success',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n },\n isVerboseDebug\n ? { params: normalizedParams, query: normalizedQuery, output: parsed }\n : undefined,\n ),\n );\n return parsed;\n } catch (error) {\n emit(\n decorateDebugEvent(\n {\n type: 'fetch',\n stage: 'error',\n method,\n url,\n leaf: leafLabel,\n durationMs: Date.now() - startedAt,\n body: payload,\n error,\n },\n detail,\n ),\n );\n throw error;\n }\n };\n\n const useEndpoint: BuiltMutation<L>['useEndpoint'] = (...tuple) => {\n emit({ type: 'useEndpoint', leaf: leafLabel, variant: 'mutation' });\n return useMutation<InferOutput<L>, unknown, InferBody<L>, unknown>({\n ...(rqOpts as MutationBuildOptionsFor<L>),\n mutationKey: key(...tuple),\n mutationFn: (body: InferBody<L>) =>\n fetchEndpoint(...([...tuple, body] as [...ArgsTuple<L>, InferBody<L>])),\n }, queryClient);\n };\n\n return {\n key,\n invalidate: invalidateExact,\n setData: setData as any,\n useEndpoint,\n fetch: fetchEndpoint,\n } as BuiltForLeaf<L>;\n }\n\n return {\n queryClient,\n invalidate,\n build: buildInternal as RouteClient<Names>['build'],\n };\n}\n\n// -------------------------------------------------------------------------------------\n// Multipart helper\n// -------------------------------------------------------------------------------------\nfunction toFormData(body: Record<string, any>): FormData {\n const fd = new FormData();\n for (const [k, v] of Object.entries(body ?? {})) {\n if (v == null) continue;\n if (Array.isArray(v)) v.forEach((item, i) => fd.append(`${k}[${i}]`, item as any));\n else fd.append(k, v as any);\n }\n return fd;\n}\n","// socket.client.context.tsx\n\nimport * as React from 'react';\nimport { Socket } from 'socket.io-client';\nimport {\n SocketClient,\n SocketClientOptions,\n EventMap,\n ClientCtx,\n Payload,\n ServerEnvelope,\n} from './socket.client.index';\nimport { ZodType } from 'zod';\n\n/** === Provider-side debug === */\nexport type SocketProviderDebugEvent =\n | { type: 'resolve'; phase: 'start' | 'ok' | 'error' | 'missing' | 'cancelled'; err?: string }\n | { type: 'client'; phase: 'ready' | 'destroy' | 'missing' }\n | { type: 'render'; phase: 'waiting_for_socket' | 'provide' };\n\nexport type SocketProviderDebugOptions = {\n verbose?: boolean;\n logger?: (e: SocketProviderDebugEvent) => void;\n} & {\n [P in SocketProviderDebugEvent['type']]?: boolean;\n};\n\n/** === Types for runtime socket injection === */\ntype BaseOptions<Ping extends ZodType, Pong extends ZodType, T extends EventMap> = Omit<\n SocketClientOptions<Ping, Pong, T>,\n 'socket'\n>;\n\ntype ProviderRuntimeSocket =\n | { socket: Socket | null } // CHANGED: may be null\n | { getSocket: () => Socket | Promise<Socket> }; // lazy/async socket\n\ntype SocketProviderProps<Ping extends ZodType, Pong extends ZodType, T extends EventMap> =\n React.PropsWithChildren<{\n events: T;\n baseOptions: BaseOptions<Ping, Pong, T>;\n /** show while waiting for async socket; should not use the socket context */\n fallback?: React.ReactNode;\n providerDebug?: SocketProviderDebugOptions;\n } & ProviderRuntimeSocket>;\n\nconst SocketCtx = React.createContext<SocketClient<ZodType, ZodType, any> | null>(null);\n\nfunction dbg(dbgOpts: SocketProviderDebugOptions | undefined, e: SocketProviderDebugEvent) {\n if (!dbgOpts?.logger) return;\n if (!dbgOpts[e.type]) return;\n dbgOpts.logger(e);\n}\n\nexport function buildSocketProvider<Ping extends ZodType, Pong extends ZodType, T extends EventMap>(args: {\n events: T;\n options: BaseOptions<Ping, Pong, T>;\n}) {\n const { events, options: baseOptions } = args;\n\n return {\n SocketProvider: (\n props: React.PropsWithChildren<\n ProviderRuntimeSocket & { fallback?: React.ReactNode; providerDebug?: SocketProviderDebugOptions }\n >\n ) => (\n <SocketProvider<Ping, Pong, T>\n events={events}\n baseOptions={baseOptions}\n {...props}\n />\n ),\n useSocketClient: () => useSocketClient<Ping, Pong, T>(),\n useSocketConnection: <K extends keyof T & string>(\n p: Parameters<typeof useSocketConnection<T, K>>[0]\n ) => useSocketConnection<T, K>(p),\n };\n}\n\nfunction SocketProvider<Ping extends ZodType, Pong extends ZodType, T extends EventMap>(\n props: SocketProviderProps<Ping, Pong, T>\n) {\n const { events, baseOptions, children, fallback, providerDebug } = props;\n\n // Async sockets are resolved into this state.\n const [resolvedSocket, setResolvedSocket] = React.useState<Socket | null>(null); // CHANGED\n\n // Single source of truth for \"the socket we should use right now\".\n const socket: Socket | null =\n 'socket' in props ? props.socket ?? null : resolvedSocket; // CHANGED\n\n React.useEffect(() => {\n if (!('getSocket' in props)) return;\n\n let cancelled = false;\n dbg(providerDebug, { type: 'resolve', phase: 'start' });\n\n if (!resolvedSocket) {\n Promise.resolve(props.getSocket())\n .then((s) => {\n if (cancelled) {\n dbg(providerDebug, { type: 'resolve', phase: 'cancelled' });\n return; // CHANGED: don't set state after cancel\n }\n if (!s) {\n dbg(providerDebug, { type: 'resolve', phase: 'missing' });\n return;\n }\n setResolvedSocket(s);\n dbg(providerDebug, { type: 'resolve', phase: 'ok' });\n })\n .catch((err) => {\n if (cancelled) return;\n dbg(providerDebug, { type: 'resolve', phase: 'error', err: String(err) });\n });\n }\n\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [resolvedSocket]); // run once per lazy resolution\n\n const client = React.useMemo(() => {\n if (!socket) {\n dbg(providerDebug, { type: 'client', phase: 'missing' }); // CHANGED\n return null;\n }\n const c = new SocketClient(events, { ...baseOptions, socket });\n dbg(providerDebug, { type: 'client', phase: 'ready' });\n return c;\n }, [events, baseOptions, socket, providerDebug]);\n\n React.useEffect(() => {\n return () => {\n if (client) {\n client.destroy();\n dbg(providerDebug, { type: 'client', phase: 'destroy' });\n }\n };\n }, [client, providerDebug]);\n\n if (!client) {\n dbg(providerDebug, { type: 'render', phase: 'waiting_for_socket' });\n return <>{fallback ?? children}</>;\n }\n\n dbg(providerDebug, { type: 'render', phase: 'provide' });\n return <SocketCtx.Provider value={client}>{children}</SocketCtx.Provider>;\n}\n\n// useSocketClient / useSocketConnection unchanged\nfunction useSocketClient<Ping extends ZodType, Pong extends ZodType, T extends EventMap>(): SocketClient<\n Ping,\n Pong,\n T\n> {\n const ctx = React.useContext(SocketCtx);\n if (!ctx) throw new Error('SocketClient not found. Wrap with <SocketProvider>.');\n return ctx as unknown as SocketClient<Ping, Pong, T>;\n}\n\ntype Rooms = string[] | string | undefined;\n\nexport type UseSocketConnectionArgs<T extends EventMap, K extends keyof T & string> = {\n event: K;\n rooms?: Rooms;\n onMessage: (\n payload: Payload<T, K>,\n meta: { envelope: ServerEnvelope<T, K>; ctx: ClientCtx }\n ) => void;\n onCleanup?: () => void;\n autoJoin?: boolean;\n autoLeave?: boolean;\n deps?: React.DependencyList;\n};\n\nfunction useSocketConnection<T extends EventMap, K extends keyof T & string>(\n args: UseSocketConnectionArgs<T, K>\n) {\n const { event, rooms, onMessage, onCleanup, autoJoin = true, autoLeave = true } = args;\n const client = useSocketClient<ZodType, ZodType, T>();\n\n const normalizedRooms = React.useMemo(\n () => (rooms == null ? [] : Array.isArray(rooms) ? rooms : [rooms]),\n [rooms]\n );\n\n React.useEffect(() => {\n if (autoJoin && normalizedRooms.length > 0) client.joinRooms(normalizedRooms);\n const unsubscribe = client.on(event, onMessage);\n\n return () => {\n unsubscribe();\n if (autoLeave && normalizedRooms.length > 0) client.leaveRooms(normalizedRooms);\n if (onCleanup) onCleanup();\n };\n }, args.deps ?? [client, event, onMessage, autoJoin, autoLeave, ...normalizedRooms]);\n}\n","// socket.client.index.ts\nimport { Socket } from 'socket.io-client';\nimport { z, ZodType } from 'zod';\nimport type { SocketEvent } from '@emeryld/rrroutes-contract';\n\ntype MaybeSocket = Socket | null;\n\nexport type EventMap = Record<string, SocketEvent>;\nexport type Payload<T extends EventMap, K extends keyof T> = z.infer<T[K]['message']>;\n\nexport type ServerEnvelope<T extends EventMap, K extends keyof T & string> = {\n eventName: K;\n sentAt: string | Date;\n sentTo: string[];\n data?: Payload<T, K>;\n metadata?: Record<string, unknown>;\n};\n\nexport type ClientCtx = {\n receivedAt: Date;\n latencyMs?: number;\n nsp?: string;\n socketId?: string;\n rooms?: string[];\n socket?: MaybeSocket; // CHANGED\n reply?: (data?: unknown) => void;\n};\n\nexport type ClientStatsSnapshot = {\n roomsCount: number;\n totalHandlers: number;\n rooms: { room: string; count: number }[];\n handlers: { event: string; handlers: number }[];\n};\n\n// helper, since original code used NoInfer\ntype NoInfer<T> = [T][T extends any ? 0 : never];\n\nexport type SocketClientDebugEvent<K extends string = string> =\n | {\n type: 'connection';\n phase: 'connect' | 'reconnect' | 'disconnect' | 'connect_error';\n id?: string;\n attempt?: number;\n reason?: string;\n err?: string;\n }\n | {\n type: 'register';\n action: 'register' | 'unregister';\n event: K;\n }\n | {\n type: 'heartbeat';\n action: 'ping_emit' | 'pong_recv';\n latencyMs?: number;\n payload?: unknown;\n }\n | {\n type: 'room';\n action: 'join' | 'leave';\n rooms: string[];\n }\n | {\n type: 'emit';\n event: K;\n metadata?: Record<string, unknown>;\n }\n | {\n type: 'receive';\n event: K;\n envelope?: {\n eventName: K;\n sentAt: string | Date;\n sentTo: string[];\n metadata?: Record<string, unknown>;\n };\n };\n\nexport type SocketClientDebugOptions<K extends string = string> = {\n verbose?: boolean;\n only?: K[];\n logger?: (e: SocketClientDebugEvent<K>) => void;\n} & {\n [P in SocketClientDebugEvent['type']]?: boolean;\n};\n\n/** === Heartbeat config (enforced) === */\nexport type HeartbeatClientOptions<Ping extends ZodType, Pong extends ZodType> = {\n /** Event names. Defaults are 'sys:ping' and 'sys:pong'. */\n pingEvent?: string;\n pongEvent?: string;\n /** Interval between pings. Default 15_000. */\n intervalMs?: number;\n /** Give up waiting for pong after this many ms. Default 7_500. */\n timeoutMs?: number;\n\n /** Schema of the ping payload you will emit. */\n pingSchema: Ping;\n /** Produce the ping payload on each tick. */\n makePingPayload: (ctx: { socket: MaybeSocket }) => NoInfer<z.infer<Ping>>; // CHANGED\n\n /** Optional validation of the pong payload you receive. */\n pongSchema?: Pong;\n /** Optional hook called on each pong. */\n onPong?: (args: {\n latencyMs: number;\n payload?: NoInfer<z.infer<Pong>>;\n socket: MaybeSocket; // CHANGED\n }) => void;\n};\n\nexport type SocketClientOptions<\n Ping extends ZodType,\n Pong extends ZodType,\n T extends EventMap = EventMap\n> = {\n /** Inject an existing socket.io-client Socket. Can be null while bootstrapping. */\n socket: MaybeSocket; // CHANGED\n roomJoinEvent?: string;\n roomLeaveEvent?: string;\n environment?: 'development' | 'production';\n debug?: SocketClientDebugOptions<keyof T & string>;\n /** required heartbeat config */\n heartbeat: HeartbeatClientOptions<Ping, Pong>;\n};\n\ntype HandlerEntry<T extends EventMap, K extends keyof T & string> = {\n orig: (payload: Payload<T, K>, meta: { envelope: ServerEnvelope<T, K>; ctx: ClientCtx }) => void;\n wrapped: (envelopeOrRaw: ServerEnvelope<T, K> | Payload<T, K>) => void;\n errorWrapped: (e: unknown) => void;\n};\n\nexport class SocketClient<Ping extends ZodType, Pong extends ZodType, T extends EventMap> {\n readonly socket: MaybeSocket; // CHANGED\n private readonly events: T;\n private readonly roomJoinEvent: string;\n private readonly roomLeaveEvent: string;\n private readonly environment: 'development' | 'production';\n private readonly debug: SocketClientDebugOptions<keyof T & string>;\n\n // heartbeat\n private readonly hb: Required<Omit<HeartbeatClientOptions<Ping, Pong>, 'pongSchema' | 'onPong'>> & {\n pongSchema?: z.ZodTypeAny;\n onPong?: HeartbeatClientOptions<Ping, Pong>['onPong'];\n };\n private hbTimer: ReturnType<typeof setInterval> | null = null;\n\n /** keep references so we can .off() later */\n private readonly onConnect: () => void;\n private readonly onReconnect: (attempt: number) => void;\n private readonly onDisconnect: (reason: unknown) => void;\n private readonly onConnectError: (err: unknown) => void;\n private readonly onPong: (raw: any) => void;\n\n // stats\n private readonly roomCounts = new Map<string, number>();\n private readonly handlerMap = new Map<string, Set<HandlerEntry<T, any>>>();\n\n constructor(events: T, opts: SocketClientOptions<Ping, Pong, T>) {\n this.events = events;\n this.socket = opts.socket ?? null; // CHANGED\n\n this.roomJoinEvent = opts.roomJoinEvent ?? 'room:join';\n this.roomLeaveEvent = opts.roomLeaveEvent ?? 'room:leave';\n this.environment = opts.environment ?? 'development';\n this.debug = opts.debug ?? {};\n // heartbeat fixed config\n const hb = opts.heartbeat;\n this.hb = {\n pingEvent: hb.pingEvent ?? 'sys:ping',\n pongEvent: hb.pongEvent ?? 'sys:pong',\n intervalMs: hb.intervalMs ?? 15_000,\n timeoutMs: hb.timeoutMs ?? 7_500,\n pingSchema: hb.pingSchema,\n makePingPayload: hb.makePingPayload,\n pongSchema: hb.pongSchema,\n onPong: hb.onPong,\n };\n\n /* socket lifecycle → connection bucket */\n this.onConnect = () => {\n this.dbg({\n type: 'connection',\n phase: 'connect',\n id: this.socket?.id ?? '', // CHANGED\n });\n this.startHeartbeat();\n };\n\n this.onReconnect = (attempt) => {\n this.dbg({\n type: 'connection',\n phase: 'reconnect',\n attempt,\n });\n };\n\n this.onDisconnect = (reason) => {\n this.dbg({\n type: 'connection',\n phase: 'disconnect',\n reason: String(reason),\n });\n this.stopHeartbeat();\n };\n\n this.onConnectError = (err) => {\n this.dbg({\n type: 'connection',\n phase: 'connect_error',\n err: String(err),\n });\n };\n\n // wire pong listener → pingpong bucket\n this.onPong = (raw: any) => {\n const receivedAt = Date.now();\n const clientSentIso: string | undefined = raw?.clientEcho?.__clientSentAt;\n let latencyMs: number | undefined;\n\n if (clientSentIso) {\n const sent = Date.parse(clientSentIso);\n if (!Number.isNaN(sent)) latencyMs = Math.max(0, receivedAt - sent);\n }\n\n if (this.hb.pongSchema) {\n const ok = this.hb.pongSchema.safeParse(raw);\n if (!ok.success) return; // drop invalid\n }\n\n const latency = latencyMs ?? raw?.sinceMs ?? 0;\n\n this.dbg({\n type: 'heartbeat',\n action: 'pong_recv',\n latencyMs: latency,\n payload: raw,\n });\n\n this.hb.onPong?.({ latencyMs: latency, payload: raw, socket: this.socket }); // CHANGED\n };\n\n // register top-level listeners with stored refs (only if we have a socket)\n if (this.socket) {\n this.socket.on('connect', this.onConnect);\n this.socket.on('reconnect', this.onReconnect);\n this.socket.on('disconnect', this.onDisconnect);\n this.socket.on('connect_error', this.onConnectError);\n this.socket.on(this.hb.pongEvent, this.onPong);\n }\n }\n\n private dbg(e: SocketClientDebugEvent<any>) {\n const d = this.debug;\n if (!d.logger) return;\n if (!d[e.type]) return;\n if (d.only && 'event' in e && !d.only.includes(e.event as any)) return;\n d.logger(e);\n }\n\n /** internal stats snapshot */\n stats(): ClientStatsSnapshot {\n const rooms = Array.from(this.roomCounts.entries()).map(([room, count]) => ({ room, count }));\n const handlers = Array.from(this.handlerMap.entries()).map(([event, set]) => ({\n event,\n handlers: set.size,\n }));\n return {\n roomsCount: rooms.length,\n totalHandlers: handlers.reduce((a, b) => a + b.handlers, 0),\n rooms,\n handlers,\n };\n }\n\n private toArray(rooms?: string[] | string): string[] {\n return rooms == null ? [] : Array.isArray(rooms) ? rooms : [rooms];\n }\n\n private startHeartbeat() {\n this.stopHeartbeat();\n if (!this.socket) return; // CHANGED\n\n const tick = () => {\n if (!this.socket) return; // CHANGED: extra safety\n\n const basePayload = this.hb.makePingPayload({ socket: this.socket }) ?? {};\n const candidate = { ...basePayload, __clientSentAt: new Date().toISOString() };\n\n const check = this.hb.pingSchema.safeParse(candidate);\n if (!check.success) {\n if (this.environment === 'development')\n // eslint-disable-next-line no-console\n console.warn('[socket] ping schema validation failed', check.error.issues);\n return;\n }\n\n const timer = setTimeout(() => {\n /* timeout, no-op here */\n }, this.hb.timeoutMs);\n\n this.socket\n .timeout(this.hb.timeoutMs)\n .emit(this.hb.pingEvent, { payload: check.data }, () => {\n clearTimeout(timer);\n });\n\n this.dbg({\n type: 'heartbeat',\n action: 'ping_emit',\n payload: check.data,\n });\n };\n\n this.hbTimer = setInterval(tick, this.hb.intervalMs);\n tick();\n }\n\n private stopHeartbeat() {\n if (this.hbTimer) {\n clearInterval(this.hbTimer as any);\n this.hbTimer = null;\n }\n }\n\n emit<K extends keyof T & string>(\n event: K,\n payload: Payload<T, K>,\n metadata?: Record<string, unknown>,\n onAck?: (ack: unknown) => void,\n timeoutMs?: number,\n ): void {\n const schema = this.events[event].message;\n const parsed = schema.safeParse(payload);\n if (!parsed.success) throw new Error(`Invalid payload for \"${event}\": ${parsed.error.message}`);\n\n if (!this.socket) {\n if (this.environment === 'development') {\n // eslint-disable-next-line no-console\n console.warn(`[socket] emit(\"${String(event)}\") skipped because socket is null`); // CHANGED\n }\n return;\n }\n\n if (onAck) {\n this.socket\n .timeout(timeoutMs ?? this.hb.timeoutMs)\n .emit(String(event), parsed.data, (ack: unknown) => {\n try {\n onAck(ack);\n } catch {\n /* noop */\n }\n });\n } else {\n this.socket.emit(String(event), parsed.data);\n }\n\n this.dbg({\n type: 'emit',\n event,\n metadata: this.debug.verbose ? metadata : undefined,\n });\n }\n\n joinRooms(rooms?: string[] | string): void {\n const list = this.toArray(rooms);\n const toJoin: string[] = [];\n for (const r of list) {\n const next = (this.roomCounts.get(r) ?? 0) + 1;\n this.roomCounts.set(r, next);\n if (next === 1) toJoin.push(r);\n }\n if (toJoin.length > 0 && this.socket) { // CHANGED\n this.socket.emit(this.roomJoinEvent, { rooms: toJoin });\n this.dbg({ type: 'room', action: 'join', rooms: toJoin });\n }\n }\n\n leaveRooms(rooms?: string[] | string): void {\n const list = this.toArray(rooms);\n const toLeave: string[] = [];\n for (const r of list) {\n const curr = this.roomCounts.get(r) ?? 0;\n const next = Math.max(0, curr - 1);\n if (next === 0 && curr > 0) toLeave.push(r);\n if (next === 0) this.roomCounts.delete(r);\n else this.roomCounts.set(r, next);\n }\n if (toLeave.length > 0 && this.socket) { // CHANGED\n this.socket.emit(this.roomLeaveEvent, { rooms: toLeave });\n this.dbg({ type: 'room', action: 'leave', rooms: toLeave });\n }\n }\n\n on<K extends keyof T & string>(\n event: K,\n handler: (payload: Payload<T, K>, meta: { envelope: ServerEnvelope<T, K>; ctx: ClientCtx }) => void,\n ): () => void {\n const schema = this.events[event].message;\n\n this.dbg({ type: 'register', action: 'register', event });\n\n if (!this.socket) {\n if (this.environment === 'development') {\n // eslint-disable-next-line no-console\n console.warn(`[socket] on(\"${String(event)}\") skipped because socket is null`); // CHANGED\n }\n return () => {};\n }\n\n const socket = this.socket; // CHANGED: capture non-null\n\n const wrapped = (\n envelopeOrRaw: ServerEnvelope<T, K> | Payload<T, K>,\n maybeAck?: (data?: unknown) => void,\n ) => {\n const maybeEnvelope = envelopeOrRaw as any;\n const rawData = maybeEnvelope?.data ?? maybeEnvelope;\n\n const parsed = schema.safeParse(rawData);\n if (!parsed.success) return;\n\n const receivedAt = new Date();\n const sentAt = maybeEnvelope?.sentAt ? new Date(maybeEnvelope.sentAt) : undefined;\n\n const meta = {\n envelope: {\n eventName: (maybeEnvelope?.eventName ?? event) as K,\n sentAt: maybeEnvelope?.sentAt ?? receivedAt.toISOString(),\n sentTo: maybeEnvelope?.sentTo ?? [],\n data: undefined,\n metadata: maybeEnvelope?.metadata,\n },\n ctx: {\n receivedAt,\n latencyMs: sentAt ? Math.max(0, receivedAt.getTime() - sentAt.getTime()) : undefined,\n nsp: (socket as any).nsp,\n socketId: socket.id,\n socket,\n reply:\n typeof maybeAck === 'function'\n ? (d?: unknown) => {\n try {\n maybeAck(d);\n } catch {\n /* noop */\n }\n }\n : undefined,\n },\n } as const;\n\n this.dbg({\n type: 'receive',\n event,\n envelope: this.debug.verbose\n ? {\n eventName: meta.envelope.eventName,\n sentAt: meta.envelope.sentAt,\n sentTo: meta.envelope.sentTo,\n metadata: meta.envelope.metadata,\n }\n : undefined,\n });\n\n handler(parsed.data as any, meta as any);\n };\n\n const errorWrapped = (e: unknown) => {\n if (this.environment === 'development') {\n // eslint-disable-next-line no-console\n console.warn(`[socket] ${String(event)}:error`, e);\n }\n };\n\n socket.on(String(event), wrapped);\n socket.on(`${String(event)}:error`, errorWrapped);\n\n let set = this.handlerMap.get(String(event));\n if (!set) {\n set = new Set();\n this.handlerMap.set(String(event), set);\n }\n const entry: HandlerEntry<T, K> = { orig: handler, wrapped, errorWrapped };\n set.add(entry);\n\n return () => {\n socket.off(String(event), wrapped);\n socket.off(`${String(event)}:error`, errorWrapped);\n const s = this.handlerMap.get(String(event));\n if (s) {\n s.delete(entry);\n if (s.size === 0) this.handlerMap.delete(String(event));\n }\n this.dbg({ type: 'register', action: 'unregister', event });\n };\n }\n\n /**\n * Remove all listeners, stop timers, and leave rooms.\n * Call when disposing the client instance.\n */\n destroy(): void {\n // stop heartbeat timer\n this.stopHeartbeat();\n\n const socket = this.socket; // CHANGED\n\n // remove top-level socket listeners\n if (socket) {\n socket.off('connect', this.onConnect);\n socket.off('reconnect', this.onReconnect);\n socket.off('disconnect', this.onDisconnect);\n socket.off('connect_error', this.onConnectError);\n socket.off(this.hb.pongEvent, this.onPong);\n\n // unsubscribe all per-event handlers\n for (const [event, set] of this.handlerMap.entries()) {\n for (const entry of set) {\n socket.off(String(event), entry.wrapped);\n socket.off(`${String(event)}:error`, entry.errorWrapped);\n }\n }\n }\n this.handlerMap.clear();\n\n // leave any rooms we joined via ref-count\n const toLeave = Array.from(this.roomCounts.entries())\n .filter(([, count]) => count > 0)\n .map(([room]) => room);\n if (toLeave.length > 0 && socket) { // CHANGED\n socket.emit(this.roomLeaveEvent, { rooms: toLeave });\n this.dbg({ type: 'room', action: 'leave', rooms: toLeave });\n }\n this.roomCounts.clear();\n }\n\n /** Pass-throughs. Managing connection is the caller’s responsibility. */\n disconnect(): void {\n if (!this.socket) return; // CHANGED\n this.stopHeartbeat();\n this.socket.disconnect();\n this.dbg({ type: 'connection', phase: 'disconnect', reason: 'client_disconnect' });\n }\n\n connect(): void {\n if (!this.socket) return; // CHANGED\n this.socket.connect();\n this.dbg({ type: 'connection', phase: 'connect', id: this.socket.id ?? '' });\n }\n}\n\nexport * from './socket.client.context';\n"],"mappings":"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","names":["useEndpoint"]}
@@ -5,11 +5,11 @@ import { ZodType } from 'zod';
5
5
  /** === Provider-side debug === */
6
6
  export type SocketProviderDebugEvent = {
7
7
  type: 'resolve';
8
- phase: 'start' | 'ok' | 'error';
8
+ phase: 'start' | 'ok' | 'error' | 'missing' | 'cancelled';
9
9
  err?: string;
10
10
  } | {
11
11
  type: 'client';
12
- phase: 'ready' | 'destroy';
12
+ phase: 'ready' | 'destroy' | 'missing';
13
13
  } | {
14
14
  type: 'render';
15
15
  phase: 'waiting_for_socket' | 'provide';
@@ -23,7 +23,7 @@ export type SocketProviderDebugOptions = {
23
23
  /** === Types for runtime socket injection === */
24
24
  type BaseOptions<Ping extends ZodType, Pong extends ZodType, T extends EventMap> = Omit<SocketClientOptions<Ping, Pong, T>, 'socket'>;
25
25
  type ProviderRuntimeSocket = {
26
- socket: Socket;
26
+ socket: Socket | null;
27
27
  } | {
28
28
  getSocket: () => Socket | Promise<Socket>;
29
29
  };
@@ -1,6 +1,7 @@
1
1
  import { Socket } from 'socket.io-client';
2
2
  import { z, ZodType } from 'zod';
3
3
  import type { SocketEvent } from '@emeryld/rrroutes-contract';
4
+ type MaybeSocket = Socket | null;
4
5
  export type EventMap = Record<string, SocketEvent>;
5
6
  export type Payload<T extends EventMap, K extends keyof T> = z.infer<T[K]['message']>;
6
7
  export type ServerEnvelope<T extends EventMap, K extends keyof T & string> = {
@@ -16,7 +17,7 @@ export type ClientCtx = {
16
17
  nsp?: string;
17
18
  socketId?: string;
18
19
  rooms?: string[];
19
- socket?: Socket;
20
+ socket?: MaybeSocket;
20
21
  reply?: (data?: unknown) => void;
21
22
  };
22
23
  export type ClientStatsSnapshot = {
@@ -32,18 +33,6 @@ export type ClientStatsSnapshot = {
32
33
  }[];
33
34
  };
34
35
  type NoInfer<T> = [T][T extends any ? 0 : never];
35
- /**
36
- * Merged/logically grouped debug events.
37
- *
38
- * Buckets:
39
- * - connection: connect, reconnect, disconnect, connect_error
40
- * - register: register, unregister
41
- * - pingpong: ping_emit, pong_recv
42
- * - room: join, leave
43
- * - emit
44
- * - receive
45
- * - stats
46
- */
47
36
  export type SocketClientDebugEvent<K extends string = string> = {
48
37
  type: 'connection';
49
38
  phase: 'connect' | 'reconnect' | 'disconnect' | 'connect_error';
@@ -98,7 +87,7 @@ export type HeartbeatClientOptions<Ping extends ZodType, Pong extends ZodType> =
98
87
  pingSchema: Ping;
99
88
  /** Produce the ping payload on each tick. */
100
89
  makePingPayload: (ctx: {
101
- socket: Socket;
90
+ socket: MaybeSocket;
102
91
  }) => NoInfer<z.infer<Ping>>;
103
92
  /** Optional validation of the pong payload you receive. */
104
93
  pongSchema?: Pong;
@@ -106,12 +95,12 @@ export type HeartbeatClientOptions<Ping extends ZodType, Pong extends ZodType> =
106
95
  onPong?: (args: {
107
96
  latencyMs: number;
108
97
  payload?: NoInfer<z.infer<Pong>>;
109
- socket: Socket;
98
+ socket: MaybeSocket;
110
99
  }) => void;
111
100
  };
112
101
  export type SocketClientOptions<Ping extends ZodType, Pong extends ZodType, T extends EventMap = EventMap> = {
113
- /** Inject an existing socket.io-client Socket. Required. */
114
- socket: Socket;
102
+ /** Inject an existing socket.io-client Socket. Can be null while bootstrapping. */
103
+ socket: MaybeSocket;
115
104
  roomJoinEvent?: string;
116
105
  roomLeaveEvent?: string;
117
106
  environment?: 'development' | 'production';
@@ -120,7 +109,7 @@ export type SocketClientOptions<Ping extends ZodType, Pong extends ZodType, T ex
120
109
  heartbeat: HeartbeatClientOptions<Ping, Pong>;
121
110
  };
122
111
  export declare class SocketClient<Ping extends ZodType, Pong extends ZodType, T extends EventMap> {
123
- readonly socket: Socket;
112
+ readonly socket: MaybeSocket;
124
113
  private readonly events;
125
114
  private readonly roomJoinEvent;
126
115
  private readonly roomLeaveEvent;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emeryld/rrroutes-client",
3
- "version": "2.0.7",
3
+ "version": "2.0.9",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",