@emeryld/rrroutes-client 2.0.5 → 2.0.7

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
@@ -32,12 +32,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
32
32
  var index_exports = {};
33
33
  __export(index_exports, {
34
34
  SocketClient: () => SocketClient,
35
- SocketProvider: () => SocketProvider,
36
35
  buildSocketProvider: () => buildSocketProvider,
37
36
  createRouteClient: () => createRouteClient,
38
- defaultFetcher: () => defaultFetcher,
39
- useSocketClient: () => useSocketClient,
40
- useSocketConnection: () => useSocketConnection
37
+ defaultFetcher: () => defaultFetcher
41
38
  });
42
39
  module.exports = __toCommonJS(index_exports);
43
40
 
@@ -469,41 +466,67 @@ function toFormData(body) {
469
466
  var React = __toESM(require("react"), 1);
470
467
  var import_jsx_runtime = require("react/jsx-runtime");
471
468
  var SocketCtx = React.createContext(null);
469
+ function dbg(dbgOpts, e) {
470
+ if (!dbgOpts?.logger) return;
471
+ if (!dbgOpts[e.type]) return;
472
+ dbgOpts.logger(e);
473
+ }
472
474
  function buildSocketProvider(args) {
473
475
  const { events, options: baseOptions } = args;
474
476
  return {
475
- SocketProvider: (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SocketProvider, { events, baseOptions, ...props }),
477
+ SocketProvider: (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
478
+ SocketProvider,
479
+ {
480
+ events,
481
+ baseOptions,
482
+ ...props
483
+ }
484
+ ),
476
485
  useSocketClient: () => useSocketClient(),
477
486
  useSocketConnection: (p) => useSocketConnection(p)
478
487
  };
479
488
  }
480
489
  function SocketProvider(props) {
481
- const { events, baseOptions, children } = props;
490
+ const { events, baseOptions, children, fallback, providerDebug } = props;
482
491
  const [socket, setSocket] = React.useState(
483
492
  "socket" in props ? props.socket : null
484
493
  );
485
494
  React.useEffect(() => {
486
495
  let cancelled = false;
487
496
  if (!socket && "getSocket" in props) {
497
+ dbg(providerDebug, { type: "resolve", phase: "start" });
488
498
  Promise.resolve(props.getSocket()).then((s) => {
489
- if (!cancelled) setSocket(s);
490
- }).catch(() => {
499
+ if (cancelled) return;
500
+ setSocket(s);
501
+ dbg(providerDebug, { type: "resolve", phase: "ok" });
502
+ }).catch((err) => {
503
+ if (cancelled) return;
504
+ dbg(providerDebug, { type: "resolve", phase: "error", err: String(err) });
491
505
  });
492
506
  }
493
507
  return () => {
494
508
  cancelled = true;
495
509
  };
496
- }, [socket, "getSocket" in props ? props.getSocket : null]);
510
+ }, [socket]);
497
511
  const client = React.useMemo(() => {
498
512
  if (!socket) return null;
499
- return new SocketClient(events, { ...baseOptions, socket });
500
- }, [events, baseOptions, socket]);
513
+ const c = new SocketClient(events, { ...baseOptions, socket });
514
+ dbg(providerDebug, { type: "client", phase: "ready" });
515
+ return c;
516
+ }, [events, baseOptions, socket, providerDebug]);
501
517
  React.useEffect(() => {
502
518
  return () => {
503
- client?.destroy();
519
+ if (client) {
520
+ client.destroy();
521
+ dbg(providerDebug, { type: "client", phase: "destroy" });
522
+ }
504
523
  };
505
- }, [client]);
506
- if (!client) return null;
524
+ }, [client, providerDebug]);
525
+ if (!client) {
526
+ dbg(providerDebug, { type: "render", phase: "waiting_for_socket" });
527
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: fallback ?? children });
528
+ }
529
+ dbg(providerDebug, { type: "render", phase: "provide" });
507
530
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SocketCtx.Provider, { value: client, children });
508
531
  }
509
532
  function useSocketClient() {
@@ -821,11 +844,8 @@ var SocketClient = class {
821
844
  // Annotate the CommonJS export names for ESM import in node:
822
845
  0 && (module.exports = {
823
846
  SocketClient,
824
- SocketProvider,
825
847
  buildSocketProvider,
826
848
  createRouteClient,
827
- defaultFetcher,
828
- useSocketClient,
829
- useSocketConnection
849
+ defaultFetcher
830
850
  });
831
851
  //# sourceMappingURL=index.cjs.map
@@ -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\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 } & ProviderRuntimeSocket>;\n\nconst SocketCtx = React.createContext<SocketClient<ZodType, ZodType, any> | null>(null);\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: (props: React.PropsWithChildren<ProviderRuntimeSocket>) => (\n <SocketProvider<Ping, Pong, T> events={events} baseOptions={baseOptions} {...props} />\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 } = 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 Promise.resolve(props.getSocket())\n .then((s) => {\n if (!cancelled) setSocket(s);\n })\n .catch(() => {\n // consumer handles failures externally\n });\n }\n\n return () => {\n cancelled = true;\n };\n }, [socket, 'getSocket' in props ? props.getSocket : null]);\n\n const client = React.useMemo(() => {\n if (!socket) return null;\n return new SocketClient(events, { ...baseOptions, socket });\n }, [events, baseOptions, socket]);\n\n React.useEffect(() => {\n return () => {\n client?.destroy();\n };\n }, [client]);\n\n if (!client) return null;\n\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\nexport { SocketProvider, useSocketClient, useSocketConnection };\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/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":"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","names":["useEndpoint"]}
package/dist/index.mjs CHANGED
@@ -434,43 +434,69 @@ function toFormData(body) {
434
434
 
435
435
  // src/sockets/socket.client.context.tsx
436
436
  import * as React from "react";
437
- import { jsx } from "react/jsx-runtime";
437
+ import { Fragment, jsx } from "react/jsx-runtime";
438
438
  var SocketCtx = React.createContext(null);
439
+ function dbg(dbgOpts, e) {
440
+ if (!dbgOpts?.logger) return;
441
+ if (!dbgOpts[e.type]) return;
442
+ dbgOpts.logger(e);
443
+ }
439
444
  function buildSocketProvider(args) {
440
445
  const { events, options: baseOptions } = args;
441
446
  return {
442
- SocketProvider: (props) => /* @__PURE__ */ jsx(SocketProvider, { events, baseOptions, ...props }),
447
+ SocketProvider: (props) => /* @__PURE__ */ jsx(
448
+ SocketProvider,
449
+ {
450
+ events,
451
+ baseOptions,
452
+ ...props
453
+ }
454
+ ),
443
455
  useSocketClient: () => useSocketClient(),
444
456
  useSocketConnection: (p) => useSocketConnection(p)
445
457
  };
446
458
  }
447
459
  function SocketProvider(props) {
448
- const { events, baseOptions, children } = props;
460
+ const { events, baseOptions, children, fallback, providerDebug } = props;
449
461
  const [socket, setSocket] = React.useState(
450
462
  "socket" in props ? props.socket : null
451
463
  );
452
464
  React.useEffect(() => {
453
465
  let cancelled = false;
454
466
  if (!socket && "getSocket" in props) {
467
+ dbg(providerDebug, { type: "resolve", phase: "start" });
455
468
  Promise.resolve(props.getSocket()).then((s) => {
456
- if (!cancelled) setSocket(s);
457
- }).catch(() => {
469
+ if (cancelled) return;
470
+ setSocket(s);
471
+ dbg(providerDebug, { type: "resolve", phase: "ok" });
472
+ }).catch((err) => {
473
+ if (cancelled) return;
474
+ dbg(providerDebug, { type: "resolve", phase: "error", err: String(err) });
458
475
  });
459
476
  }
460
477
  return () => {
461
478
  cancelled = true;
462
479
  };
463
- }, [socket, "getSocket" in props ? props.getSocket : null]);
480
+ }, [socket]);
464
481
  const client = React.useMemo(() => {
465
482
  if (!socket) return null;
466
- return new SocketClient(events, { ...baseOptions, socket });
467
- }, [events, baseOptions, socket]);
483
+ const c = new SocketClient(events, { ...baseOptions, socket });
484
+ dbg(providerDebug, { type: "client", phase: "ready" });
485
+ return c;
486
+ }, [events, baseOptions, socket, providerDebug]);
468
487
  React.useEffect(() => {
469
488
  return () => {
470
- client?.destroy();
489
+ if (client) {
490
+ client.destroy();
491
+ dbg(providerDebug, { type: "client", phase: "destroy" });
492
+ }
471
493
  };
472
- }, [client]);
473
- if (!client) return null;
494
+ }, [client, providerDebug]);
495
+ if (!client) {
496
+ dbg(providerDebug, { type: "render", phase: "waiting_for_socket" });
497
+ return /* @__PURE__ */ jsx(Fragment, { children: fallback ?? children });
498
+ }
499
+ dbg(providerDebug, { type: "render", phase: "provide" });
474
500
  return /* @__PURE__ */ jsx(SocketCtx.Provider, { value: client, children });
475
501
  }
476
502
  function useSocketClient() {
@@ -787,11 +813,8 @@ var SocketClient = class {
787
813
  };
788
814
  export {
789
815
  SocketClient,
790
- SocketProvider,
791
816
  buildSocketProvider,
792
817
  createRouteClient,
793
- defaultFetcher,
794
- useSocketClient,
795
- useSocketConnection
818
+ defaultFetcher
796
819
  };
797
820
  //# sourceMappingURL=index.mjs.map
@@ -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\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 } & ProviderRuntimeSocket>;\n\nconst SocketCtx = React.createContext<SocketClient<ZodType, ZodType, any> | null>(null);\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: (props: React.PropsWithChildren<ProviderRuntimeSocket>) => (\n <SocketProvider<Ping, Pong, T> events={events} baseOptions={baseOptions} {...props} />\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 } = 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 Promise.resolve(props.getSocket())\n .then((s) => {\n if (!cancelled) setSocket(s);\n })\n .catch(() => {\n // consumer handles failures externally\n });\n }\n\n return () => {\n cancelled = true;\n };\n }, [socket, 'getSocket' in props ? props.getSocket : null]);\n\n const client = React.useMemo(() => {\n if (!socket) return null;\n return new SocketClient(events, { ...baseOptions, socket });\n }, [events, baseOptions, socket]);\n\n React.useEffect(() => {\n return () => {\n client?.destroy();\n };\n }, [client]);\n\n if (!client) return null;\n\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\nexport { SocketProvider, useSocketClient, useSocketConnection };\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","// 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"]}
@@ -2,26 +2,42 @@ import * as React from 'react';
2
2
  import { Socket } from 'socket.io-client';
3
3
  import { SocketClient, SocketClientOptions, EventMap, ClientCtx, Payload, ServerEnvelope } from './socket.client.index';
4
4
  import { ZodType } from 'zod';
5
+ /** === Provider-side debug === */
6
+ export type SocketProviderDebugEvent = {
7
+ type: 'resolve';
8
+ phase: 'start' | 'ok' | 'error';
9
+ err?: string;
10
+ } | {
11
+ type: 'client';
12
+ phase: 'ready' | 'destroy';
13
+ } | {
14
+ type: 'render';
15
+ phase: 'waiting_for_socket' | 'provide';
16
+ };
17
+ export type SocketProviderDebugOptions = {
18
+ verbose?: boolean;
19
+ logger?: (e: SocketProviderDebugEvent) => void;
20
+ } & {
21
+ [P in SocketProviderDebugEvent['type']]?: boolean;
22
+ };
23
+ /** === Types for runtime socket injection === */
5
24
  type BaseOptions<Ping extends ZodType, Pong extends ZodType, T extends EventMap> = Omit<SocketClientOptions<Ping, Pong, T>, 'socket'>;
6
25
  type ProviderRuntimeSocket = {
7
26
  socket: Socket;
8
27
  } | {
9
28
  getSocket: () => Socket | Promise<Socket>;
10
29
  };
11
- type SocketProviderProps<Ping extends ZodType, Pong extends ZodType, T extends EventMap> = React.PropsWithChildren<{
12
- events: T;
13
- baseOptions: BaseOptions<Ping, Pong, T>;
14
- } & ProviderRuntimeSocket>;
15
30
  export declare function buildSocketProvider<Ping extends ZodType, Pong extends ZodType, T extends EventMap>(args: {
16
31
  events: T;
17
32
  options: BaseOptions<Ping, Pong, T>;
18
33
  }): {
19
- SocketProvider: (props: React.PropsWithChildren<ProviderRuntimeSocket>) => import("react/jsx-runtime").JSX.Element;
34
+ SocketProvider: (props: React.PropsWithChildren<ProviderRuntimeSocket & {
35
+ fallback?: React.ReactNode;
36
+ providerDebug?: SocketProviderDebugOptions;
37
+ }>) => import("react/jsx-runtime").JSX.Element;
20
38
  useSocketClient: () => SocketClient<Ping, Pong, T>;
21
39
  useSocketConnection: <K extends keyof T & string>(p: Parameters<typeof useSocketConnection<T, K>>[0]) => void;
22
40
  };
23
- declare function SocketProvider<Ping extends ZodType, Pong extends ZodType, T extends EventMap>(props: SocketProviderProps<Ping, Pong, T>): import("react/jsx-runtime").JSX.Element | null;
24
- declare function useSocketClient<Ping extends ZodType, Pong extends ZodType, T extends EventMap>(): SocketClient<Ping, Pong, T>;
25
41
  type Rooms = string[] | string | undefined;
26
42
  export type UseSocketConnectionArgs<T extends EventMap, K extends keyof T & string> = {
27
43
  event: K;
@@ -36,4 +52,4 @@ export type UseSocketConnectionArgs<T extends EventMap, K extends keyof T & stri
36
52
  deps?: React.DependencyList;
37
53
  };
38
54
  declare function useSocketConnection<T extends EventMap, K extends keyof T & string>(args: UseSocketConnectionArgs<T, K>): void;
39
- export { SocketProvider, useSocketClient, useSocketConnection };
55
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emeryld/rrroutes-client",
3
- "version": "2.0.5",
3
+ "version": "2.0.7",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",