@luckystack/sync 0.9.2 → 0.10.1
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/CHANGELOG.md +16 -1
- package/CLAUDE.md +6 -3
- package/dist/chunk-AJ36D2PQ.js +35 -0
- package/dist/chunk-AJ36D2PQ.js.map +1 -0
- package/dist/client.d.ts +1 -0
- package/dist/client.js +5 -0
- package/dist/client.js.map +1 -1
- package/dist/errorCodes-B8GoTenr.d.ts +5 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +73 -16
- package/dist/index.js.map +1 -1
- package/docs/error-states.md +9 -4
- package/docs/room-fanout.md +48 -24
- package/docs/server-vs-client-handlers.md +8 -6
- package/package.json +3 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/handleSyncRequest.ts","../src/_shared/streamEmitters.ts","../src/_shared/logFlags.ts","../src/_shared/redactToken.ts","../src/_shared/errorBuilders.ts","../src/_shared/clientFanout.ts","../src/_shared/validationMode.ts","../src/_shared/receiverAuth.ts","../src/handleHttpSyncRequest.ts","../src/streamThrottle.ts"],"sourcesContent":["//? SYNC-20 — targeted disables replacing the former blanket `/* eslint-disable */`\n//? (which masked findings across this security-critical transport file). These\n//? mirror the `@luckystack/api` handlers: template expressions interpolate the\n//? route name / receiver (already validated strings); nullish-coalescing is\n//? deliberately avoided where `||`'s empty-string fallthrough is intended; the\n//? `?.` chains on runtime-map values read as \"unnecessary\" to the typed view but\n//? are real runtime guards. (The former `user!` assertion at the `validateRequest`\n//? call site was removed once core made `validateRequest` null-safe — CORE-06.)\n/* eslint-disable @typescript-eslint/no-unnecessary-condition, @typescript-eslint/restrict-template-expressions, @typescript-eslint/prefer-nullish-coalescing, @typescript-eslint/no-non-null-assertion, eqeqeq */\nimport { randomUUID } from \"node:crypto\";\nimport type { syncMessage, PostSyncFanoutPayload, PostSyncExecutePayload, BaseSessionLayout as SessionLayout, ErrorFormatter } from \"@luckystack/core\";\nimport { Socket } from \"socket.io\";\nimport {\n readSession,\n getProjectConfig,\n getRuntimeSyncMaps,\n validateRequest,\n extractTokenFromSocket,\n formatRoomName,\n getIoInstance,\n tryCatch,\n parseTransportRouteName,\n checkRateLimit,\n buildSyncProgressEventName,\n buildSyncResponseEventName,\n socketEventNames,\n dispatchHook,\n validateInputByType,\n getLogger,\n resolveClientIp,\n isLoopbackIp,\n extractLanguageFromHeader,\n normalizeErrorResponse,\n runWithErrorTrackerIdentityScope,\n setCurrentErrorTrackerIdentity,\n registerSyncAbortController,\n unregisterSyncAbortController,\n isProductionRuntime,\n} from \"@luckystack/core\";\nimport { buildSyncStreamEmitters } from './_shared/streamEmitters';\n\nimport type {\n RuntimeErrorResponse,\n RuntimeSyncServerEntry,\n RuntimeSyncClientHandler,\n SyncErrorEnvelopeInput,\n} from './_shared/syncTypes';\nimport { shouldLogDev, shouldLogStream } from './_shared/logFlags';\nimport { buildFormattedError } from './_shared/errorBuilders';\nimport { processClientSyncForRecipient } from './_shared/clientFanout';\nimport { resolveSyncValidationMode } from './_shared/validationMode';\nimport { authorizeSyncReceiver } from './_shared/receiverAuth';\n\ntype SyncErrorBuilder = (args: {\n response: SyncErrorEnvelopeInput;\n preferred?: string | null;\n userLanguage?: string | null;\n }) => RuntimeErrorResponse;\n\n//? Returns true when both buckets passed; false when one rejected and the\n//? caller should bail. The caller still owns the socket emit + responseIndex\n//? wiring because the existing code structure interleaves emit logic with\n//? other guard returns.\nconst applySyncRateLimits = async ({\n resolvedName,\n socket,\n user,\n responseIndex,\n buildSyncError,\n preferredLocale,\n routeLimit,\n}: {\n resolvedName: string;\n token: string | null;\n socket: Socket;\n user: SessionLayout | null;\n responseIndex: number | undefined;\n buildSyncError: SyncErrorBuilder;\n preferredLocale: string | null | undefined;\n //? SYNC-11 — per-route `rateLimit` export. `undefined` ⇒ fall back to the\n //? global `defaultApiLimit`; a number overrides the per-requester bucket;\n //? `false` disables it (the global per-IP bucket below still applies).\n routeLimit: number | false | undefined;\n}): Promise<boolean> => {\n const config = getProjectConfig();\n //? Resolve the real client IP once for both buckets. Default\n //? `http.trustProxy: false` returns `socket.handshake.address` verbatim\n //? (only IPv4-mapped IPv6 canonicalized), preserving historical keys; a\n //? trusted proxy honors X-Forwarded-For / X-Real-IP.\n const resolvedIp = resolveClientIp({\n rawAddress: socket.handshake.address,\n headers: socket.handshake.headers,\n trustProxy: config.http.trustProxy,\n trustedProxyHopCount: config.http.trustedProxyHopCount,\n });\n const defaultApiLimit = routeLimit === undefined ? config.rateLimiting.defaultApiLimit : routeLimit;\n if (defaultApiLimit !== false && defaultApiLimit > 0) {\n //? H-TWIN with the api transport: key the per-route bucket on the VALIDATED\n //? user.id (never the token). A token is per-session, so token-keying let an\n //? authenticated abuser reset the bucket by re-logging-in (new token = fresh\n //? counter); user.id ties all of a user's sessions to one bucket. Anonymous\n //? callers fall back to the resolved IP.\n const identityCb = config.rateLimiting.identity;\n const customIdentity = identityCb?.({ routeName: resolvedName, userId: user?.id ?? null, ip: resolvedIp, transport: 'socket' }) ?? null;\n const requesterIdentity = customIdentity?.id ?? user?.id ?? resolvedIp;\n const keyPrefix = customIdentity?.scope ?? (user?.id ? 'user' : 'ip');\n const rateLimitKey = `${keyPrefix}:${requesterIdentity}:sync:${resolvedName}`;\n const { allowed, resetIn } = await checkRateLimit({\n key: rateLimitKey,\n limit: defaultApiLimit,\n windowMs: config.rateLimiting.windowMs,\n });\n if (!allowed) {\n void dispatchHook('rateLimitExceeded', {\n //? Parity with the API handler: an anonymous per-route bucket is IP-keyed,\n //? so the scope is `ip` (with `route` still set to mark it a per-route\n //? bucket vs the global `:sync:all` IP bucket), never `route`.\n scope: user?.id ? 'user' : 'ip',\n key: rateLimitKey,\n limit: defaultApiLimit,\n windowMs: config.rateLimiting.windowMs,\n count: defaultApiLimit + 1,\n route: resolvedName,\n userId: user?.id,\n ip: user?.id ? undefined : resolvedIp,\n });\n if (typeof responseIndex === 'number') {\n socket.emit(buildSyncResponseEventName(responseIndex), buildSyncError({\n response: {\n status: 'error',\n errorCode: 'sync.rateLimitExceeded',\n errorParams: [{ key: 'seconds', value: resetIn }],\n httpStatus: 429,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }));\n }\n return false;\n }\n }\n\n const defaultIpLimit = config.rateLimiting.defaultIpLimit;\n //? SYNC-O11 — skip the global per-IP abuse limit for loopback traffic in\n //? non-production when `skipLoopbackInDev` is enabled (parity with the HTTP\n //? sync transport and the API socket handler). Only the cross-route `:sync:all`\n //? IP bucket is skipped; per-route limits above still apply. Pass the raw\n //? `resolvedIp` (not UNKNOWN_CLIENT_IP) so only real loopback addresses qualify.\n const requesterIsLoopback = config.rateLimiting.skipLoopbackInDev\n && !isProductionRuntime()\n && isLoopbackIp(resolvedIp);\n if (!requesterIsLoopback && defaultIpLimit !== false && defaultIpLimit > 0) {\n const requesterIp = resolvedIp;\n const ipKey = `ip:${requesterIp}:sync:all`;\n const { allowed, resetIn } = await checkRateLimit({\n key: ipKey,\n limit: defaultIpLimit,\n windowMs: config.rateLimiting.windowMs,\n });\n if (!allowed) {\n void dispatchHook('rateLimitExceeded', {\n scope: 'ip',\n key: ipKey,\n limit: defaultIpLimit,\n windowMs: config.rateLimiting.windowMs,\n count: defaultIpLimit + 1,\n ip: requesterIp,\n });\n if (typeof responseIndex === 'number') {\n socket.emit(buildSyncResponseEventName(responseIndex), buildSyncError({\n response: {\n status: 'error',\n errorCode: 'sync.rateLimitExceeded',\n errorParams: [{ key: 'seconds', value: resetIn }],\n httpStatus: 429,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }));\n }\n return false;\n }\n }\n\n return true;\n};\n\n// ─── Private stage helpers ────────────────────────────────────────────────────\n\n//? Centralized error emitter — replaces the ~12 scattered\n//? `typeof responseIndex == 'number' && socket.emit(...)` patterns.\n//? Returns `undefined` so callers can `return rejectSync(...)` from a `void` fn.\nfunction rejectSync({\n socket,\n responseIndex,\n buildSyncError,\n response,\n preferred,\n userLanguage,\n}: {\n socket: Socket;\n responseIndex: number | undefined;\n buildSyncError: SyncErrorBuilder;\n response: SyncErrorEnvelopeInput;\n preferred?: string | null;\n userLanguage?: string | null;\n}): void {\n if (typeof responseIndex === 'number') {\n socket.emit(buildSyncResponseEventName(responseIndex), buildSyncError({\n response,\n preferred,\n userLanguage,\n }));\n }\n}\n\n//? Stage 1 — validates that `msg` is a plain object before any field access.\n//? Emits directly on `socketEventNames.sync` (no `responseIndex` yet) and\n//? returns false when the message shape is invalid.\nfunction validateSyncMessage({\n msg,\n socket,\n preferredLocale,\n}: {\n msg: unknown;\n socket: Socket;\n preferredLocale: string | null;\n}): boolean {\n //? `typeof null === 'object'` and arrays are objects too, so the bare\n //? `typeof != 'object'` guard let a `null`/array payload through to the field\n //? access below (`const { responseIndex } = msg`), throwing before the top-level\n //? tryCatch → unhandledRejection → process kill. Any connected socket could\n //? trigger it pre-auth via `socket.emit('sync', null)` (remote DoS). Reject\n //? non-plain-object payloads here, matching this guard's documented contract.\n if (typeof msg !== 'object' || msg === null || Array.isArray(msg)) {\n if (shouldLogDev()) {\n getLogger().warn('sync: socket message was not a json object');\n }\n const normalized = normalizeErrorResponse({\n response: { status: 'error', errorCode: 'sync.invalidRequest' },\n preferredLocale,\n });\n socket.emit(socketEventNames.sync, {\n status: normalized.status,\n message: normalized.message,\n errorCode: normalized.errorCode,\n errorParams: normalized.errorParams,\n httpStatus: normalized.httpStatus,\n });\n return false;\n }\n return true;\n}\n\n//? Stage 2 — parses and validates the structured fields from the message.\n//? Returns a `{ ok: true, ... }` discriminated union on success so the caller\n//? can narrow the fields without re-casting. On validation failure it emits the\n//? appropriate error and returns `{ ok: false }`.\nfunction parseSyncFields({\n msg,\n socket,\n responseIndex,\n preferredLocale,\n buildSyncError,\n}: {\n msg: syncMessage;\n socket: Socket;\n responseIndex: number | undefined;\n preferredLocale: string | null;\n buildSyncError: SyncErrorBuilder;\n}):\n | { ok: false }\n | {\n ok: true;\n name: string;\n normalizedData: Record<string, unknown>;\n cb: string;\n receiver: string;\n ignoreSelf: boolean | undefined;\n resolvedName: string;\n }\n{\n const { name, data, cb, receiver: rawReceiver, ignoreSelf } = msg;\n const receiver = typeof rawReceiver === 'string' ? rawReceiver.trim() : '';\n\n //? Positive plain-object guard. `typeof data != 'object'` alone let an ARRAY\n //? `clientInput` through (`typeof [] === 'object'`), reaching a `_server`\n //? handler that assumes a plain object — and with `validation: 'relaxed'`\n //? there is no further runtime shape check. `!data` already excludes `null`.\n if (!name || !data || typeof name != 'string' || typeof data != 'object' || Array.isArray(data)) {\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.invalidRequest' }, preferred: preferredLocale });\n return { ok: false };\n }\n\n const parsedRoute = parseTransportRouteName({ value: name, prefix: 'sync' });\n if (parsedRoute.status === 'error') {\n rejectSync({\n socket, responseIndex, buildSyncError,\n response: {\n status: 'error',\n errorCode: 'routing.invalidServiceRouteName',\n errorParams: [{ key: 'name', value: name }],\n },\n preferred: preferredLocale,\n });\n return { ok: false };\n }\n\n const resolvedName = parsedRoute.normalizedFullName;\n\n if (!cb || typeof cb != 'string') {\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.invalidCallback' }, preferred: preferredLocale });\n return { ok: false };\n }\n\n if (!receiver) {\n if (shouldLogDev()) {\n getLogger().warn('sync: missing receiver / roomCode', { receiver });\n }\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.missingReceiver' }, preferred: preferredLocale });\n return { ok: false };\n }\n\n return {\n ok: true,\n name,\n normalizedData: data as Record<string, unknown>,\n cb,\n receiver,\n ignoreSelf: typeof ignoreSelf === 'boolean' ? ignoreSelf : undefined,\n resolvedName,\n };\n}\n\n//? Stage 3 — sets up the per-request AbortController, registers it in the\n//? cancel registry, arms the disconnect listener, and sends the `__cancelId`\n//? handshake frame. Returns the cleanup function and the abort controller so\n//? later stages can call `cleanupRequest()` or read `abortController.signal`.\nfunction setupAbortController({\n socket,\n responseIndex,\n}: {\n socket: Socket;\n responseIndex: number | undefined;\n}): {\n abortController: AbortController;\n abortKey: string;\n cleanupRequest: () => void;\n} {\n //? B1 / S13 — per-request AbortController. The controller drives three things:\n //? 1. Aborts when the client emits `syncCancel { cb: <cancelId> }`.\n //? 2. Aborts when the originator socket disconnects (listener below).\n //? 3. Gates further chunk emits via the signal handed to streamEmitters.\n //?\n //? S13 SECURITY: the registry key MUST NOT be the client-controlled callback\n //? string (`cb` = `${name}/${version}`). That value is REUSED across every\n //? concurrent request of the same route, so two in-flight `sync/chat/send/v1`\n //? calls would register under the identical `${socket.id}:${cb}` key — the\n //? second `Map.set` clobbered the first's controller, a `syncCancel` aborted\n //? the wrong request, and the first request's `unregister` deleted the\n //? second's entry (registry corruption). We now key on a SERVER-ISSUED,\n //? per-request unique `cancelId` and hand that id to the client via a\n //? handshake frame on the progress channel; the client cancels by echoing it\n //? back as `syncCancel { cb: cancelId }`. The wire field stays `cb` so the\n //? existing server-side cancel listener is unchanged — only its value is now\n //? a unique id instead of a reused callback name.\n const cancelId = randomUUID();\n const abortController = new AbortController();\n const abortKey = registerSyncAbortController(socket.id, cancelId, abortController);\n //? Hand the server-issued cancel id to the originator on the progress channel\n //? BEFORE any work runs, so an abort fired mid-flight (even on a non-streaming\n //? route) can target THIS exact request. The client filters this frame out of\n //? its `onStream` delivery by the reserved `__cancelId` marker key.\n if (typeof responseIndex === 'number') {\n socket.emit(buildSyncProgressEventName(responseIndex), { __cancelId: cancelId });\n }\n const onSocketDisconnect = () => { abortController.abort(); };\n socket.once(socketEventNames.disconnect, onSocketDisconnect);\n let cleanupDone = false;\n const cleanupRequest = () => {\n if (cleanupDone) return;\n cleanupDone = true;\n socket.off(socketEventNames.disconnect, onSocketDisconnect);\n unregisterSyncAbortController(abortKey);\n };\n return { abortController, abortKey, cleanupRequest };\n}\n\n//? Stage 4 — verifies the route map contains a valid `_server` file.\n//? A `_client`-only route is rejected as misconfigured (no auth gate).\n//? Returns false and emits the appropriate error when the route is absent.\nfunction checkRouteExists({\n syncObject,\n resolvedName,\n name,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n user,\n cleanupRequest,\n}: {\n syncObject: Record<string, unknown>;\n resolvedName: string;\n name: string;\n socket: Socket;\n responseIndex: number | undefined;\n buildSyncError: SyncErrorBuilder;\n preferredLocale: string | null;\n user: SessionLayout | null;\n cleanupRequest: () => void;\n}): boolean {\n if (!syncObject[`${resolvedName}_client`] && !syncObject[`${resolvedName}_server`]) {\n if (shouldLogDev()) {\n getLogger().warn(`sync: ${name} has no _client or _server file`, { sync: name });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.notFound' }, preferred: preferredLocale, userLanguage: user?.language });\n return false;\n }\n\n //? SYNC: reject a CLIENT-ONLY route (a `_client` file with no `_server`) as\n //? misconfigured. The `_server` file is the documented, MANDATORY gate that\n //? owns auth (`auth.login` / `additional`) and input validation; the entire\n //? auth+validate block below lives inside `if (serverSyncEntry)`. Without\n //? this guard a `_client`-only route would run receiver-auth + the `_client`\n //? fanout with fully attacker-controlled, UNVALIDATED input and NO login\n //? check — reachable by unauthenticated sockets. Treat it as a routing error.\n if (!syncObject[`${resolvedName}_server`]) {\n if (shouldLogDev()) {\n getLogger().warn(`sync: ${resolvedName} has a _client file but no required _server file`, { sync: resolvedName });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.notFound' }, preferred: preferredLocale, userLanguage: user?.language });\n return false;\n }\n\n return true;\n}\n\n//? Stage 5 — runs auth.login, auth.additional presence check, and\n//? `validateRequest`. Returns false and emits `auth.required` / the route's\n//? auth error when the request fails any check.\nfunction runSyncAuth({\n serverSyncEntry,\n user,\n resolvedName,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n cleanupRequest,\n}: {\n serverSyncEntry: RuntimeSyncServerEntry | undefined;\n user: SessionLayout | null;\n resolvedName: string;\n socket: Socket;\n responseIndex: number | undefined;\n buildSyncError: SyncErrorBuilder;\n preferredLocale: string | null;\n cleanupRequest: () => void;\n}): boolean {\n if (!serverSyncEntry) return true;\n\n const { auth } = serverSyncEntry;\n if (auth.login && !user?.id) {\n if (shouldLogDev()) {\n getLogger().warn(`sync: ${resolvedName} requires login`, { sync: resolvedName });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'auth.required' }, preferred: preferredLocale });\n return false;\n }\n\n //? SYNC-02 — guard the anonymous `additional`-only case. When a route\n //? declares `auth.additional` predicates but NOT `auth.login`, an\n //? unauthenticated socket reaches here with `user === null`. Passing\n //? `user!` into `validateRequest` would execute `condition.key in null`\n //? → a fatal `TypeError` that, because loadSocket invokes this handler as\n //? an un-`.catch()`'d `void` IIFE, becomes a process-killing\n //? unhandledRejection. Reject as `auth.required` BEFORE the call (a route\n //? gating on session fields legitimately requires a session).\n if (auth.additional && auth.additional.length > 0 && !user) {\n if (shouldLogDev()) {\n getLogger().warn(`sync: ${resolvedName} requires a session for additional auth`, { sync: resolvedName });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'auth.required' }, preferred: preferredLocale });\n return false;\n }\n\n //? CORE-06 / SYNC-02 — `validateRequest` is now null-safe: pass the real\n //? (possibly null) session instead of the former `user!` assertion. The\n //? anonymous-additional case is still rejected explicitly above with\n //? `auth.required`; core forbids any `additional[]` predicate when no\n //? session rather than throwing on `condition.key in null`.\n const validationResult = validateRequest({ auth, user });\n if (validationResult.status === 'error') {\n if (shouldLogDev()) {\n getLogger().warn(`sync: auth failed for ${resolvedName}`, { sync: resolvedName, errorCode: validationResult.errorCode });\n }\n cleanupRequest();\n rejectSync({\n socket, responseIndex, buildSyncError,\n response: {\n status: 'error',\n errorCode: validationResult.errorCode || 'auth.forbidden',\n errorParams: validationResult.errorParams,\n httpStatus: validationResult.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n return false;\n }\n\n return true;\n}\n\n//? Stage 6 — checks framework-level receiver authorization.\n//? Returns false and emits `sync.notRoomMember` / `sync.receiverNotAllowed`\n//? when the originator is not permitted to target the requested receiver.\nfunction runReceiverAuth({\n receiver,\n resolvedName,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n user,\n cleanupRequest,\n}: {\n receiver: string;\n resolvedName: string;\n socket: Socket;\n responseIndex: number | undefined;\n buildSyncError: SyncErrorBuilder;\n preferredLocale: string | null;\n user: SessionLayout | null;\n cleanupRequest: () => void;\n}): boolean {\n //? SYNC-07 — default receiver authorization. Reject a cluster-wide `'all'`\n //? broadcast when `sync.allowClientReceiverAll` is false, and (when\n //? `sync.requireRoomMembership` is true) a room the originator socket has not\n //? actually joined. Both flags default to today's permissive behavior, so a\n //? missing key changes nothing. Runs before `preSyncAuthorize` so the\n //? framework baseline is enforced first; the hook still applies finer policy.\n const syncConfig = getProjectConfig().sync;\n const receiverAuth = authorizeSyncReceiver({\n receiver,\n allowClientReceiverAll: syncConfig.allowClientReceiverAll,\n requireRoomMembership: syncConfig.requireRoomMembership,\n //? Sockets physically JOIN the FORMATTED room (loadSocket runs the room name\n //? through formatRoomName at join time), so membership must be tested against\n //? the SAME physical name the fanout fetch uses (see physicalReceiver below) —\n //? NOT the raw client `receiver`. Otherwise a non-identity\n //? registerRoomNameFormatter (multi-tenant) makes every joined member fail the\n //? check on the socket transport while HTTP still works.\n isMember: () =>\n socket.rooms.has(\n receiver === 'all' ? 'all' : formatRoomName(receiver, { purpose: 'broadcast', userId: user?.id ?? null }),\n ),\n });\n if (!receiverAuth.allowed) {\n if (shouldLogDev()) {\n getLogger().warn(`sync: receiver authorization failed for ${resolvedName}`, { sync: resolvedName, receiver, errorCode: receiverAuth.errorCode });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: receiverAuth.errorCode, httpStatus: 403 }, preferred: preferredLocale, userLanguage: user?.language });\n return false;\n }\n return true;\n}\n\n//? Stage 7 — runs `preSyncAuthorize` (custom policy hook) and fires\n//? `postSyncAuthorize` (observational). Returns false when the hook stops\n//? the request.\nasync function runPreAuthorizeHook({\n resolvedName,\n normalizedData,\n user,\n receiver,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n cleanupRequest,\n}: {\n resolvedName: string;\n normalizedData: Record<string, unknown>;\n user: SessionLayout | null;\n receiver: string;\n socket: Socket;\n responseIndex: number | undefined;\n buildSyncError: SyncErrorBuilder;\n preferredLocale: string | null;\n cleanupRequest: () => void;\n}): Promise<boolean> {\n //? Custom authorization hook. Fires after basic auth + AuthProps check\n //? and rate-limit pass. Consumers use this to enforce room-membership\n //? rules (\"user X may only emit sync to room Y\"), per-tenant policies,\n //? or audit trails. Stop with a specific errorCode to reject without\n //? revealing input shape.\n const preAuthorizeResult = await dispatchHook('preSyncAuthorize', {\n routeName: resolvedName,\n data: normalizedData,\n user,\n receiver,\n transport: 'socket',\n });\n if (preAuthorizeResult.stopped) {\n if (shouldLogDev()) {\n getLogger().warn(`sync: preSyncAuthorize stopped ${resolvedName}`, { sync: resolvedName, errorCode: preAuthorizeResult.signal.errorCode });\n }\n cleanupRequest();\n rejectSync({\n socket, responseIndex, buildSyncError,\n response: {\n status: 'error',\n errorCode: preAuthorizeResult.signal.errorCode,\n httpStatus: preAuthorizeResult.signal.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n return false;\n }\n\n //? Observational mirror of `preSyncAuthorize`. Fires after the request\n //? passes auth + custom policy; lets audit-log / metrics subscribers\n //? record successful authorizations without forking the dispatch path.\n //? Stop signals from handlers are ignored (this is post-decision).\n void dispatchHook('postSyncAuthorize', {\n routeName: resolvedName,\n data: normalizedData,\n user,\n receiver,\n transport: 'socket',\n });\n\n return true;\n}\n\n//? Stage 8 — validates input (when mode is strict) and runs the `_server`\n//? handler. Returns `{ ok: false }` on any failure (emitting the appropriate\n//? error on the way out) and `{ ok: true, serverOutput }` on success.\nasync function runSyncServerExecution({\n serverSyncEntry,\n resolvedName,\n normalizedData,\n user,\n receiver,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n cleanupRequest,\n functionsObject,\n emitServerSyncStream,\n emitBroadcastSyncStream,\n emitStreamToTokens,\n flushPressure,\n abortController,\n}: {\n serverSyncEntry: RuntimeSyncServerEntry | undefined;\n resolvedName: string;\n normalizedData: Record<string, unknown>;\n user: SessionLayout | null;\n receiver: string;\n socket: Socket;\n responseIndex: number | undefined;\n buildSyncError: SyncErrorBuilder;\n preferredLocale: string | null;\n cleanupRequest: () => void;\n functionsObject: Record<string, unknown>;\n emitServerSyncStream: ReturnType<typeof buildSyncStreamEmitters>['emitServerSyncStream'];\n emitBroadcastSyncStream: ReturnType<typeof buildSyncStreamEmitters>['emitBroadcastSyncStream'];\n emitStreamToTokens: ReturnType<typeof buildSyncStreamEmitters>['emitStreamToTokens'];\n flushPressure: ReturnType<typeof buildSyncStreamEmitters>['flushPressure'];\n abortController: AbortController;\n}): Promise<{ ok: false } | { ok: true; serverOutput: Record<string, unknown> }> {\n if (!serverSyncEntry) return { ok: true, serverOutput: {} };\n\n const { main: serverMain, inputType, inputTypeFilePath } = serverSyncEntry;\n\n //? EXT-04 — validation-stage hooks mirroring the API pipeline. `preSyncValidate`\n //? may stop before validation; `postSyncValidate` reports the outcome.\n const preValidateResult = await dispatchHook('preSyncValidate', {\n routeName: resolvedName,\n data: normalizedData,\n user,\n receiver,\n transport: 'socket',\n });\n if (preValidateResult.stopped) {\n cleanupRequest();\n rejectSync({\n socket, responseIndex, buildSyncError,\n response: {\n status: 'error',\n errorCode: preValidateResult.signal.errorCode,\n httpStatus: preValidateResult.signal.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n return { ok: false };\n }\n\n //? Per-route validation toggle (mirrors the API handler). `'relaxed'` or\n //? `{ input: 'skip' }` skips runtime input validation entirely — for routes\n //? whose payload shape can't be modelled in TS. Default `'strict'`.\n if (resolveSyncValidationMode(serverSyncEntry.validation) === 'strict') {\n const inputValidation = await validateInputByType({\n typeText: inputType,\n value: normalizedData,\n rootKey: 'clientInput',\n filePath: inputTypeFilePath,\n });\n void dispatchHook('postSyncValidate', {\n routeName: resolvedName,\n data: normalizedData,\n user,\n receiver,\n transport: 'socket',\n validation: inputValidation.status === 'error'\n ? { status: 'error', message: inputValidation.message }\n : { status: 'success' },\n });\n if (inputValidation.status === 'error') {\n //? SYNC-04 SECURITY: do NOT echo the raw validator message (e.g.\n //? \"clientInput.userId should be string\") back to the client — that lets\n //? an unauthenticated caller enumerate a route's input schema. The\n //? DETAILED message travels to the `postSyncValidate` hook above + the\n //? dev log below only; the client receives the generic code. Mirrors the\n //? API fix in `@luckystack/api`'s socketValidationStage.\n if (shouldLogDev()) {\n getLogger().warn(`sync: input validation failed for ${resolvedName}`, { sync: resolvedName, message: inputValidation.message });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.invalidInputType' }, preferred: preferredLocale, userLanguage: user?.language });\n return { ok: false };\n }\n } else {\n void dispatchHook('postSyncValidate', {\n routeName: resolvedName,\n data: normalizedData,\n user,\n receiver,\n transport: 'socket',\n validation: { status: 'success' },\n });\n }\n\n //? EXT-04 — execution-stage hooks mirroring the API pipeline. `preSyncExecute`\n //? may stop before the `_server` runs; the single `executePayload` reference is\n //? reused so `@luckystack/error-tracking` can pin spans via WeakMap, and\n //? `postSyncExecute` fires on BOTH the success AND failure paths (the error\n //? path was previously invisible to hook consumers).\n const executePayload: PostSyncExecutePayload = {\n routeName: resolvedName,\n data: normalizedData,\n user,\n receiver,\n transport: 'socket',\n result: undefined,\n error: null,\n durationMs: 0,\n };\n const preExecuteResult = await dispatchHook('preSyncExecute', executePayload);\n if (preExecuteResult.stopped) {\n cleanupRequest();\n rejectSync({\n socket, responseIndex, buildSyncError,\n response: {\n status: 'error',\n errorCode: preExecuteResult.signal.errorCode,\n httpStatus: preExecuteResult.signal.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n return { ok: false };\n }\n\n //? if the user has passed all the checks we call the preload sync function and return the result\n const executeStart = Date.now();\n const [serverSyncError, serverSyncResult] = await tryCatch(\n async () => await serverMain({\n clientInput: normalizedData,\n user,\n functions: functionsObject,\n roomCode: receiver,\n stream: emitServerSyncStream,\n broadcastStream: emitBroadcastSyncStream,\n streamTo: emitStreamToTokens,\n abortSignal: abortController.signal,\n flushPressure,\n }),\n undefined,\n {\n handler: 'handleSyncRequest',\n sync: resolvedName,\n stage: 'server',\n userId: user?.id,\n receiver,\n transport: 'socket',\n },\n );\n executePayload.result = serverSyncResult;\n executePayload.error = serverSyncError ?? null;\n executePayload.durationMs = Date.now() - executeStart;\n await dispatchHook('postSyncExecute', executePayload);\n\n if (serverSyncError) {\n if (shouldLogDev()) {\n getLogger().error(`sync: server execution failed for ${resolvedName}`, serverSyncError, { sync: resolvedName });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.serverExecutionFailed' }, preferred: preferredLocale, userLanguage: user?.language });\n return { ok: false };\n }\n\n if (serverSyncResult?.status == 'error') {\n const normalizedServerError = buildSyncError({\n response: serverSyncResult,\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n if (shouldLogDev()) {\n getLogger().warn(`sync: server returned error for ${resolvedName}`, { sync: resolvedName, message: normalizedServerError.message });\n }\n cleanupRequest();\n if (typeof responseIndex === 'number') {\n socket.emit(buildSyncResponseEventName(responseIndex), normalizedServerError);\n }\n return { ok: false };\n }\n\n if (serverSyncResult?.status !== 'success') {\n //? badReturn means it doesnt include a status key with the value 'success' || 'error'\n if (shouldLogDev()) {\n getLogger().warn(`sync: ${resolvedName}_server returned invalid response`, { sync: resolvedName });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.invalidServerResponse' }, preferred: preferredLocale, userLanguage: user?.language });\n return { ok: false };\n }\n\n return { ok: true, serverOutput: serverSyncResult };\n}\n\n//? Stage 9 — fetches the target socket list and runs the per-recipient fanout\n//? (preSyncFanout → ack originator → loop → postSyncFanout).\n//? Returns false when there are no recipients (already emitted an error).\nasync function runSyncFanout({\n ioInstance,\n receiver,\n resolvedName,\n normalizedData,\n serverOutput,\n user,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n cleanupRequest,\n ignoreSelf,\n token,\n syncObject,\n functionsObject,\n}: {\n ioInstance: ReturnType<typeof getIoInstance>;\n receiver: string;\n resolvedName: string;\n normalizedData: Record<string, unknown>;\n serverOutput: Record<string, unknown>;\n user: SessionLayout | null;\n socket: Socket;\n responseIndex: number | undefined;\n buildSyncError: SyncErrorBuilder;\n preferredLocale: string | null;\n cleanupRequest: () => void;\n ignoreSelf: boolean | undefined;\n token: string | null;\n cb: string;\n syncObject: Record<string, unknown>;\n functionsObject: Record<string, unknown>;\n}): Promise<boolean> {\n //? Cross-instance recipient list. `fetchSockets()` (via the Redis adapter)\n //? returns RemoteSocket objects spanning EVERY backend sharing the adapter —\n //? not just this process's room view — so a normal sync fan-out reaches room\n //? members connected to other instances. `remoteSocket.emit()` routes to the\n //? owning instance. (Per-sync Redis round-trip; see docs/ARCHITECTURE_MULTI_INSTANCE.md.)\n //? Route the receiver room through the core room-name formatter (PRESENCE-1)\n //? so a non-identity `registerRoomNameFormatter` targets the same physical room\n //? that sockets actually joined (which is already formatted at join time).\n const physicalReceiver = receiver === 'all' ? 'all' : formatRoomName(receiver, { purpose: 'broadcast', userId: user?.id ?? null });\n const sockets = physicalReceiver === 'all'\n ? await ioInstance!.fetchSockets()\n : await ioInstance!.in(physicalReceiver).fetchSockets();\n\n //? now we check if we found any sockets\n if (sockets.length === 0) {\n if (shouldLogDev()) {\n getLogger().warn('sync: no sockets found for receiver', { receiver, sync: resolvedName });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.noReceiversFound' }, preferred: preferredLocale, userLanguage: user?.language });\n return false;\n }\n\n //? Single payload reference reused by pre/post — span pinning in\n //? `@luckystack/error-tracking` uses WeakMap on this object. `recipientCount`\n //? is mutated in place after fanout completes.\n const fanoutPayload: PostSyncFanoutPayload = {\n routeName: resolvedName,\n data: normalizedData,\n user,\n receiver,\n serverOutput,\n transport: 'socket',\n recipientCount: 0,\n };\n const preFanoutResult = await dispatchHook('preSyncFanout', fanoutPayload);\n if (preFanoutResult.stopped) {\n cleanupRequest();\n rejectSync({\n socket, responseIndex, buildSyncError,\n response: {\n status: 'error',\n errorCode: preFanoutResult.signal.errorCode,\n httpStatus: preFanoutResult.signal.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n return false;\n }\n\n //? SYNC-O9 — ack the originator as soon as server execution + preSyncFanout\n //? pass, BEFORE the per-recipient _client loop runs. The serial loop can take\n //? O(recipients × _client latency) on a large `receiver: 'all'` fanout, which\n //? would trip the client's requestTimeoutMs and cause a false 504 for the\n //? originator even though the server side succeeded. Recipients still get their\n //? payloads — the loop continues after the ack.\n //? Note: we intentionally do NOT call cleanupRequest() here so the disconnect\n //? listener stays active and can still abort the in-flight fanout loop.\n //? `originatorAcked` (hoisted above tryCatch) gates the error-fallback so a\n //? later fanout throw does not emit a conflicting response after the success ack.\n let originatorAcked = false;\n if (typeof responseIndex === 'number') {\n socket.emit(buildSyncResponseEventName(responseIndex), {\n status: 'success',\n message: `sync ${resolvedName} success`,\n result: serverOutput,\n });\n originatorAcked = true;\n }\n\n //? here we loop over all the connected clients\n //? Yield to the event loop periodically so a giant `receiver: 'all'` fanout\n //? doesn't starve other requests. Tunables live in projectConfig.sync.\n const { fanoutYieldEvery, fanoutYieldMs } = getProjectConfig().sync;\n //? SYNC-16 — clamp to >= 1 so a misconfigured `fanoutYieldEvery: 0` doesn't\n //? produce `n % 0 === NaN` (never truthy) → the loop never yields and a giant\n //? `receiver: 'all'` fanout can starve the event loop.\n const yieldEvery = Math.max(1, fanoutYieldEvery);\n let recipientCount = 0;\n let tempCount = 1;\n for (const tempSocket of sockets) {\n tempCount++;\n if (tempCount % yieldEvery === 0) { await new Promise(resolve => setTimeout(resolve, fanoutYieldMs)); }\n\n //? check if they have a token stored in their cookie or session based on the settings\n const tempToken = extractTokenFromSocket(tempSocket);\n\n //? Symmetry with the HTTP handler: strict equality + a `token` guard so an\n //? anonymous (token-less) socket is never treated as \"self\" (null == null).\n if (ignoreSelf && typeof ignoreSelf === 'boolean' && token && token === tempToken) {\n continue;\n }\n\n //? SYNC-22 — per-recipient fanout hook. Fires ONCE per resolved recipient,\n //? before this socket receives anything, letting a consumer FILTER the\n //? fanout (block users, per-tenant visibility) without a `_client` file. A\n //? stop signal SKIPS just this recipient — the loop continues and the\n //? recipient is NOT counted as delivered. `recipientUserId` is left null on\n //? the hot path (resolving it would cost a session read per recipient); a\n //? handler that needs it can derive it from `recipientSocketId` / `receiver`.\n //? SYNC-O8 — per-recipient hook. A stop signal with no `overrideOutput`\n //? SKIPS this recipient (existing behaviour). A stop signal WITH\n //? `overrideOutput` sends the override in place of `serverOutput` so a\n //? consumer can redact PII without excluding the socket from the fanout.\n //? This allows fine-grained per-recipient redaction even when no `_client`\n //? file is present (which would otherwise broadcast the full serverOutput).\n const preRecipientResult = await dispatchHook('preSyncRecipient', {\n routeName: resolvedName,\n receiver,\n recipientSocketId: tempSocket.id,\n recipientUserId: null,\n serverOutput,\n });\n if (preRecipientResult.stopped && preRecipientResult.signal.overrideOutput === undefined) {\n continue;\n }\n\n //? Use the override output when the hook supplied one; fall back to the\n //? unredacted serverOutput for all other recipients.\n const effectiveServerOutput = preRecipientResult.stopped\n ? preRecipientResult.signal.overrideOutput\n : serverOutput;\n\n recipientCount++;\n\n if (syncObject[`${resolvedName}_client`]) {\n const clientSyncHandler = syncObject[`${resolvedName}_client`] as RuntimeSyncClientHandler;\n await processClientSyncForRecipient({\n tempSocket,\n tempToken,\n clientSyncHandler,\n data: normalizedData,\n functionsObject,\n serverOutput: effectiveServerOutput,\n receiver,\n resolvedName,\n //? Server-authoritative callback key (SYNC security): route recipient\n //? callbacks off the SERVER-resolved route, never the client-supplied\n //? `cb`. Otherwise a room co-member could send a legit `name` but a `cb`\n //? for a DIFFERENT route and fire other clients' handlers for that route\n //? (cross-route callback spoofing). The client `cb` stays only for the\n //? originator's own cancel handshake.\n callbackKey: resolvedName,\n transport: 'socket',\n handlerName: 'handleSyncRequest',\n logLabel: 'sync',\n shouldLogDev,\n shouldLogStream,\n buildSyncError,\n //? Socket transport prefers `x-language` over `accept-language` —\n //? preserved verbatim from the previous inlined error path.\n resolvePreferredLocale: (headers) =>\n extractLanguageFromHeader(headers['x-language'])\n || extractLanguageFromHeader(headers['accept-language']),\n sourceUserId: user?.id,\n });\n } else {\n //? No _client file — broadcast serverOutput (or the per-recipient\n //? override when the preSyncRecipient hook supplied one) to this socket.\n const result = {\n //? Server-authoritative cb (SYNC security): emit the SERVER-resolved\n //? route so a spoofed client `cb` can't route this payload to a different\n //? route's callbacks on recipients. Mirrors the _client-path callbackKey.\n cb: resolvedName,\n fullName: resolvedName,\n serverOutput: effectiveServerOutput,\n clientOutput: {},\n message: `${resolvedName} sync success`,\n status: 'success'\n };\n if (shouldLogDev()) {\n getLogger().debug(`sync: ${resolvedName} server-only success`, { result });\n }\n tempSocket.emit(socketEventNames.sync, result);\n }\n }\n\n fanoutPayload.recipientCount = recipientCount;\n await dispatchHook('postSyncFanout', fanoutPayload);\n cleanupRequest();\n\n return originatorAcked;\n}\n\n// export default async function handleSyncRequest({ name, clientData, user, serverOutput, roomCode }: syncMessage) {\n//? ET-02 — open a per-request error-tracker identity scope around the ENTIRE sync\n//? handler before any await that could interleave with another concurrent request\n//? (`readSession` below is such a boundary). The resolved session is written into\n//? the scope's ALS box the moment it resolves, so two concurrent syncs with\n//? different users can't cross-attribute captures. Each request gets its own box.\nexport default async function handleSyncRequest(args: {\n msg: syncMessage,\n socket: Socket,\n token: string | null,\n}): Promise<void> {\n await runWithErrorTrackerIdentityScope(() => handleSyncRequestInner(args));\n}\n\nasync function handleSyncRequestInner({ msg, socket, token }: {\n msg: syncMessage,\n socket: Socket,\n token: string | null,\n}) {\n\n const ioInstance = getIoInstance();\n if (!ioInstance) { return; }\n\n //? Resolve locale once up front for both the early plain-object guard and\n //? all subsequent error emits.\n const preferredLocale =\n extractLanguageFromHeader(socket.handshake.headers['x-language'])\n || extractLanguageFromHeader(socket.handshake.headers['accept-language']);\n\n // Stage 1 — validate raw message shape\n if (!validateSyncMessage({ msg, socket, preferredLocale })) return;\n\n const { responseIndex } = msg;\n\n //? EXT-02 — per-message socket interception seam (websocket counterpart to\n //? `preHttpRequest`). Fires before session lookup / route resolution / auth\n //? so a consumer can gate, throttle, or audit individual sync messages. A\n //? stop signal rejects the message: we emit a localized error envelope on the\n //? response channel (when the client supplied a `responseIndex`) and abort.\n const preMessageResult = await dispatchHook('preSocketMessage', {\n channel: 'sync',\n socketId: socket.id,\n ip: socket.handshake.address,\n authenticated: Boolean(token),\n routeName: typeof msg.name === 'string' ? msg.name : undefined,\n });\n if (preMessageResult.stopped) {\n return typeof responseIndex == 'number' && socket.emit(buildSyncResponseEventName(responseIndex), normalizeErrorResponse({\n response: {\n status: 'error',\n errorCode: preMessageResult.signal.errorCode,\n httpStatus: preMessageResult.signal.httpStatus,\n },\n preferredLocale,\n }));\n }\n\n //? Per-route formatter ref + resolved-name ref — both undefined until the\n //? sync entry is looked up. Pre-lookup errors (invalid message, unknown\n //? route) emit with global formatter only because there's no syncEntry yet.\n //? `let` (not `const`): each is declared here, captured by the `buildSyncError`\n //? closure below, and assigned only further down once the route/session resolves\n //? — so a `const` at declaration is impossible (TDZ in the closure). The\n //? flow-based `prefer-const` mis-reads the single later assignment as the sole\n //? init for the two `string | undefined` refs; disabled with that rationale.\n // eslint-disable-next-line prefer-const\n let currentRouteName: string | undefined;\n let currentPerRouteFormatter: ErrorFormatter | undefined;\n // eslint-disable-next-line prefer-const\n let currentUserId: string | undefined;\n\n const buildSyncError = ({\n response,\n preferred,\n userLanguage,\n }: {\n response: SyncErrorEnvelopeInput;\n preferred?: string | null;\n userLanguage?: string | null;\n }): RuntimeErrorResponse => buildFormattedError({\n response,\n preferred,\n userLanguage,\n routeName: currentRouteName,\n transport: 'socket',\n userId: currentUserId,\n perRouteFormatter: currentPerRouteFormatter,\n });\n\n // Stage 2 — parse and validate structured message fields\n const parsedFields = parseSyncFields({ msg, socket, responseIndex, preferredLocale, buildSyncError });\n if (!parsedFields.ok) return;\n\n const { name, normalizedData, cb, receiver, resolvedName } = parsedFields;\n currentRouteName = resolvedName;\n\n if (shouldLogDev()) {\n getLogger().debug(`sync: ${resolvedName} called`, { sync: resolvedName });\n }\n\n const user = await readSession(token);\n currentUserId = user?.id;\n //? ET-02 — bind the resolved session into the active per-request ALS identity\n //? box so every subsequent capture (server handler throw, `_client` fanout,\n //? hook subscriber) attributes to this user. Identity also still flows to the\n //? legacy global via the `preSyncAuthorize` hook subscriber; the ALS read wins\n //? at capture time.\n setCurrentErrorTrackerIdentity(user?.id ? { id: user.id, email: user.email ?? undefined, username: user.name ?? undefined } : null);\n const { syncObject, functionsObject } = await getRuntimeSyncMaps();\n\n // Stage 3 — set up AbortController + cleanup\n const { abortController, cleanupRequest } = setupAbortController({ socket, responseIndex });\n\n //? SYNC-O9 — tracks whether the originator's response channel has been\n //? settled (early-ack before the fanout loop). When true, the error-fallback\n //? must NOT emit a second response on that channel.\n let originatorAcked = false;\n\n //? SYNC-02 — top-level error envelope. The socket handler runs un-`.catch()`'d\n //? from loadSocket (`void (async () => …)()`), so ANY throw below — a\n //? `fetchSockets()` Redis-adapter timeout, a misbehaving `_server`/`_client`\n //? handler, a hook subscriber — would surface as a fatal unhandledRejection\n //? (process kill on modern Node). The HTTP twin already wraps its body the\n //? same way. On throw we run cleanup and emit `sync.serverExecutionFailed`.\n const [handlerError] = await tryCatch(async () => {\n\n // Stage 4 — verify route exists\n if (!checkRouteExists({ syncObject, resolvedName, name, socket, responseIndex, buildSyncError, preferredLocale, user, cleanupRequest })) return;\n\n const { emitServerSyncStream, emitBroadcastSyncStream, emitStreamToTokens, flushPressure } =\n buildSyncStreamEmitters({\n cb,\n receiver,\n userId: user?.id ?? null,\n resolvedName,\n logLabel: 'sync',\n signal: abortController.signal,\n originatorSocket: socket,\n emitOriginatorChunk: (payload) => {\n if (typeof responseIndex !== 'number') return;\n socket.emit(buildSyncProgressEventName(responseIndex), payload);\n },\n });\n\n //? Pipeline order: auth → rate-limit → validate → execute → respond.\n //? Auth runs first so unauthenticated probes can't consume rate-limit budget\n //? or learn input shape from `inputValidation.message`. Mirrors api handlers.\n const serverSyncEntry = syncObject[`${resolvedName}_server`] as RuntimeSyncServerEntry | undefined;\n currentPerRouteFormatter = serverSyncEntry?.errorFormatter;\n\n // Stage 5 — auth\n if (!runSyncAuth({ serverSyncEntry, user, resolvedName, socket, responseIndex, buildSyncError, preferredLocale, cleanupRequest })) return;\n\n // Stage 6 — receiver auth\n if (!runReceiverAuth({ receiver, resolvedName, socket, responseIndex, buildSyncError, preferredLocale, user, cleanupRequest })) return;\n\n //? SYNC-O4 — rate-limit runs BEFORE the consumer `preSyncAuthorize` hook so\n //? an unauthenticated (login:false) caller cannot trigger potentially-expensive\n //? DB/tenant lookups on every message with no throttle.\n const rateLimitOk = await applySyncRateLimits({\n resolvedName,\n token,\n socket,\n user,\n responseIndex,\n buildSyncError,\n preferredLocale,\n routeLimit: serverSyncEntry?.rateLimit,\n });\n if (!rateLimitOk) { cleanupRequest(); return; }\n\n // Stage 7 — pre/post authorize hooks\n if (!await runPreAuthorizeHook({ resolvedName, normalizedData, user, receiver, socket, responseIndex, buildSyncError, preferredLocale, cleanupRequest })) return;\n\n // Stage 8 — validate input + run server handler\n const executionResult = await runSyncServerExecution({\n serverSyncEntry,\n resolvedName,\n normalizedData,\n user,\n receiver,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n cleanupRequest,\n functionsObject,\n emitServerSyncStream,\n emitBroadcastSyncStream,\n emitStreamToTokens,\n flushPressure,\n abortController,\n });\n if (!executionResult.ok) return;\n\n const { serverOutput } = executionResult;\n\n //? from here on we can assume that we have either called a server sync and got a proper result of we didnt call a server sync\n\n // Stage 9 — fanout\n const fanoutAcked = await runSyncFanout({\n ioInstance,\n receiver,\n resolvedName,\n normalizedData,\n serverOutput,\n user,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n cleanupRequest,\n ignoreSelf: parsedFields.ignoreSelf,\n token,\n cb,\n syncObject,\n functionsObject,\n });\n if (typeof fanoutAcked === 'boolean') {\n originatorAcked = fanoutAcked || originatorAcked;\n }\n\n }, undefined, {\n handler: 'handleSyncRequest',\n sync: currentRouteName,\n stage: 'handler',\n userId: currentUserId,\n receiver,\n transport: 'socket',\n });\n if (handlerError) {\n if (shouldLogDev()) {\n getLogger().error(`sync: unhandled error for ${currentRouteName ?? msg.name}`, handlerError, { sync: currentRouteName });\n }\n cleanupRequest();\n //? Guard: if the originator was already acked (SYNC-O9 early ack), do not\n //? emit a conflicting error response — the success already settled the\n //? client's pending promise. Only log the fanout-phase error above.\n if (!originatorAcked) {\n return typeof responseIndex == 'number' && socket.emit(buildSyncResponseEventName(responseIndex), buildSyncError({\n response: { status: 'error', errorCode: 'sync.serverExecutionFailed' },\n preferred: preferredLocale,\n }));\n }\n }\n}\n","import {\n dispatchHook,\n formatRoomName,\n getIoInstance,\n getLogger,\n getProjectConfig,\n socketEventNames,\n} from '@luckystack/core';\nimport type { Socket } from 'socket.io';\nimport { shouldLogStream } from './logFlags';\nimport { redactTokens } from './redactToken';\n\n//? Chunk-index counters are intentionally per-request (built inside\n//? `buildSyncStreamEmitters`) so they are garbage-collected with the\n//? closure when the request ends. A module-level Map keyed on\n//? `routeName|recipient` would grow unbounded for the process lifetime\n//? because `bumpChunkIndex` only ever `set`s — there is no teardown\n//? hook that reliably fires per room. (SYNC-N4)\n\nexport type SyncStreamPayload = Record<string, unknown>;\n\n//? Optional helper passed to consumer handlers so an LLM/long stream can\n//? `await flushPressure()` between chunks. Resolves once the underlying\n//? Socket.io transport's pending write buffer drops below `thresholdBytes`\n//? (measured in packets, not bytes — engine.io exposes a writeBuffer of\n//? packet objects, not byte length, so we approximate via packet count).\n//? Fallback threshold (used only before config is registered) = 1 MB ≈ 1024\n//? packets at ~1KB each; the EFFECTIVE default is `sync.flushPressure.maxBufferedBytes`\n//? (5 MiB). Handlers opt in;\n//? omitting the call is fine for handlers that don't stream a lot.\nexport interface FlushPressureOptions {\n /**\n * Drain threshold in bytes. Used as a packet-count approximation —\n * we assume an average packet size of ~1024 bytes and resolve once the\n * engine.io writeBuffer length is below `thresholdBytes / 1024`.\n * When omitted, falls back to `projectConfig.sync.flushPressure.maxBufferedBytes`\n * (default 5 MiB as configured in the framework defaults).\n */\n thresholdBytes?: number;\n}\n\nexport type FlushPressure = (options?: FlushPressureOptions) => Promise<void>;\n\nexport interface SyncStreamEmitters {\n emitServerSyncStream: (payload?: SyncStreamPayload) => void;\n emitBroadcastSyncStream: (payload?: SyncStreamPayload) => void;\n emitStreamToTokens: (tokens: string | string[], payload?: SyncStreamPayload) => void;\n buildBroadcastFrame: (payload: SyncStreamPayload) => Record<string, unknown>;\n flushPressure: FlushPressure;\n}\n\n//? Fallback 1 MB threshold (per spec B2) — effective default is\n//? `sync.flushPressure.maxBufferedBytes` (5 MiB). Packet count = bytes / avg-packet-size.\nconst DEFAULT_THRESHOLD_BYTES = 1_048_576;\nconst AVG_PACKET_BYTES = 1024;\nconst POLL_INTERVAL_MS = 10;\n//? Cap sockets considered for worst-case pressure so a `receiver: 'all'`\n//? broadcast doesn't degrade to O(n). First 32 — see spec B2.\nconst MAX_SOCKETS_FOR_PRESSURE_SAMPLE = 32;\n\n//? Read the engine.io write-buffer length defensively — the underlying\n//? `socket.conn` and `transport` are present at runtime but `writeBuffer`\n//? is marked private in the engine.io typings. Narrow the shape via a\n//? runtime guard (vs `as unknown as` double-cast) to satisfy the\n//? boundary-helper lint rule.\ninterface EngineIoConnLike {\n writeBuffer?: { length: number };\n transport?: { writable?: boolean };\n}\n\nconst isEngineConnLike = (value: unknown): value is EngineIoConnLike =>\n typeof value === 'object' && value !== null;\n\nconst readSocketPressure = (socket: Socket): { packets: number; writable: boolean } => {\n const maybeConn: unknown = (socket as { conn?: unknown }).conn;\n if (!isEngineConnLike(maybeConn)) return { packets: 0, writable: true };\n const packets = maybeConn.writeBuffer?.length ?? 0;\n const writable = maybeConn.transport?.writable ?? true;\n return { packets, writable };\n};\n\n//? Poll-based drain — engine.io doesn't surface a per-socket `drain` event\n//? in the Socket.io public API. Poll every POLL_INTERVAL_MS until either\n//? buffer drops below threshold, transport is no longer writable (in\n//? which case waiting is pointless), or `isAborted()` returns true.\nconst waitUntilSocketDrained = async (\n socket: Socket,\n packetThreshold: number,\n isAborted: () => boolean,\n): Promise<void> => {\n let { packets, writable } = readSocketPressure(socket);\n while (writable && packets >= packetThreshold && !isAborted()) {\n await new Promise<void>((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n ({ packets, writable } = readSocketPressure(socket));\n }\n};\n\n//? SYNC-O13 / SYNC-O5 — LOCAL-ONLY. Uses `io.sockets.adapter.rooms` which\n//? is the per-process room view. In a multi-instance cluster (Redis adapter)\n//? members connected to OTHER instances are not visible here, so `flushPressure`\n//? only drains the LOCAL subset (up to MAX_SOCKETS_FOR_PRESSURE_SAMPLE sockets).\n//? Cross-instance backpressure cannot be measured via this API; callers should\n//? treat a resolved `flushPressure()` as \"local buffer cleared\" not \"all\n//? recipients drained\". For `streamTo` use cases the sampled room is the\n//? ORIGINAL `receiver`, not the token-named rooms; the caller's own socket\n//? (originatorSocket) is the primary pressure signal in that case.\nconst collectRoomSocketsForPressure = (receiver: string): Socket[] => {\n const io = getIoInstance();\n if (!io) return [];\n if (!receiver) return [];\n\n if (receiver === 'all') {\n const out: Socket[] = [];\n let i = 0;\n for (const [, sock] of io.sockets.sockets) {\n if (i >= MAX_SOCKETS_FOR_PRESSURE_SAMPLE) break;\n out.push(sock);\n i++;\n }\n return out;\n }\n\n const ids = io.sockets.adapter.rooms.get(receiver);\n if (!ids || ids.size === 0) return [];\n const out: Socket[] = [];\n let i = 0;\n for (const id of ids) {\n if (i >= MAX_SOCKETS_FOR_PRESSURE_SAMPLE) break;\n const sock = io.sockets.sockets.get(id);\n if (sock) out.push(sock);\n i++;\n }\n return out;\n};\n\ninterface BuildSyncStreamEmittersArgs {\n cb: string | undefined;\n receiver: string;\n /**\n * Session user id of the request originator (or null when anonymous). Threaded\n * through so `broadcastStream` / `flushPressure` can route the receiver room\n * through `formatRoomName` with the SAME `{ purpose: 'broadcast', userId }`\n * context the fanout in `handleSyncRequest` / `handleHttpSyncRequest` uses —\n * otherwise a non-identity `registerRoomNameFormatter` (multi-tenant) makes\n * broadcast streams target the UNFORMATTED room and miss every recipient.\n */\n userId?: string | null;\n resolvedName: string;\n emitOriginatorChunk: (payload: SyncStreamPayload) => void;\n logLabel: string;\n /**\n * AbortSignal sourced from the per-request controller in `handleSyncRequest`\n * / `handleHttpSyncRequest`. When aborted (client disconnect, explicit\n * `syncCancel`), every emit is short-circuited with a single dev-log line\n * and `flushPressure()` resolves immediately.\n */\n signal?: AbortSignal;\n /**\n * Originator socket — used to drive `flushPressure` measurement when the\n * stream targets only the originator. Optional because the HTTP/SSE\n * transport has no originator socket (SSE response writer is the sink).\n */\n originatorSocket?: Socket;\n}\n\n//? Shared between socket (`handleSyncRequest`) and HTTP/SSE\n//? (`handleHttpSyncRequest`) transports. The only divergence is the originator\n//? sink: socket transport unicasts a progress event back to the requesting\n//? socket; HTTP transport pipes the chunk through the SSE writer. Caller\n//? supplies that as `emitOriginatorChunk`. Broadcast/streamTo paths use\n//? Socket.io regardless of transport because recipients always live on sockets.\nexport const buildSyncStreamEmitters = ({\n cb,\n receiver,\n userId,\n resolvedName,\n emitOriginatorChunk,\n logLabel,\n signal,\n originatorSocket,\n}: BuildSyncStreamEmittersArgs): SyncStreamEmitters => {\n //? Route the receiver room through the core room-name formatter, matching how\n //? `handleSyncRequest` (runSyncFanout) + `handleHttpSyncRequest` (stageFanout)\n //? resolve the physical room before `fetchSockets()`. Sockets physically JOIN\n //? the FORMATTED room, so a non-identity formatter (multi-tenant key) means the\n //? RAW `receiver` is the wrong physical room. `'all'` and the empty-string\n //? sentinel are passed through unchanged (matching the fanout's `=== 'all'`\n //? branch + the broadcast/pressure guards on the raw `receiver` below).\n const physicalReceiver =\n !receiver || receiver === 'all'\n ? receiver\n : formatRoomName(receiver, { purpose: 'broadcast', userId: userId ?? null });\n //? Per-request chunk counters keyed by recipient. Scoped to this closure\n //? so they are released when the request ends — no process-lifetime leak.\n const chunkCounters = new Map<string, number>();\n const bumpChunkIndex = (recipient: string): number => {\n const next = (chunkCounters.get(recipient) ?? 0) + 1;\n chunkCounters.set(recipient, next);\n return next;\n };\n const dispatchStreamHooks = (recipient: string, chunk: unknown): void => {\n //? Fire-and-forget — stream emitters are sync and consumer hooks must\n //? not block chunk delivery. Errors inside hooks are swallowed by the\n //? hook dispatcher's own tryCatch.\n void dispatchHook('preSyncStream', { routeName: resolvedName, chunk, recipient });\n const chunkIndex = bumpChunkIndex(recipient);\n void dispatchHook('postSyncStream', { routeName: resolvedName, chunk, recipient, chunkIndex });\n };\n\n const buildBroadcastFrame = (payload: SyncStreamPayload) => ({\n ...payload,\n cb,\n fullName: resolvedName,\n status: 'stream' as const,\n });\n\n const isAborted = (): boolean => signal?.aborted === true;\n const logAbortedDrop = (kind: string): void => {\n if (shouldLogStream()) {\n getLogger().debug(`${logLabel}: ${resolvedName} ${kind} skipped — request aborted`);\n }\n };\n\n const emitServerSyncStream = (payload: SyncStreamPayload = {}) => {\n if (isAborted()) { logAbortedDrop('server stream'); return; }\n if (shouldLogStream()) {\n getLogger().debug(`${logLabel}: ${resolvedName} server stream`, { payload });\n }\n dispatchStreamHooks('originator', payload);\n emitOriginatorChunk(payload);\n };\n\n const emitBroadcastSyncStream = (payload: SyncStreamPayload = {}) => {\n if (isAborted()) { logAbortedDrop('broadcastStream'); return; }\n if (shouldLogStream()) {\n getLogger().debug(`${logLabel}: ${resolvedName} broadcastStream`, { payload });\n }\n if (!receiver) return;\n const io = getIoInstance();\n if (!io) return;\n\n dispatchStreamHooks(receiver, payload);\n\n //? `io.to(room).emit` fans the chunk out across EVERY server instance via\n //? the Redis adapter, so room members connected to a different instance get\n //? it too. Do NOT gate on `adapter.rooms.get(receiver)` — that is the\n //? per-process room view; in a multi-instance cluster it only sees locally\n //? connected members, so the previous \"size <= 1 ⇒ unicast to the lone\n //? socket\" optimization mis-fired whenever the other room members lived on\n //? another instance and collapsed broadcastStream into an originator-only\n //? stream. `streamTo` always used `io.to(...).emit` and never had this bug;\n //? this aligns broadcastStream with it.\n io.to(physicalReceiver).emit(socketEventNames.sync, buildBroadcastFrame(payload));\n };\n\n const emitStreamToTokens = (\n tokens: string | string[],\n payload: SyncStreamPayload = {},\n ) => {\n if (isAborted()) { logAbortedDrop('streamTo'); return; }\n const list = Array.isArray(tokens) ? tokens : [tokens];\n const filtered = list.filter((t): t is string => typeof t === 'string' && t.length > 0);\n if (filtered.length === 0) return;\n if (shouldLogStream()) {\n //? Redact the raw bearer session tokens before they reach the stream\n //? debug log — a verbatim token in logs is a usable credential. The\n //? 4-char prefix still correlates log lines.\n getLogger().debug(`${logLabel}: ${resolvedName} streamTo`, { tokens: redactTokens(filtered), payload });\n }\n const io = getIoInstance();\n if (!io) return;\n //? SYNC-N8 — hooks fire before `io.to(tokens).emit()` which is a cross-instance\n //? Redis broadcast; there is no local way to know whether any socket actually\n //? received the frame (the remote instance may have the token-holder). Hooks\n //? are therefore fire-and-forget observers, not delivery confirmations.\n for (const recipient of filtered) {\n dispatchStreamHooks(recipient, payload);\n }\n const frame = buildBroadcastFrame(payload);\n io.to(filtered).emit(socketEventNames.sync, frame);\n };\n\n //? Backpressure helper. Resolves once the worst-case pending write-buffer\n //? across the affected sockets drops below the configured threshold. Used\n //? opt-in by handlers streaming many small chunks (LLM tokens, telemetry).\n //?\n //? Sockets considered (in order of preference):\n //? 1. Originator socket (if provided) — covers `stream(payload)`.\n //? 2. Room sockets for `receiver` (up to 32) — covers `broadcastStream` / `streamTo`.\n //? If neither is available we return immediately — there's nothing to\n //? measure pressure on (e.g. HTTP/SSE only, empty room).\n const flushPressure: FlushPressure = async ({ thresholdBytes } = {}) => {\n if (isAborted()) return;\n //? SYNC-N1 — honour `sync.flushPressure.maxBufferedBytes` from projectConfig\n //? as the fallback so consumer tuning is not silently ignored. Caller-supplied\n //? `thresholdBytes` still wins; the hard-coded DEFAULT_THRESHOLD_BYTES is the\n //? last resort when config is not yet registered (early-boot / test context).\n const configuredBytes = getProjectConfig().sync.flushPressure.maxBufferedBytes;\n const effectiveThresholdBytes = typeof thresholdBytes === 'number' && thresholdBytes > 0\n ? thresholdBytes\n : (typeof configuredBytes === 'number' && configuredBytes > 0 ? configuredBytes : DEFAULT_THRESHOLD_BYTES);\n const packetThreshold = Math.max(1, Math.ceil(effectiveThresholdBytes / AVG_PACKET_BYTES));\n\n const targets: Socket[] = [];\n if (originatorSocket) targets.push(originatorSocket);\n for (const sock of collectRoomSocketsForPressure(physicalReceiver)) {\n //? Avoid duplicating the originator if it's also in the receiver room.\n if (sock !== originatorSocket) targets.push(sock);\n }\n if (targets.length === 0) return;\n\n //? Wait on every target in parallel — worst-case latency wins. Abort\n //? mid-wait short-circuits via `isAborted()` check inside the loop body.\n await Promise.all(targets.map((sock) => waitUntilSocketDrained(sock, packetThreshold, isAborted)));\n };\n\n return {\n emitServerSyncStream,\n emitBroadcastSyncStream,\n emitStreamToTokens,\n buildBroadcastFrame,\n flushPressure,\n };\n};\n","//? Logging-flag accessors shared across the SERVER-side sync transports\n//? (`handleSyncRequest`, `handleHttpSyncRequest`) + `streamEmitters` (CC-5).\n//? Each reads the live `getProjectConfig().logging.*` at call time — never\n//? cached — so a config swap (tests, hot-reload) is picked up immediately.\n//? Previously `shouldLogDev` / `shouldLogStream` were redefined in both\n//? handlers and `streamEmitters.ts`.\n//?\n//? NOTE: imports from the server `@luckystack/core` barrel, so this module is\n//? server-only. The client `syncRequest.ts` keeps its own flag lambdas\n//? (it imports from the browser-safe `@luckystack/core/client` subpath and\n//? must not pull the server barrel into the Vite client bundle).\n\nimport { getProjectConfig } from '@luckystack/core';\n\nexport const shouldLogDev = (): boolean => getProjectConfig().logging.devLogs;\nexport const shouldLogStream = (): boolean => getProjectConfig().logging.stream;\n","//? SYNC-17 — token redaction for logs + error-tracker context.\n//?\n//? Raw session tokens are bearer credentials: anyone holding one can act as the\n//? session. They must never be persisted verbatim into the error tracker\n//? (`tryCatch` context → `captureException`) or stream debug logs, where they\n//? defeat HttpOnly-cookie mode. This helper truncates a token to a short,\n//? non-reversible prefix that is still useful for correlating log lines /\n//? error events without exposing a usable credential.\n\n//? 4 chars is sufficient for log-line correlation while preventing partial\n//? brute-force of low-entropy tokens (audit finding SYNC-medium-5).\nconst VISIBLE_PREFIX = 4;\n\n/**\n * Truncate a session token to `<first 4 chars>…` for safe logging. Returns the\n * value unchanged when it is null/empty (nothing to redact) or already shorter\n * than the visible prefix.\n */\nexport const redactToken = (token: string | null): string | null => {\n if (!token) return token;\n if (token.length <= VISIBLE_PREFIX) return token;\n return `${token.slice(0, VISIBLE_PREFIX)}…`;\n};\n\n/**\n * Redact a list of tokens (e.g. the `streamTo` recipient list) for logging.\n */\nexport const redactTokens = (tokens: readonly string[]): string[] =>\n tokens.map((t) => redactToken(t) ?? t);\n","//? Shared error-envelope builders for the sync transports. Both\n//? `handleSyncRequest` (socket) and `handleHttpSyncRequest` (HTTP/SSE)\n//? previously hand-rolled an identical `buildSyncError` closure that did\n//? normalize → envelope → applyErrorFormatter, plus a duplicate\n//? `ensureSyncErrorShape`. Centralizing them removes the duplication AND the\n//? `as unknown as` double-casts: `applyErrorFormatter` is now generic over the\n//? envelope type (see `@luckystack/core` errorFormatterRegistry), so a typed\n//? envelope flows in and the SAME type flows out — no boundary cast required.\n\nimport {\n applyErrorFormatter,\n normalizeErrorResponse,\n type ErrorFormatter,\n} from '@luckystack/core';\nimport type { SyncErrorEnvelopeInput } from './syncTypes';\n\n//? The post-normalization envelope. `applyErrorFormatter` is generic over this\n//? shape, so the formatted result keeps the same type — both sync handlers can\n//? assign it directly to their `RuntimeErrorResponse` / `HttpSyncResponse`\n//? return types without casting.\nexport interface FormattedSyncErrorEnvelope {\n status: 'error';\n message: string;\n errorCode: string;\n errorParams?: { key: string; value: string | number | boolean }[];\n httpStatus?: number;\n [key: string]: unknown;\n}\n\nexport interface BuildFormattedErrorArgs {\n response: SyncErrorEnvelopeInput;\n preferred?: string | null;\n userLanguage?: string | null;\n routeName: string | undefined;\n transport: 'socket' | 'http';\n userId?: string | null;\n perRouteFormatter?: ErrorFormatter | undefined | null;\n}\n\n/**\n * Normalize an error envelope (i18n message + envelope shape), then run it\n * through the per-route → global → identity formatter chain. Transport\n * handlers pass the same logical inputs; only `transport`, `routeName`, and\n * the per-route formatter differ. Returns a typed, formatted error envelope.\n */\nexport const buildFormattedError = ({\n response,\n preferred,\n userLanguage,\n routeName,\n transport,\n userId,\n perRouteFormatter,\n}: BuildFormattedErrorArgs): FormattedSyncErrorEnvelope => {\n const normalized = normalizeErrorResponse({\n response,\n preferredLocale: preferred,\n userLanguage,\n });\n\n const baseEnvelope: FormattedSyncErrorEnvelope = {\n status: 'error',\n message: normalized.message,\n errorCode: normalized.errorCode,\n errorParams: normalized.errorParams,\n httpStatus: normalized.httpStatus,\n };\n\n return applyErrorFormatter({\n response: baseEnvelope,\n routeName: routeName ?? 'sync/unknown',\n transport,\n userId,\n perRouteFormatter,\n });\n};\n\n/**\n * Guarantee a client-rejection envelope always carries a non-empty\n * `errorCode`, falling back to `sync.clientRejected`. Shared by both\n * transports' per-recipient `_client` error path.\n */\nexport const ensureSyncErrorShape = (\n response: SyncErrorEnvelopeInput,\n): SyncErrorEnvelopeInput => {\n if (typeof response.errorCode === 'string' && response.errorCode.trim().length > 0) {\n return response;\n }\n return { ...response, errorCode: 'sync.clientRejected' };\n};\n","//? Per-recipient `_client` dispatch — shared by both sync transports.\n//?\n//? `handleSyncRequest` (socket) and `handleHttpSyncRequest` (HTTP/SSE)\n//? previously inlined an identical ~70-line loop body that, for one recipient\n//? socket, ran the route's optional `_client_v{N}` handler, normalized its\n//? result, and emitted the per-recipient `sync` envelope (stream / error /\n//? success / server-only-success). The two copies differed only in:\n//?\n//? - the `cb` value carried back to the client (raw `cb` over sockets,\n//? `callbackName` over HTTP),\n//? - the accept-/x-language header preference ORDER used to localize a\n//? per-recipient error (socket prefers `x-language`; HTTP prefers\n//? `accept-language` — preserved verbatim here), and\n//? - the `handler` / log-label strings used for tryCatch context + dev logs.\n//?\n//? Those are now explicit parameters, so the loop body itself is single-source.\n//? Behaviour (emit shapes, ordering, continue-on-error) is identical to the\n//? previous inlined copies.\n\nimport { tryCatch, socketEventNames, getLogger } from '@luckystack/core';\nimport type { RuntimeSyncClientHandler, SyncStreamPayload, SyncErrorEnvelopeInput } from './syncTypes';\nimport { ensureSyncErrorShape } from './errorBuilders';\nimport { redactToken } from './redactToken';\n\n//? Minimal surface of the per-recipient socket the fanout uses. Both\n//? `RemoteSocket` (cross-instance, via the Redis adapter) and a plain local\n//? `Socket` satisfy it, so the helper works for whichever `fetchSockets()`\n//? returns. `emit` is declared method-style (bivariant params) and returns\n//? `unknown` so socket.io's overloaded `emit(): boolean` is assignable.\ninterface FanoutRecipientSocket {\n emit(event: string, ...args: unknown[]): unknown;\n handshake: { headers: Record<string, string | string[] | undefined> };\n}\n\nexport interface ProcessClientSyncForRecipientArgs<TError extends object> {\n tempSocket: FanoutRecipientSocket;\n tempToken: string | null;\n clientSyncHandler: RuntimeSyncClientHandler;\n data: Record<string, unknown>;\n functionsObject: Record<string, unknown>;\n serverOutput: unknown;\n receiver: string;\n resolvedName: string;\n //? `cb` value echoed back to the recipient. Socket transport uses the raw\n //? client `cb`; HTTP transport uses the derived `callbackName`.\n callbackKey: string;\n //? `'socket' | 'http'` — feeds the tryCatch context + chooses the header\n //? preference order for per-recipient error localization.\n transport: 'socket' | 'http';\n handlerName: 'handleSyncRequest' | 'handleHttpSyncRequest';\n logLabel: 'sync' | 'http sync';\n shouldLogDev: () => boolean;\n shouldLogStream: () => boolean;\n buildSyncError: (args: {\n response: SyncErrorEnvelopeInput;\n preferred?: string | null;\n userLanguage?: string | null;\n }) => TError;\n //? Resolves a recipient's preferred locale from its handshake headers,\n //? honoring the transport-specific header preference order.\n resolvePreferredLocale: (headers: Record<string, string | string[] | undefined>) => string | null | undefined;\n sourceUserId?: string;\n}\n\n/**\n * Run the optional `_client` handler for ONE recipient socket and emit the\n * per-recipient `sync` envelope. When the route has no `_client` file the\n * caller emits the server-only success envelope instead (kept at the call site\n * because it does not run the handler). Behaviour-identical to the previously\n * inlined loop body in both transports.\n */\nexport const processClientSyncForRecipient = async <TError extends object>({\n tempSocket,\n tempToken,\n clientSyncHandler,\n data,\n functionsObject,\n serverOutput,\n receiver,\n resolvedName,\n callbackKey,\n transport,\n handlerName,\n logLabel,\n shouldLogDev,\n shouldLogStream,\n buildSyncError,\n resolvePreferredLocale,\n sourceUserId,\n}: ProcessClientSyncForRecipientArgs<TError>): Promise<void> => {\n const emitClientSyncStream = (payload: SyncStreamPayload = {}) => {\n if (shouldLogStream()) {\n getLogger().debug(`${logLabel}: ${resolvedName} client stream`, { payload });\n }\n\n tempSocket.emit(socketEventNames.sync, {\n ...payload,\n cb: callbackKey,\n fullName: resolvedName,\n status: 'stream',\n });\n };\n\n //? SYNC-O14 — the raw `tempToken` is passed to the `_client` handler by design:\n //? `_client` handlers receive it specifically so they can call\n //? `functions.session.getSession(token)` to look up the RECIPIENT's session\n //? without a server-side session store hit from the fanout loop. The token is\n //? NOT forwarded to the error-tracker context — `targetToken` below uses\n //? `redactToken(tempToken)` (SYNC-N2 fix).\n const [clientSyncError, clientSyncResult] = await tryCatch(\n async () => await clientSyncHandler({ clientInput: data, token: tempToken, functions: functionsObject, serverOutput, roomCode: receiver, stream: emitClientSyncStream }),\n undefined,\n {\n handler: handlerName,\n sync: resolvedName,\n stage: 'client',\n sourceUserId,\n //? Redact the raw bearer session token before it lands in the\n //? error-tracker context (`captureException`) — a verbatim token there is\n //? a usable credential (defeats HttpOnly-cookie mode). The 4-char prefix\n //? still correlates error events.\n targetToken: redactToken(tempToken),\n receiver,\n transport,\n },\n );\n const preferred = resolvePreferredLocale(tempSocket.handshake.headers);\n if (clientSyncError) {\n tempSocket.emit(socketEventNames.sync, {\n cb: callbackKey,\n fullName: resolvedName,\n ...buildSyncError({\n response: { status: 'error', errorCode: 'sync.clientExecutionFailed' },\n preferred,\n }),\n });\n return;\n }\n if (clientSyncResult?.status === 'error') {\n tempSocket.emit(socketEventNames.sync, {\n cb: callbackKey,\n fullName: resolvedName,\n ...buildSyncError({\n response: ensureSyncErrorShape(clientSyncResult),\n preferred,\n }),\n });\n return;\n }\n if (clientSyncResult?.status !== 'success') {\n tempSocket.emit(socketEventNames.sync, {\n cb: callbackKey,\n fullName: resolvedName,\n ...buildSyncError({\n response: { status: 'error', errorCode: 'sync.invalidClientResponse' },\n preferred,\n }),\n });\n return;\n }\n\n const result = {\n cb: callbackKey,\n fullName: resolvedName,\n serverOutput,\n clientOutput: clientSyncResult,\n // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- an empty message should fall back to the default too\n message: clientSyncResult.message || `${resolvedName} sync success`,\n status: 'success',\n };\n if (shouldLogDev()) {\n getLogger().debug(`${logLabel}: ${resolvedName} client success`, { result });\n }\n tempSocket.emit(socketEventNames.sync, result);\n};\n","//? Per-route input-validation toggle for sync `_server` handlers. Mirrors the\n//? API package's `resolveValidationMode` (socketValidationStage.ts) so both\n//? transports interpret the `validation` export identically:\n//?\n//? - `'relaxed'` or `{ input: 'skip' }` → skip runtime input validation\n//? entirely. Useful for routes whose payload shape can't reasonably be\n//? modelled in TypeScript (third-party webhook fan-in, dynamic blobs).\n//? - `'strict'`, `{ input: 'strict' }`, or omitted → validate (default).\n//?\n//? Before this existed, `RuntimeSyncServerEntry.validation` was declared,\n//? generated, and documented but never read — both sync handlers always\n//? validated, so the documented escape hatch silently did nothing (QUA-044).\n\nimport type { RuntimeSyncServerEntry } from './syncTypes';\n\nexport const resolveSyncValidationMode = (\n validation: RuntimeSyncServerEntry['validation'],\n): 'strict' | 'relaxed' => {\n if (!validation) return 'strict';\n //? FAIL CLOSED on an unrecognized value. Only the exact string `'relaxed'`\n //? (or the object form `{ input: 'skip' }`) skips validation; ANY other value\n //? — a typo like `'Strict'`/`'on'`, or a stray string the generator emitted —\n //? falls back to `'strict'` (validate). Returning the raw string verbatim\n //? meant a typo silently DISABLED input validation (it failed the caller's\n //? `=== 'strict'` test and skipped), a fail-open footgun.\n if (typeof validation === 'string') {\n return validation === 'relaxed' ? 'relaxed' : 'strict';\n }\n return validation.input === 'skip' ? 'relaxed' : 'strict';\n};\n","//? SYNC-07 — default receiver authorization, shared by both sync transports.\n//?\n//? Historically a client could name ANY `receiver` (a room code, or the\n//? cluster-wide `'all'` broadcast) and the framework fanned out regardless of\n//? whether the requester had actually joined that room — `preSyncAuthorize` was\n//? the only (opt-in, undocumented-as-required) gate. The core config keys\n//? `sync.allowClientReceiverAll` / `sync.requireRoomMembership` add\n//? framework-level defaults; this pure helper resolves the decision so the\n//? socket + HTTP handlers stay single-source and the rule is unit-testable.\n//?\n//? Both flags default to today's permissive behavior (`allowClientReceiverAll:\n//? true`, `requireRoomMembership: false`) so a missing key changes nothing.\n\n/** Decision returned by {@link authorizeSyncReceiver}. */\nexport type ReceiverAuthDecision =\n | { allowed: true }\n | { allowed: false; errorCode: 'sync.receiverNotAllowed' | 'sync.notRoomMember' };\n\nexport interface AuthorizeSyncReceiverInput {\n /** The (already-trimmed, non-empty) receiver the client requested. */\n receiver: string;\n /** `sync.allowClientReceiverAll` from project config. */\n allowClientReceiverAll: boolean;\n /** `sync.requireRoomMembership` from project config. */\n requireRoomMembership: boolean;\n /**\n * Membership predicate for the requested room. Pass a function that reports\n * whether the requester has actually joined `receiver` — on the socket\n * transport this is `socket.rooms.has(receiver)`; on HTTP/SSE (no originator\n * socket) derive it from the session's persisted `roomCodes`. Pass `null`\n * ONLY when membership genuinely cannot be determined for this requester\n * (e.g. an anonymous HTTP caller with no session). When `null` and\n * `requireRoomMembership` is true, this helper FAILS CLOSED (rejects) rather\n * than silently delegating the security default to the opt-in\n * `preSyncAuthorize` hook.\n */\n isMember: (() => boolean) | null;\n}\n\n/**\n * Resolve whether a client may target `receiver` for a sync fanout under the\n * configured default policy. Returns `{ allowed: true }` when permitted, or a\n * specific generic error code when rejected. The `'all'` check runs first\n * (cluster-wide broadcasts are the riskiest), then room-membership.\n */\nexport const authorizeSyncReceiver = ({\n receiver,\n allowClientReceiverAll,\n requireRoomMembership,\n isMember,\n}: AuthorizeSyncReceiverInput): ReceiverAuthDecision => {\n if (receiver === 'all' && !allowClientReceiverAll) {\n return { allowed: false, errorCode: 'sync.receiverNotAllowed' };\n }\n\n //? `'all'` is never a \"joined room\", so membership only gates concrete room\n //? codes. When `requireRoomMembership` is on we FAIL CLOSED: a known\n //? non-member is rejected, AND an UNDETERMINABLE membership (`isMember ===\n //? null`, e.g. an anonymous HTTP caller) is also rejected — previously the\n //? `null` case silently passed, so a consumer who set `requireRoomMembership:\n //? true` was protected on websockets but BYPASSED over the HTTP/SSE fallback\n //? (any `receiver`). The security default must not be silently delegated to\n //? the opt-in `preSyncAuthorize` hook.\n if (requireRoomMembership && receiver !== 'all' && !isMember?.()) {\n return { allowed: false, errorCode: 'sync.notRoomMember' };\n }\n\n return { allowed: true };\n};\n","//? SYNC-20 — targeted disables replacing the former blanket `/* eslint-disable */`.\n//? Same rationale as the socket handler: validated-string template interpolation,\n//? intentional `||` empty-string fallthrough, runtime `?.` guards on runtime-map\n//? values. (The former `user!` assertion at the `validateRequest` call site was\n//? removed once core made `validateRequest` null-safe — CORE-06.)\n/* eslint-disable @typescript-eslint/no-unnecessary-condition, @typescript-eslint/restrict-template-expressions, @typescript-eslint/prefer-nullish-coalescing, @typescript-eslint/no-non-null-assertion, eqeqeq */\nimport type { BaseSessionLayout as SessionLayout, ErrorFormatter, PostSyncFanoutPayload, PostSyncExecutePayload } from '@luckystack/core';\nimport {\n readSession,\n getProjectConfig,\n getRuntimeSyncMaps as getRuntimeSyncMapsFromSource,\n validateRequest,\n extractTokenFromSocket,\n formatRoomName,\n getIoInstance,\n tryCatch,\n parseTransportRouteName,\n checkRateLimit,\n socketEventNames,\n validateInputByType,\n dispatchHook,\n getLogger,\n runWithErrorTrackerIdentityScope,\n setCurrentErrorTrackerIdentity,\n isLoopbackIp,\n extractLanguageFromHeader,\n isProductionRuntime,\n} from '@luckystack/core';\n\n\nimport { buildSyncStreamEmitters } from './_shared/streamEmitters';\nimport type {\n RuntimeSyncServerEntry,\n RuntimeSyncClientHandler,\n SyncStreamPayload,\n SyncErrorEnvelopeInput,\n} from './_shared/syncTypes';\nimport { shouldLogDev, shouldLogStream } from './_shared/logFlags';\nimport { buildFormattedError } from './_shared/errorBuilders';\nimport { processClientSyncForRecipient } from './_shared/clientFanout';\nimport { resolveSyncValidationMode } from './_shared/validationMode';\nimport { authorizeSyncReceiver } from './_shared/receiverAuth';\n\ninterface HttpSyncRequestParams {\n name: string;\n cb?: string;\n data: Record<string, unknown>;\n receiver: string;\n ignoreSelf?: boolean;\n token: string | null;\n requesterIp?: string;\n xLanguageHeader?: string | string[];\n acceptLanguageHeader?: string | string[];\n stream?: (payload: HttpSyncStreamEvent) => void;\n /**\n * Optional AbortSignal. The HTTP server (`@luckystack/server`) wires this\n * to `req.on('close', ...)` so a closed SSE connection aborts in-flight\n * stream emits. Sync handlers receive it as `abortSignal` in params.\n */\n abortSignal?: AbortSignal;\n}\n\ninterface HttpSyncResponse {\n status: 'success' | 'error';\n message: string;\n //? S22 — transport-parity envelope. The Socket.io ack (`handleSyncRequest`)\n //? is the CANONICAL shape: `{ status, message, result: serverOutput }`. The\n //? HTTP/SSE fallback previously FLATTENED `serverOutput` to the top level\n //? (`{ ...serverOutput, status, message }`), so an HTTP caller saw the route\n //? fields hoisted while a socket caller saw them nested under `result`. Both\n //? transports now nest under `result`; `errorCode`/`errorParams`/`httpStatus`\n //? remain on the error envelope only.\n result?: unknown;\n errorCode?: string;\n errorParams?: { key: string; value: string | number | boolean; }[];\n httpStatus?: number;\n}\n\ntype HttpSyncErrorBuilder = (args: {\n response: SyncErrorEnvelopeInput;\n preferred?: string | null;\n userLanguage?: string | null;\n }) => HttpSyncResponse;\n\n//? Returns an HttpSyncResponse when a rate limit was hit (caller should\n//? return it directly), or null when both buckets passed.\nconst applyHttpSyncRateLimits = async ({\n resolvedName,\n requesterIp,\n user,\n buildSyncError,\n preferredLocale,\n routeLimit,\n}: {\n resolvedName: string;\n token: string | null;\n requesterIp: string | undefined;\n user: SessionLayout | null;\n buildSyncError: HttpSyncErrorBuilder;\n preferredLocale: string | null | undefined;\n //? SYNC-11 — per-route `rateLimit` export (parity with the socket handler).\n routeLimit: number | false | undefined;\n}): Promise<HttpSyncResponse | null> => {\n const config = getProjectConfig();\n const effectiveSyncLimit = routeLimit === undefined ? config.rateLimiting.defaultApiLimit : routeLimit;\n if (effectiveSyncLimit !== false && effectiveSyncLimit > 0) {\n //? H-TWIN with the api transport: key the per-route bucket on the VALIDATED\n //? user.id (never the token) so an authenticated abuser can't reset the bucket\n //? by re-logging-in. Anonymous callers fall back to the IP ('unknown' sentinel).\n const identityCb = config.rateLimiting.identity;\n const customIdentity = identityCb?.({ routeName: resolvedName, userId: user?.id ?? null, ip: requesterIp ?? '', transport: 'http' }) ?? null;\n //? SYNC-O11 — use 'unknown' (not 'anonymous') when requesterIp is absent,\n //? matching the global-IP-bucket sentinel on line 156. 'anonymous' collapsed\n //? all unauthenticated callers with no IP into one shared per-route bucket;\n //? 'unknown' is the established sentinel that also signals a missing IP to\n //? hook subscribers (rateLimitExceeded ip field).\n const requesterIdentity = customIdentity?.id ?? user?.id ?? (requesterIp ?? 'unknown');\n const keyPrefix = customIdentity?.scope ?? (user?.id ? 'user' : 'ip');\n const rateLimitKey = `${keyPrefix}:${requesterIdentity}:sync:${resolvedName}`;\n const { allowed, resetIn } = await checkRateLimit({\n key: rateLimitKey,\n limit: effectiveSyncLimit,\n windowMs: config.rateLimiting.windowMs,\n });\n if (!allowed) {\n void dispatchHook('rateLimitExceeded', {\n //? Parity with the API handler: an anonymous per-route bucket is IP-keyed,\n //? so the scope is `ip` (with `route` still set to mark it a per-route\n //? bucket vs the global `:sync:all` IP bucket), never `route`.\n scope: user?.id ? 'user' : 'ip',\n key: rateLimitKey,\n limit: effectiveSyncLimit,\n windowMs: config.rateLimiting.windowMs,\n count: effectiveSyncLimit + 1,\n route: resolvedName,\n userId: user?.id,\n ip: user?.id ? undefined : requesterIp,\n });\n return buildSyncError({\n response: {\n status: 'error',\n errorCode: 'sync.rateLimitExceeded',\n errorParams: [{ key: 'seconds', value: resetIn }],\n httpStatus: 429,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n }\n\n const defaultIpLimit = config.rateLimiting.defaultIpLimit;\n //? Mirror handleHttpApiRequest: skip the global per-IP abuse limit for\n //? loopback traffic in non-production (dev + the scalable test suite).\n //? Per-route limits still apply; production is unaffected.\n //? Mirror handleHttpApiRequest API-O2 fix: use isLoopbackIp() + skipLoopbackInDev\n //? config flag so the loopback check is canonical and config-gated.\n const requesterIsLoopback = config.rateLimiting.skipLoopbackInDev\n && !isProductionRuntime()\n && isLoopbackIp(requesterIp ?? '');\n if (!requesterIsLoopback && defaultIpLimit !== false && defaultIpLimit > 0) {\n const ipBucket = requesterIp ?? 'unknown';\n const ipKey = `ip:${ipBucket}:sync:all`;\n const { allowed, resetIn } = await checkRateLimit({\n key: ipKey,\n limit: defaultIpLimit,\n windowMs: config.rateLimiting.windowMs,\n });\n if (!allowed) {\n void dispatchHook('rateLimitExceeded', {\n scope: 'ip',\n key: ipKey,\n limit: defaultIpLimit,\n windowMs: config.rateLimiting.windowMs,\n count: defaultIpLimit + 1,\n ip: ipBucket,\n });\n return buildSyncError({\n response: {\n status: 'error',\n errorCode: 'sync.rateLimitExceeded',\n errorParams: [{ key: 'seconds', value: resetIn }],\n httpStatus: 429,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n }\n\n return null;\n};\n\nexport type HttpSyncStreamEvent = SyncStreamPayload;\n\n// ─── Shared context threaded through staged helpers ───────────────────────────\n\ninterface HttpSyncContext {\n name: string;\n cb: string | undefined;\n data: Record<string, unknown>;\n normalizedReceiver: string;\n ignoreSelf: boolean | undefined;\n token: string | null;\n requesterIp: string | undefined;\n stream: ((payload: HttpSyncStreamEvent) => void) | undefined;\n effectiveAbortSignal: AbortSignal;\n preferredLocale: string | null;\n user: SessionLayout | null;\n buildSyncError: HttpSyncErrorBuilder;\n}\n\n// ─── Stage 1: parse and resolve the route name ───────────────────────────────\n\n//? Returns the resolved name + callback key, or an error response when parsing\n//? fails or the route is missing from the sync maps.\nasync function stageResolveRoute(\n ctx: HttpSyncContext,\n): Promise<{ resolvedName: string; callbackName: string; error?: never } | { error: HttpSyncResponse; resolvedName?: never; callbackName?: never }> {\n const { name, cb, data, normalizedReceiver, user, buildSyncError, preferredLocale } = ctx;\n\n if (!name || typeof name !== 'string') {\n return {\n error: buildSyncError({\n response: { status: 'error', errorCode: 'sync.invalidRequest' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n //? Parity with the socket transport (handleSyncRequest's parseSyncFields, which\n //? rejects `!data || typeof data != 'object' || Array.isArray(data)`). A null /\n //? non-object / array `clientInput` slips past the HTTP route's\n //? `normalizeHttpSyncParams` coercion; `typeof null === 'object'` and\n //? `typeof [] === 'object'` mean the bare object check is insufficient. Without\n //? this a non-object would reach a `_server` handler expecting an object — and\n //? under `validation: 'relaxed'` there is no further runtime shape check. The\n //? socket path rejects it outright, so the HTTP path must too.\n if (data === null || typeof data !== 'object' || Array.isArray(data)) {\n return {\n error: buildSyncError({\n response: { status: 'error', errorCode: 'sync.invalidRequest' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n const parsedRoute = parseTransportRouteName({ value: name, prefix: 'sync' });\n if (parsedRoute.status === 'error') {\n return {\n error: buildSyncError({\n response: {\n status: 'error',\n errorCode: 'routing.invalidServiceRouteName',\n errorParams: [{ key: 'name', value: name }],\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n const resolvedName = parsedRoute.normalizedFullName;\n const callbackName = typeof cb === 'string' && cb.trim().length > 0\n ? cb.trim()\n : `${parsedRoute.serviceRoute.normalizedRouteName}/${parsedRoute.version}`;\n\n if (!normalizedReceiver) {\n return {\n error: buildSyncError({\n response: { status: 'error', errorCode: 'sync.missingReceiver' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n const { syncObject } = await getRuntimeSyncMapsFromSource();\n\n if (!syncObject[`${resolvedName}_client`] && !syncObject[`${resolvedName}_server`]) {\n return {\n error: buildSyncError({\n response: { status: 'error', errorCode: 'sync.notFound' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n //? SYNC: reject a CLIENT-ONLY route (parity with the socket handler). The\n //? `_server` file is the MANDATORY auth + input-validation gate; the entire\n //? auth+validate block below lives inside `if (serverSyncEntry)`. Without\n //? this guard a `_client`-only route would fan out fully attacker-controlled,\n //? UNVALIDATED input with NO login check — reachable by unauthenticated\n //? callers. Treat a missing `_server` as a routing error.\n if (!syncObject[`${resolvedName}_server`]) {\n if (shouldLogDev()) {\n getLogger().warn(`http sync: ${resolvedName} has a _client file but no required _server file`, { sync: resolvedName, transport: 'http' });\n }\n return {\n error: buildSyncError({\n response: { status: 'error', errorCode: 'sync.notFound' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n return { resolvedName, callbackName };\n}\n\n// ─── Stage 2: auth checks ─────────────────────────────────────────────────────\n\n//? Returns an error response when auth fails, or null when auth passes.\nfunction stageCheckAuth(\n serverSyncEntry: RuntimeSyncServerEntry,\n ctx: Pick<HttpSyncContext, 'user' | 'preferredLocale' | 'buildSyncError'>,\n): HttpSyncResponse | null {\n const { user, preferredLocale, buildSyncError } = ctx;\n const { auth } = serverSyncEntry;\n\n if (auth.login && !user?.id) {\n return buildSyncError({\n response: { status: 'error', errorCode: 'auth.required' },\n preferred: preferredLocale,\n });\n }\n\n //? SYNC-02 — guard the anonymous `additional`-only case (parity with the\n //? socket handler). A route declaring `auth.additional` but not\n //? `auth.login` would otherwise pass `user! === null` into\n //? `validateRequest` → `condition.key in null` TypeError. The body's\n //? tryCatch would catch it, but it would surface as a generic\n //? `sync.serverExecutionFailed` instead of the correct `auth.required`.\n if (auth.additional && auth.additional.length > 0 && !user) {\n return buildSyncError({\n response: { status: 'error', errorCode: 'auth.required' },\n preferred: preferredLocale,\n });\n }\n\n //? CORE-06 / SYNC-02 — `validateRequest` is now null-safe: pass the real\n //? (possibly null) session instead of the former `user!` assertion (parity\n //? with the socket handler). The anonymous-additional case is still\n //? rejected explicitly above with `auth.required`.\n const validationResult = validateRequest({ auth, user });\n if (validationResult.status === 'error') {\n return buildSyncError({\n response: {\n status: 'error',\n errorCode: validationResult.errorCode || 'auth.forbidden',\n errorParams: validationResult.errorParams,\n httpStatus: validationResult.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n\n return null;\n}\n\n// ─── Stage 3: receiver authorization ─────────────────────────────────────────\n\n//? Returns an error response when receiver auth fails, or null when it passes.\nfunction stageAuthorizeReceiver(\n resolvedName: string,\n ctx: Pick<HttpSyncContext, 'normalizedReceiver' | 'user' | 'preferredLocale' | 'buildSyncError'>,\n): HttpSyncResponse | null {\n const { normalizedReceiver, user, preferredLocale, buildSyncError } = ctx;\n const syncConfig = getProjectConfig().sync;\n\n //? SYNC-07 — default receiver authorization (parity with the socket\n //? handler). Over HTTP/SSE there is no originator socket, so membership is\n //? derived from the SESSION's persisted `roomCodes` (the same list\n //? `loadSocket` re-joins on connect). This closes the bypass where a\n //? consumer who set `requireRoomMembership: true` was protected on\n //? websockets but NOT over the HTTP fallback. When there is no session\n //? (anonymous caller) membership is undeterminable → `isMember: null`, and\n //? `authorizeSyncReceiver` fails closed under `requireRoomMembership`.\n const receiverAuth = authorizeSyncReceiver({\n receiver: normalizedReceiver,\n allowClientReceiverAll: syncConfig.allowClientReceiverAll,\n requireRoomMembership: syncConfig.requireRoomMembership,\n //? A session is ALWAYS an implicit member of its OWN token-room: on the socket\n //? transport `loadSocket` auto-joins `socket.join(token)` on connect, so the\n //? socket path's `socket.rooms.has(token)` is true for the caller's own token.\n //? The HTTP path derives membership from persisted `roomCodes`, which never\n //? contains the token-room — so without this self-token allowance a client\n //? could stream to its own session over websockets but NOT over the HTTP\n //? fallback (`sync.notRoomMember`). Targeting your OWN token is safe (you own\n //? it) and grants no access to anyone else's room. Keeps the two transports\n //? symmetric under `requireRoomMembership`.\n isMember: user ? () => normalizedReceiver === user.token || Boolean(user.roomCodes?.includes(normalizedReceiver)) : null,\n });\n\n if (!receiverAuth.allowed) {\n if (shouldLogDev()) {\n getLogger().warn(`http sync: receiver authorization failed for ${resolvedName}`, { sync: resolvedName, receiver: normalizedReceiver, errorCode: receiverAuth.errorCode, transport: 'http' });\n }\n return buildSyncError({\n response: { status: 'error', errorCode: receiverAuth.errorCode, httpStatus: 403 },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n\n return null;\n}\n\n// ─── Stage 4: authorize hooks (preSyncAuthorize / postSyncAuthorize) ──────────\n\n//? Returns an error response when preSyncAuthorize stops the request, or null\n//? when the request is allowed through.\nasync function stageRunAuthorizeHooks(\n resolvedName: string,\n ctx: Pick<HttpSyncContext, 'data' | 'normalizedReceiver' | 'user' | 'preferredLocale' | 'buildSyncError'>,\n): Promise<HttpSyncResponse | null> {\n const { data, normalizedReceiver, user, preferredLocale, buildSyncError } = ctx;\n\n //? Identity propagation hook — runs after basic auth + AuthProps check\n //? and rate-limit pass. `@luckystack/error-tracking`'s\n //? auto-instrumentation subscribes here to call `setSentryUser(user)`.\n const preAuthorizeResult = await dispatchHook('preSyncAuthorize', {\n routeName: resolvedName,\n data,\n user,\n receiver: normalizedReceiver,\n transport: 'http',\n });\n if (preAuthorizeResult.stopped) {\n return buildSyncError({\n response: {\n status: 'error',\n errorCode: preAuthorizeResult.signal.errorCode,\n httpStatus: preAuthorizeResult.signal.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n\n //? Observational mirror of `preSyncAuthorize` (parity with the socket\n //? handler). Fires after the request passes auth + custom policy; lets\n //? audit-log / metrics subscribers record successful authorizations over\n //? the HTTP/SSE transport too. Stop signals are ignored (post-decision).\n void dispatchHook('postSyncAuthorize', {\n routeName: resolvedName,\n data,\n user,\n receiver: normalizedReceiver,\n transport: 'http',\n });\n\n return null;\n}\n\n// ─── Stage 5: input validation ────────────────────────────────────────────────\n\n//? Returns an error response when preSyncValidate stops or input validation\n//? fails, or null when validation passes.\nasync function stageValidateInput(\n resolvedName: string,\n serverSyncEntry: RuntimeSyncServerEntry,\n ctx: Pick<HttpSyncContext, 'data' | 'normalizedReceiver' | 'user' | 'preferredLocale' | 'buildSyncError'>,\n): Promise<HttpSyncResponse | null> {\n const { data, normalizedReceiver, user, preferredLocale, buildSyncError } = ctx;\n\n //? EXT-04 — validation-stage hooks mirroring the API pipeline + socket-sync\n //? handler. `preSyncValidate` may stop before validation; `postSyncValidate`\n //? reports the outcome.\n const preValidateResult = await dispatchHook('preSyncValidate', {\n routeName: resolvedName,\n data,\n user,\n receiver: normalizedReceiver,\n transport: 'http',\n });\n if (preValidateResult.stopped) {\n return buildSyncError({\n response: {\n status: 'error',\n errorCode: preValidateResult.signal.errorCode,\n httpStatus: preValidateResult.signal.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n\n const { inputType, inputTypeFilePath } = serverSyncEntry;\n\n //? Per-route validation toggle (mirrors the API + socket-sync handler).\n //? `'relaxed'` / `{ input: 'skip' }` skips runtime input validation.\n if (resolveSyncValidationMode(serverSyncEntry.validation) === 'strict') {\n const inputValidation = await validateInputByType({\n typeText: inputType,\n value: data,\n rootKey: 'clientInput',\n filePath: inputTypeFilePath,\n });\n void dispatchHook('postSyncValidate', {\n routeName: resolvedName,\n data,\n user,\n receiver: normalizedReceiver,\n transport: 'http',\n validation: inputValidation.status === 'error'\n ? { status: 'error', message: inputValidation.message }\n : { status: 'success' },\n });\n if (inputValidation.status === 'error') {\n //? SYNC-04 SECURITY: do NOT echo the raw validator message back to the\n //? client (schema enumeration). The detail goes to `postSyncValidate`\n //? + the dev log only; the client receives the generic code. Mirrors\n //? the socket handler + the API package's fix.\n if (shouldLogDev()) {\n getLogger().warn(`http sync: input validation failed for ${resolvedName}`, { sync: resolvedName, message: inputValidation.message, transport: 'http' });\n }\n return buildSyncError({\n response: {\n status: 'error',\n errorCode: 'sync.invalidInputType',\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n } else {\n void dispatchHook('postSyncValidate', {\n routeName: resolvedName,\n data,\n user,\n receiver: normalizedReceiver,\n transport: 'http',\n validation: { status: 'success' },\n });\n }\n\n return null;\n}\n\n// ─── Stage 6: execute the server handler ─────────────────────────────────────\n\n//? Returns the server output object on success, or an error response on\n//? failure. The payload reference is shared so span-pinning subscribers work.\nasync function stageExecuteServer(\n resolvedName: string,\n serverSyncEntry: RuntimeSyncServerEntry,\n functionsObject: Record<string, unknown>,\n ctx: Pick<HttpSyncContext, 'data' | 'normalizedReceiver' | 'name' | 'user' | 'preferredLocale' | 'buildSyncError' | 'effectiveAbortSignal' | 'cb' | 'stream'>,\n): Promise<{ serverOutput: Record<string, unknown>; error?: never } | { error: HttpSyncResponse; serverOutput?: never }> {\n const { data, normalizedReceiver, user, preferredLocale, buildSyncError, effectiveAbortSignal, cb, stream } = ctx;\n const { main: serverMain } = serverSyncEntry;\n\n const { emitServerSyncStream, emitBroadcastSyncStream, emitStreamToTokens, flushPressure } =\n buildSyncStreamEmitters({\n cb,\n receiver: normalizedReceiver,\n userId: user?.id ?? null,\n resolvedName,\n logLabel: 'http sync',\n signal: effectiveAbortSignal,\n //? No originatorSocket for HTTP/SSE — `flushPressure` falls back\n //? to room-socket measurement only. SSE backpressure is the\n //? caller's responsibility (Node's `res.write` returns a bool).\n //? Originator chunks travel back via SSE; broadcast / targeted\n //? chunks still flow over Socket.io to recipients in the receiver room.\n emitOriginatorChunk: (payload) => {\n stream?.(payload);\n },\n });\n\n //? EXT-04 — execution-stage hooks mirroring the API pipeline. `preSyncExecute`\n //? may stop before the `_server` runs; `postSyncExecute` fires on BOTH the\n //? success AND failure paths (previously invisible to hook consumers). The\n //? single payload reference is reused so span-pinning subscribers work.\n const executePayload: PostSyncExecutePayload = {\n routeName: resolvedName,\n data,\n user,\n receiver: normalizedReceiver,\n transport: 'http',\n result: undefined,\n error: null,\n durationMs: 0,\n };\n const preExecuteResult = await dispatchHook('preSyncExecute', executePayload);\n if (preExecuteResult.stopped) {\n return {\n error: buildSyncError({\n response: {\n status: 'error',\n errorCode: preExecuteResult.signal.errorCode,\n httpStatus: preExecuteResult.signal.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n const executeStart = Date.now();\n const [serverSyncError, serverSyncResult] = await tryCatch(\n async () => await serverMain({\n clientInput: data,\n user,\n functions: functionsObject,\n roomCode: normalizedReceiver,\n stream: emitServerSyncStream,\n broadcastStream: emitBroadcastSyncStream,\n streamTo: emitStreamToTokens,\n abortSignal: effectiveAbortSignal,\n flushPressure,\n }),\n undefined,\n {\n handler: 'handleHttpSyncRequest',\n sync: resolvedName,\n stage: 'server',\n userId: user?.id,\n //? Bug fix: was `name` (the raw route-name string) — should be\n //? `normalizedReceiver` to match the field's semantics and the socket handler.\n receiver: normalizedReceiver,\n transport: 'http',\n },\n );\n executePayload.result = serverSyncResult;\n executePayload.error = serverSyncError ?? null;\n executePayload.durationMs = Date.now() - executeStart;\n await dispatchHook('postSyncExecute', executePayload);\n\n if (serverSyncError) {\n return {\n error: buildSyncError({\n response: { status: 'error', errorCode: 'sync.serverExecutionFailed' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n if (serverSyncResult?.status == 'error') {\n return {\n error: buildSyncError({\n response: serverSyncResult,\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n if (serverSyncResult?.status !== 'success') {\n return {\n error: buildSyncError({\n response: { status: 'error', errorCode: 'sync.invalidServerResponse' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n return { serverOutput: serverSyncResult };\n}\n\n// ─── Stage 7: fanout to room members ─────────────────────────────────────────\n\n//? Fans the serverOutput out to every connected socket in the receiver room,\n//? respecting `ignoreSelf`, per-recipient hooks, and optional `_client` handlers.\nasync function stageFanout(\n resolvedName: string,\n callbackName: string,\n serverOutput: Record<string, unknown>,\n syncObject: Record<string, unknown>,\n functionsObject: Record<string, unknown>,\n ctx: Pick<HttpSyncContext, 'data' | 'normalizedReceiver' | 'token' | 'ignoreSelf' | 'user' | 'buildSyncError' | 'preferredLocale'>,\n): Promise<HttpSyncResponse | null> {\n const { data, normalizedReceiver, token, ignoreSelf, user, buildSyncError, preferredLocale } = ctx;\n const ioInstance = getIoInstance();\n\n //? Single payload reference reused by pre/post — span pinning in\n //? `@luckystack/error-tracking` uses WeakMap on this object.\n const fanoutPayload: PostSyncFanoutPayload = {\n routeName: resolvedName,\n data,\n user,\n receiver: normalizedReceiver,\n serverOutput,\n transport: 'http',\n recipientCount: 0,\n };\n //? Parity with the socket handler (handleSyncRequest.ts runSyncFanout): capture\n //? the hook result and bail when the hook stops the fanout.\n const preFanoutResult = await dispatchHook('preSyncFanout', fanoutPayload);\n if (preFanoutResult.stopped) {\n //? Parity with the socket handler: a preSyncFanout stop is a DENY decision,\n //? so the HTTP/SSE transport must surface it as an error response — not a\n //? silent success (which would let a deny hook be bypassed over HTTP).\n return buildSyncError({\n response: {\n status: 'error',\n errorCode: preFanoutResult.signal.errorCode,\n httpStatus: preFanoutResult.signal.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n\n //? Over the HTTP/SSE fallback the caller IS the originator, so a receiver\n //? room with no connected sockets (no peers online, or the originator used\n //? HTTP instead of a websocket) is normal — NOT an error. Fall back to an\n //? empty set so the fanout loop simply runs zero times; the server handler\n //? already ran and its `serverOutput` is the meaningful result returned below.\n //? Cross-instance recipient list (RemoteSocket[]) spanning every backend on\n //? the shared Redis adapter, so an HTTP-triggered sync still fans out to room\n //? members on other instances. Empty array = no peers online, which is normal\n //? over the HTTP fallback (the loop just runs zero times).\n //? Branch off the NORMALIZED receiver so authorize, branch, and fetch all\n //? key off the same value (the auth check above used `normalizedReceiver`).\n //? Using the raw `receiver` here diverged from the socket handler and was a\n //? latent inversion hazard if a future edit changed which value gated auth.\n //? Route through the core room-name formatter (PRESENCE-1) so a non-identity\n //? `registerRoomNameFormatter` targets the same physical room sockets joined.\n const physicalReceiver = normalizedReceiver === 'all' ? 'all' : formatRoomName(normalizedReceiver, { purpose: 'broadcast', userId: user?.id ?? null });\n const sockets = physicalReceiver === 'all'\n ? await ioInstance!.fetchSockets()\n : await ioInstance!.in(physicalReceiver).fetchSockets();\n\n let recipientCount = 0;\n //? Yield to the event loop periodically so a giant `receiver: 'all'` fanout\n //? doesn't starve other requests (parity with the socket handler). Tunables\n //? live in projectConfig.sync. Clamp to >= 1 so a misconfigured\n //? `fanoutYieldEvery: 0` doesn't produce `n % 0 === NaN` (never truthy).\n const { fanoutYieldEvery, fanoutYieldMs } = getProjectConfig().sync;\n const yieldEvery = Math.max(1, fanoutYieldEvery);\n let fanoutIterCount = 1;\n for (const tempSocket of sockets) {\n fanoutIterCount++;\n if (fanoutIterCount % yieldEvery === 0) { await new Promise(resolve => setTimeout(resolve, fanoutYieldMs)); }\n\n const tempToken = extractTokenFromSocket(tempSocket);\n\n //? SYNC-O10 — `token &&` guard: an anonymous (token-less) originator is\n //? never matched as \"self\" (null === null is always true). Parity with\n //? the socket handler; `ignoreSelf` is a no-op for anonymous callers by design.\n if (ignoreSelf && typeof ignoreSelf === 'boolean' && token && token === tempToken) {\n continue;\n }\n\n //? SYNC-22 — per-recipient fanout hook (parity with the socket handler).\n //? A stop signal SKIPS just this recipient (loop continues; not counted).\n //? `recipientUserId` is null on the hot path (no per-recipient session\n //? read); a handler can derive it from `recipientSocketId` / `receiver`.\n const preRecipientResult = await dispatchHook('preSyncRecipient', {\n routeName: resolvedName,\n receiver: normalizedReceiver,\n recipientSocketId: tempSocket.id,\n recipientUserId: null,\n serverOutput,\n });\n //? Parity with the socket handler (SYNC-O8): a stop signal with no\n //? overrideOutput skips this recipient entirely; a stop signal WITH\n //? overrideOutput sends the override in place of serverOutput.\n if (preRecipientResult.stopped && preRecipientResult.signal.overrideOutput === undefined) {\n continue;\n }\n\n const effectiveServerOutput = preRecipientResult.stopped\n ? preRecipientResult.signal.overrideOutput\n : serverOutput;\n\n //? Count every recipient the request fanned out to — including ones whose\n //? per-recipient `_client` handler later errors — matching the Socket.io\n //? handler (handleSyncRequest.ts) so `postSyncFanout` sees the same total.\n recipientCount++;\n\n if (syncObject[`${resolvedName}_client`]) {\n const clientSyncHandler = syncObject[`${resolvedName}_client`] as RuntimeSyncClientHandler;\n await processClientSyncForRecipient({\n tempSocket,\n tempToken,\n clientSyncHandler,\n data,\n functionsObject,\n serverOutput: effectiveServerOutput,\n receiver: normalizedReceiver,\n resolvedName,\n callbackKey: callbackName,\n transport: 'http',\n handlerName: 'handleHttpSyncRequest',\n logLabel: 'http sync',\n shouldLogDev,\n shouldLogStream,\n buildSyncError,\n //? HTTP transport prefers `accept-language` over `x-language`\n //? (reversed vs. the socket handler) — preserved verbatim from the\n //? previous inlined error path.\n resolvePreferredLocale: (headers) =>\n extractLanguageFromHeader(headers['accept-language'] || headers['x-language']),\n sourceUserId: user?.id,\n });\n continue;\n }\n\n tempSocket.emit(socketEventNames.sync, {\n cb: callbackName,\n fullName: resolvedName,\n serverOutput: effectiveServerOutput,\n clientOutput: {},\n message: `${resolvedName} sync success`,\n status: 'success',\n });\n }\n\n fanoutPayload.recipientCount = recipientCount;\n await dispatchHook('postSyncFanout', fanoutPayload);\n return null;\n}\n\n//? ET-02 — wrap the whole HTTP/SSE sync request in a per-request error-tracker\n//? identity scope (opened before `readSession`, the first interleaving await).\n//? The resolved session is written into the scope's ALS box the moment it\n//? resolves, so concurrent HTTP syncs with different users can't cross-attribute\n//? captures. Each request gets its own isolated box.\nexport default async function handleHttpSyncRequest(args: HttpSyncRequestParams): Promise<HttpSyncResponse> {\n return runWithErrorTrackerIdentityScope(() => handleHttpSyncRequestScoped(args));\n}\n\nasync function handleHttpSyncRequestScoped({\n name,\n cb,\n data,\n receiver,\n ignoreSelf,\n token,\n requesterIp,\n xLanguageHeader,\n acceptLanguageHeader,\n stream,\n abortSignal,\n}: HttpSyncRequestParams): Promise<HttpSyncResponse> {\n if (shouldLogDev()) {\n getLogger().debug(`http sync: ${name} called`);\n }\n\n //? B1 — HTTP/SSE transport. The caller (typically `@luckystack/server`'s\n //? SSE bridge) wires `req.on('close', ...)` to a controller and passes its\n //? signal in. If no signal was provided we build a dummy controller so\n //? `signal` is always defined for handler param shape. The dummy never\n //? aborts on its own, which preserves current behavior for callers that\n //? don't opt in.\n const effectiveAbortSignal = abortSignal ?? new AbortController().signal;\n\n const normalizedReceiver = typeof receiver === 'string' ? receiver.trim() : '';\n const preferredLocale =\n extractLanguageFromHeader(xLanguageHeader)\n || extractLanguageFromHeader(acceptLanguageHeader);\n const user = await readSession(token);\n //? ET-02 — bind the resolved session into the active per-request ALS identity\n //? box so every capture in this request attributes to this user. Identity also\n //? still flows to the legacy global via the `preSyncAuthorize` hook subscriber;\n //? the ALS read wins at capture time.\n setCurrentErrorTrackerIdentity(user?.id ? { id: user.id, email: user.email ?? undefined, username: user.name ?? undefined } : null);\n\n //? Per-route formatter ref. Mirrors the socket-sync + API handler pattern —\n //? set after the syncEntry lookup; pre-lookup errors fall through to global\n //? formatter only because there's no entry yet to read from.\n let currentRouteName: string | undefined;\n let currentPerRouteFormatter: ErrorFormatter | undefined;\n\n const buildSyncError = ({\n response,\n preferred,\n userLanguage,\n }: {\n response: SyncErrorEnvelopeInput;\n preferred?: string | null;\n userLanguage?: string | null;\n }): HttpSyncResponse => buildFormattedError({\n response,\n preferred,\n userLanguage,\n routeName: currentRouteName,\n transport: 'http',\n userId: user?.id,\n perRouteFormatter: currentPerRouteFormatter,\n });\n\n const ioInstance = getIoInstance();\n\n //? Wrap the body so the span always closes — including on an unexpected\n //? throw. tryCatch returns `[error, value]` so we can call `span.end()`\n //? in one place after the inner work resolves.\n const [bodyError, bodyResult] = await tryCatch(async () => {\n if (!ioInstance) {\n return buildSyncError({\n response: { status: 'error', errorCode: 'sync.ioUnavailable' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n\n // Build the shared context once — all stage helpers read from this.\n const ctx: HttpSyncContext = {\n name,\n cb,\n data,\n normalizedReceiver,\n ignoreSelf,\n token,\n requesterIp,\n stream,\n effectiveAbortSignal,\n preferredLocale,\n user,\n buildSyncError,\n };\n\n // Stage 1: parse and resolve the route name.\n const routeResult = await stageResolveRoute(ctx);\n if (routeResult.error) return routeResult.error;\n const { resolvedName, callbackName } = routeResult;\n currentRouteName = resolvedName;\n\n const { syncObject, functionsObject } = await getRuntimeSyncMapsFromSource();\n const serverSyncEntry = syncObject[`${resolvedName}_server`] as RuntimeSyncServerEntry | undefined;\n currentPerRouteFormatter = serverSyncEntry?.errorFormatter;\n\n // Stage 2: auth checks (only when a _server entry exists, which is always true after stage 1).\n if (serverSyncEntry) {\n const authError = stageCheckAuth(serverSyncEntry, ctx);\n if (authError) return authError;\n }\n\n // Stage 3: receiver authorization.\n const receiverError = stageAuthorizeReceiver(resolvedName, ctx);\n if (receiverError) return receiverError;\n\n //? SYNC-O4 — rate-limit runs BEFORE the consumer `preSyncAuthorize` hook\n //? so an unauthenticated (login:false) caller cannot trigger potentially-\n //? expensive DB/tenant lookups on every message with no throttle.\n const rateLimitResult = await applyHttpSyncRateLimits({\n resolvedName,\n token,\n requesterIp,\n user,\n buildSyncError,\n preferredLocale,\n routeLimit: serverSyncEntry?.rateLimit,\n });\n if (rateLimitResult) return rateLimitResult;\n\n // Stage 4: authorize hooks.\n const authorizeHookError = await stageRunAuthorizeHooks(resolvedName, ctx);\n if (authorizeHookError) return authorizeHookError;\n\n let serverOutput: Record<string, unknown> = {};\n if (serverSyncEntry) {\n // Stage 5: input validation.\n const validationError = await stageValidateInput(resolvedName, serverSyncEntry, ctx);\n if (validationError) return validationError;\n\n // Stage 6: execute the server handler.\n const executeResult = await stageExecuteServer(resolvedName, serverSyncEntry, functionsObject, ctx);\n if (executeResult.error) return executeResult.error;\n serverOutput = executeResult.serverOutput;\n }\n\n // Stage 7: fanout to room members.\n const fanoutError = await stageFanout(resolvedName, callbackName, serverOutput, syncObject, functionsObject, ctx);\n if (fanoutError) return fanoutError;\n\n if (shouldLogDev()) {\n getLogger().debug(`http sync: ${resolvedName} completed`);\n }\n\n //? S22 — conform to the CANONICAL Socket.io ack envelope: nest the route's\n //? `serverOutput` under `result` (was: flattened to the top level). The\n //? socket handler emits `{ status, message, result: serverOutput }`; the\n //? HTTP/SSE fallback now returns the identical shape so a consumer reading\n //? `response.result` gets the route's fields on BOTH transports. The\n //? `message` still prefers the route's own message when it supplied one,\n //? falling back to the generic success line (HttpSyncResponse requires it).\n const serverMessage = (serverOutput as { message?: unknown }).message;\n return {\n status: 'success' as const,\n message: typeof serverMessage === 'string' ? serverMessage : `${resolvedName} sync success`,\n result: serverOutput,\n };\n });\n if (bodyError) {\n getLogger().error(`http sync: ${name} threw`, bodyError, { sync: name });\n return buildSyncError({\n response: { status: 'error', errorCode: 'sync.serverExecutionFailed' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n return bodyResult ?? buildSyncError({\n response: { status: 'error', errorCode: 'sync.serverExecutionFailed' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n}\n","import { getProjectConfig } from '@luckystack/core';\n\n//? Stream-chunk throttle. Coalesces tiny pieces of data (e.g. AI-provider\n//? tokens of 3-10 characters each) into bigger chunks before they're sent\n//? over the wire, cutting message count by 10-100x with no perceptible\n//? latency hit.\n//?\n//? Two flush triggers:\n//? - `flushAtChars` — buffered length crossed the byte threshold.\n//? - `flushEveryMs` — the throttle's internal timer fired.\n//?\n//? Whichever happens first flushes the buffer. The author calls `push(text, emit)`\n//? in the AI loop and `flush(emit)` once after the loop finishes. The `emit`\n//? argument is whichever stream callback the route is using (`stream`,\n//? `broadcastStream`, `streamTo` partial, etc.) — the throttle stays\n//? agnostic so it works with any of the three primitives.\n\nexport interface CreateStreamThrottleOptions {\n /**\n * Flush buffered text once it crosses this many characters. Default: 32.\n * Lower = more updates, more network traffic.\n * Higher = fewer updates, choppier UI.\n */\n flushAtChars?: number;\n /**\n * Flush buffered text after this many milliseconds even if the char\n * threshold hasn't been hit. Default: 50ms — fast enough that the user\n * perceives \"live typing\", slow enough that 50–100 tokens batch into a\n * single message on a fast LLM stream.\n *\n * Set to `false` to disable the timer (only flush at char threshold or\n * on explicit `flush()`).\n */\n flushEveryMs?: number | false;\n /**\n * Field name on the emitted payload that carries the buffered text.\n * Default: `'chunk'`. Override if your stream payload uses a different\n * key (e.g. `'text'`, `'delta'`).\n */\n field?: string;\n}\n\nexport interface StreamThrottle {\n /** Append text to the buffer. May trigger a flush. */\n push: (text: string, emit: (payload: Record<string, unknown>) => void) => void;\n /** Force-flush whatever is in the buffer right now. Call after the source loop ends. */\n flush: (emit: (payload: Record<string, unknown>) => void) => void;\n /** Drop the buffered text without emitting. Useful on abort. */\n reset: () => void;\n}\n\n/**\n * Build a chunk throttle for streaming use cases. Designed for LLM token\n * streams where the provider yields very small pieces (3–10 chars) and you\n * don't want to send a separate socket message for each one.\n *\n * @example\n * const throttle = createStreamThrottle({ flushEveryMs: 50, flushAtChars: 32 });\n * for await (const chunk of openaiStream) {\n * throttle.push(chunk.text, broadcastStream);\n * }\n * throttle.flush(broadcastStream);\n */\nexport const createStreamThrottle = (\n options: CreateStreamThrottleOptions = {},\n): StreamThrottle => {\n const defaults = getProjectConfig().sync.streamThrottle;\n const flushAtChars = options.flushAtChars ?? defaults.flushAtChars;\n const flushEveryMs = options.flushEveryMs ?? defaults.flushEveryMs;\n const field = options.field ?? defaults.field;\n\n let buffer = '';\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n const clearTimer = () => {\n if (timer !== null) {\n clearTimeout(timer);\n timer = null;\n }\n };\n\n const flushNow = (emit: (payload: Record<string, unknown>) => void) => {\n if (buffer.length === 0) {\n clearTimer();\n return;\n }\n const payload: Record<string, unknown> = { [field]: buffer };\n buffer = '';\n clearTimer();\n emit(payload);\n };\n\n return {\n push: (text, emit) => {\n if (!text) return;\n buffer += text;\n\n if (buffer.length >= flushAtChars) {\n flushNow(emit);\n return;\n }\n\n if (flushEveryMs !== false && timer === null) {\n timer = setTimeout(() => {\n flushNow(emit);\n }, flushEveryMs);\n //? Allow process exit even if the throttle has a pending flush.\n //? Prevents tests + short scripts from hanging waiting on a timer.\n if (typeof timer === 'object' && 'unref' in timer) {\n (timer as { unref: () => void }).unref();\n }\n }\n },\n flush: (emit) => {\n flushNow(emit);\n },\n reset: () => {\n buffer = '';\n clearTimer();\n },\n };\n};\n"],"mappings":"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","names":["getProjectConfig","formatRoomName","getIoInstance","tryCatch","socketEventNames","dispatchHook","getLogger","normalizeErrorResponse","getProjectConfig","out","i","getProjectConfig","socketEventNames","getLogger","shouldLogDev","shouldLogStream","getLogger","socketEventNames","getProjectConfig","dispatchHook","getLogger","normalizeErrorResponse","socketEventNames","formatRoomName","tryCatch","getIoInstance","readSession","getProjectConfig","validateRequest","extractTokenFromSocket","formatRoomName","getIoInstance","tryCatch","parseTransportRouteName","checkRateLimit","socketEventNames","validateInputByType","dispatchHook","getLogger","runWithErrorTrackerIdentityScope","setCurrentErrorTrackerIdentity","isLoopbackIp","extractLanguageFromHeader","isProductionRuntime","getProjectConfig","checkRateLimit","dispatchHook","isProductionRuntime","isLoopbackIp","parseTransportRouteName","getLogger","validateRequest","validateInputByType","tryCatch","getIoInstance","formatRoomName","extractTokenFromSocket","extractLanguageFromHeader","socketEventNames","runWithErrorTrackerIdentityScope","readSession","setCurrentErrorTrackerIdentity","getProjectConfig"]}
|
|
1
|
+
{"version":3,"sources":["../src/handleSyncRequest.ts","../src/_shared/streamEmitters.ts","../src/_shared/logFlags.ts","../src/_shared/redactToken.ts","../src/_shared/errorBuilders.ts","../src/_shared/clientFanout.ts","../src/_shared/validationMode.ts","../src/_shared/receiverAuth.ts","../src/handleHttpSyncRequest.ts","../src/streamThrottle.ts"],"sourcesContent":["//? SYNC-20 — targeted disables replacing the former blanket `/* eslint-disable */`\n//? (which masked findings across this security-critical transport file). These\n//? mirror the `@luckystack/api` handlers: template expressions interpolate the\n//? route name / receiver (already validated strings); nullish-coalescing is\n//? deliberately avoided where `||`'s empty-string fallthrough is intended; the\n//? `?.` chains on runtime-map values read as \"unnecessary\" to the typed view but\n//? are real runtime guards. (The former `user!` assertion at the `validateRequest`\n//? call site was removed once core made `validateRequest` null-safe — CORE-06.)\n/* eslint-disable @typescript-eslint/no-unnecessary-condition, @typescript-eslint/restrict-template-expressions, @typescript-eslint/prefer-nullish-coalescing, @typescript-eslint/no-non-null-assertion, eqeqeq */\nimport { randomUUID } from \"node:crypto\";\nimport type { syncMessage, PostSyncFanoutPayload, PostSyncExecutePayload, BaseSessionLayout as SessionLayout, ErrorFormatter, RoomSocket } from \"@luckystack/core\";\nimport { Socket } from \"socket.io\";\nimport {\n readSession,\n getProjectConfig,\n getRuntimeSyncMaps,\n validateRequest,\n extractTokenFromSocket,\n formatRoomName,\n getIoInstance,\n tryCatch,\n parseTransportRouteName,\n checkRateLimit,\n buildSyncProgressEventName,\n buildSyncResponseEventName,\n socketEventNames,\n dispatchHook,\n validateInputByType,\n getLogger,\n resolveClientIp,\n isLoopbackIp,\n extractLanguageFromHeader,\n normalizeErrorResponse,\n runWithErrorTrackerIdentityScope,\n setCurrentErrorTrackerIdentity,\n registerSyncAbortController,\n unregisterSyncAbortController,\n isProductionRuntime,\n} from \"@luckystack/core\";\nimport { buildSyncStreamEmitters } from './_shared/streamEmitters';\n\nimport type {\n RuntimeErrorResponse,\n RuntimeSyncServerEntry,\n RuntimeSyncClientHandler,\n SyncErrorEnvelopeInput,\n} from './_shared/syncTypes';\nimport { shouldLogDev, shouldLogStream } from './_shared/logFlags';\nimport { buildFormattedError } from './_shared/errorBuilders';\nimport { processClientSyncForRecipient } from './_shared/clientFanout';\nimport { resolveSyncValidationMode } from './_shared/validationMode';\nimport { authorizeSyncReceiver } from './_shared/receiverAuth';\n\ntype SyncErrorBuilder = (args: {\n response: SyncErrorEnvelopeInput;\n preferred?: string | null;\n userLanguage?: string | null;\n }) => RuntimeErrorResponse;\n\n//? Returns true when both buckets passed; false when one rejected and the\n//? caller should bail. The caller still owns the socket emit + responseIndex\n//? wiring because the existing code structure interleaves emit logic with\n//? other guard returns.\nconst applySyncRateLimits = async ({\n resolvedName,\n socket,\n user,\n responseIndex,\n buildSyncError,\n preferredLocale,\n routeLimit,\n}: {\n resolvedName: string;\n token: string | null;\n socket: Socket;\n user: SessionLayout | null;\n responseIndex: number | undefined;\n buildSyncError: SyncErrorBuilder;\n preferredLocale: string | null | undefined;\n //? SYNC-11 — per-route `rateLimit` export. `undefined` ⇒ fall back to the\n //? global `defaultApiLimit`; a number overrides the per-requester bucket;\n //? `false` disables it (the global per-IP bucket below still applies).\n routeLimit: number | false | undefined;\n}): Promise<boolean> => {\n const config = getProjectConfig();\n //? Resolve the real client IP once for both buckets. Default\n //? `http.trustProxy: false` returns `socket.handshake.address` verbatim\n //? (only IPv4-mapped IPv6 canonicalized), preserving historical keys; a\n //? trusted proxy honors X-Forwarded-For / X-Real-IP.\n const resolvedIp = resolveClientIp({\n rawAddress: socket.handshake.address,\n headers: socket.handshake.headers,\n trustProxy: config.http.trustProxy,\n trustedProxyHopCount: config.http.trustedProxyHopCount,\n });\n const defaultApiLimit = routeLimit === undefined ? config.rateLimiting.defaultApiLimit : routeLimit;\n if (defaultApiLimit !== false && defaultApiLimit > 0) {\n //? H-TWIN with the api transport: key the per-route bucket on the VALIDATED\n //? user.id (never the token). A token is per-session, so token-keying let an\n //? authenticated abuser reset the bucket by re-logging-in (new token = fresh\n //? counter); user.id ties all of a user's sessions to one bucket. Anonymous\n //? callers fall back to the resolved IP.\n const identityCb = config.rateLimiting.identity;\n const customIdentity = identityCb?.({ routeName: resolvedName, userId: user?.id ?? null, ip: resolvedIp, transport: 'socket' }) ?? null;\n const requesterIdentity = customIdentity?.id ?? user?.id ?? resolvedIp;\n const keyPrefix = customIdentity?.scope ?? (user?.id ? 'user' : 'ip');\n const rateLimitKey = `${keyPrefix}:${requesterIdentity}:sync:${resolvedName}`;\n const { allowed, resetIn } = await checkRateLimit({\n key: rateLimitKey,\n limit: defaultApiLimit,\n windowMs: config.rateLimiting.windowMs,\n });\n if (!allowed) {\n void dispatchHook('rateLimitExceeded', {\n //? Parity with the API handler: an anonymous per-route bucket is IP-keyed,\n //? so the scope is `ip` (with `route` still set to mark it a per-route\n //? bucket vs the global `:sync:all` IP bucket), never `route`.\n scope: user?.id ? 'user' : 'ip',\n key: rateLimitKey,\n limit: defaultApiLimit,\n windowMs: config.rateLimiting.windowMs,\n count: defaultApiLimit + 1,\n route: resolvedName,\n userId: user?.id,\n ip: user?.id ? undefined : resolvedIp,\n });\n if (typeof responseIndex === 'number') {\n socket.emit(buildSyncResponseEventName(responseIndex), buildSyncError({\n response: {\n status: 'error',\n errorCode: 'sync.rateLimitExceeded',\n errorParams: [{ key: 'seconds', value: resetIn }],\n httpStatus: 429,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }));\n }\n return false;\n }\n }\n\n const defaultIpLimit = config.rateLimiting.defaultIpLimit;\n //? SYNC-O11 — skip the global per-IP abuse limit for loopback traffic in\n //? non-production when `skipLoopbackInDev` is enabled (parity with the HTTP\n //? sync transport and the API socket handler). Only the cross-route `:sync:all`\n //? IP bucket is skipped; per-route limits above still apply. Pass the raw\n //? `resolvedIp` (not UNKNOWN_CLIENT_IP) so only real loopback addresses qualify.\n const requesterIsLoopback = config.rateLimiting.skipLoopbackInDev\n && !isProductionRuntime()\n && isLoopbackIp(resolvedIp);\n if (!requesterIsLoopback && defaultIpLimit !== false && defaultIpLimit > 0) {\n const requesterIp = resolvedIp;\n const ipKey = `ip:${requesterIp}:sync:all`;\n const { allowed, resetIn } = await checkRateLimit({\n key: ipKey,\n limit: defaultIpLimit,\n windowMs: config.rateLimiting.windowMs,\n });\n if (!allowed) {\n void dispatchHook('rateLimitExceeded', {\n scope: 'ip',\n key: ipKey,\n limit: defaultIpLimit,\n windowMs: config.rateLimiting.windowMs,\n count: defaultIpLimit + 1,\n ip: requesterIp,\n });\n if (typeof responseIndex === 'number') {\n socket.emit(buildSyncResponseEventName(responseIndex), buildSyncError({\n response: {\n status: 'error',\n errorCode: 'sync.rateLimitExceeded',\n errorParams: [{ key: 'seconds', value: resetIn }],\n httpStatus: 429,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }));\n }\n return false;\n }\n }\n\n return true;\n};\n\n// ─── Private stage helpers ────────────────────────────────────────────────────\n\n//? Centralized error emitter — replaces the ~12 scattered\n//? `typeof responseIndex == 'number' && socket.emit(...)` patterns.\n//? Returns `undefined` so callers can `return rejectSync(...)` from a `void` fn.\nfunction rejectSync({\n socket,\n responseIndex,\n buildSyncError,\n response,\n preferred,\n userLanguage,\n}: {\n socket: Socket;\n responseIndex: number | undefined;\n buildSyncError: SyncErrorBuilder;\n response: SyncErrorEnvelopeInput;\n preferred?: string | null;\n userLanguage?: string | null;\n}): void {\n if (typeof responseIndex === 'number') {\n socket.emit(buildSyncResponseEventName(responseIndex), buildSyncError({\n response,\n preferred,\n userLanguage,\n }));\n }\n}\n\n//? Stage 1 — validates that `msg` is a plain object before any field access.\n//? Emits directly on `socketEventNames.sync` (no `responseIndex` yet) and\n//? returns false when the message shape is invalid.\nfunction validateSyncMessage({\n msg,\n socket,\n preferredLocale,\n}: {\n msg: unknown;\n socket: Socket;\n preferredLocale: string | null;\n}): boolean {\n //? `typeof null === 'object'` and arrays are objects too, so the bare\n //? `typeof != 'object'` guard let a `null`/array payload through to the field\n //? access below (`const { responseIndex } = msg`), throwing before the top-level\n //? tryCatch → unhandledRejection → process kill. Any connected socket could\n //? trigger it pre-auth via `socket.emit('sync', null)` (remote DoS). Reject\n //? non-plain-object payloads here, matching this guard's documented contract.\n if (typeof msg !== 'object' || msg === null || Array.isArray(msg)) {\n if (shouldLogDev()) {\n getLogger().warn('sync: socket message was not a json object');\n }\n const normalized = normalizeErrorResponse({\n response: { status: 'error', errorCode: 'sync.invalidRequest' },\n preferredLocale,\n });\n socket.emit(socketEventNames.sync, {\n status: normalized.status,\n message: normalized.message,\n errorCode: normalized.errorCode,\n errorParams: normalized.errorParams,\n httpStatus: normalized.httpStatus,\n });\n return false;\n }\n return true;\n}\n\n//? Stage 2 — parses and validates the structured fields from the message.\n//? Returns a `{ ok: true, ... }` discriminated union on success so the caller\n//? can narrow the fields without re-casting. On validation failure it emits the\n//? appropriate error and returns `{ ok: false }`.\nfunction parseSyncFields({\n msg,\n socket,\n responseIndex,\n preferredLocale,\n buildSyncError,\n}: {\n msg: syncMessage;\n socket: Socket;\n responseIndex: number | undefined;\n preferredLocale: string | null;\n buildSyncError: SyncErrorBuilder;\n}):\n | { ok: false }\n | {\n ok: true;\n name: string;\n normalizedData: Record<string, unknown>;\n cb: string;\n receiver: string;\n ignoreSelf: boolean | undefined;\n resolvedName: string;\n }\n{\n const { name, data, cb, receiver: rawReceiver, ignoreSelf } = msg;\n const receiver = typeof rawReceiver === 'string' ? rawReceiver.trim() : '';\n\n //? Positive plain-object guard. `typeof data != 'object'` alone let an ARRAY\n //? `clientInput` through (`typeof [] === 'object'`), reaching a `_server`\n //? handler that assumes a plain object — and with `validation: 'relaxed'`\n //? there is no further runtime shape check. `!data` already excludes `null`.\n if (!name || !data || typeof name != 'string' || typeof data != 'object' || Array.isArray(data)) {\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.invalidRequest' }, preferred: preferredLocale });\n return { ok: false };\n }\n\n const parsedRoute = parseTransportRouteName({ value: name, prefix: 'sync' });\n if (parsedRoute.status === 'error') {\n rejectSync({\n socket, responseIndex, buildSyncError,\n response: {\n status: 'error',\n errorCode: 'routing.invalidServiceRouteName',\n errorParams: [{ key: 'name', value: name }],\n },\n preferred: preferredLocale,\n });\n return { ok: false };\n }\n\n const resolvedName = parsedRoute.normalizedFullName;\n\n if (!cb || typeof cb != 'string') {\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.invalidCallback' }, preferred: preferredLocale });\n return { ok: false };\n }\n\n if (!receiver) {\n if (shouldLogDev()) {\n getLogger().warn('sync: missing receiver / roomCode', { receiver });\n }\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.missingReceiver' }, preferred: preferredLocale });\n return { ok: false };\n }\n\n return {\n ok: true,\n name,\n normalizedData: data as Record<string, unknown>,\n cb,\n receiver,\n ignoreSelf: typeof ignoreSelf === 'boolean' ? ignoreSelf : undefined,\n resolvedName,\n };\n}\n\n//? Stage 3 — sets up the per-request AbortController, registers it in the\n//? cancel registry, arms the disconnect listener, and sends the `__cancelId`\n//? handshake frame. Returns the cleanup function and the abort controller so\n//? later stages can call `cleanupRequest()` or read `abortController.signal`.\nfunction setupAbortController({\n socket,\n responseIndex,\n}: {\n socket: Socket;\n responseIndex: number | undefined;\n}): {\n abortController: AbortController;\n abortKey: string;\n cleanupRequest: () => void;\n} {\n //? B1 / S13 — per-request AbortController. The controller drives three things:\n //? 1. Aborts when the client emits `syncCancel { cb: <cancelId> }`.\n //? 2. Aborts when the originator socket disconnects (listener below).\n //? 3. Gates further chunk emits via the signal handed to streamEmitters.\n //?\n //? S13 SECURITY: the registry key MUST NOT be the client-controlled callback\n //? string (`cb` = `${name}/${version}`). That value is REUSED across every\n //? concurrent request of the same route, so two in-flight `sync/chat/send/v1`\n //? calls would register under the identical `${socket.id}:${cb}` key — the\n //? second `Map.set` clobbered the first's controller, a `syncCancel` aborted\n //? the wrong request, and the first request's `unregister` deleted the\n //? second's entry (registry corruption). We now key on a SERVER-ISSUED,\n //? per-request unique `cancelId` and hand that id to the client via a\n //? handshake frame on the progress channel; the client cancels by echoing it\n //? back as `syncCancel { cb: cancelId }`. The wire field stays `cb` so the\n //? existing server-side cancel listener is unchanged — only its value is now\n //? a unique id instead of a reused callback name.\n const cancelId = randomUUID();\n const abortController = new AbortController();\n const abortKey = registerSyncAbortController(socket.id, cancelId, abortController);\n //? Hand the server-issued cancel id to the originator on the progress channel\n //? BEFORE any work runs, so an abort fired mid-flight (even on a non-streaming\n //? route) can target THIS exact request. The client filters this frame out of\n //? its `onStream` delivery by the reserved `__cancelId` marker key.\n if (typeof responseIndex === 'number') {\n socket.emit(buildSyncProgressEventName(responseIndex), { __cancelId: cancelId });\n }\n const onSocketDisconnect = () => { abortController.abort(); };\n socket.once(socketEventNames.disconnect, onSocketDisconnect);\n let cleanupDone = false;\n const cleanupRequest = () => {\n if (cleanupDone) return;\n cleanupDone = true;\n socket.off(socketEventNames.disconnect, onSocketDisconnect);\n unregisterSyncAbortController(abortKey);\n };\n return { abortController, abortKey, cleanupRequest };\n}\n\n//? Stage 4 — verifies the route map contains a valid `_server` file.\n//? A `_client`-only route is rejected as misconfigured (no auth gate).\n//? Returns false and emits the appropriate error when the route is absent.\nfunction checkRouteExists({\n syncObject,\n resolvedName,\n name,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n user,\n cleanupRequest,\n}: {\n syncObject: Record<string, unknown>;\n resolvedName: string;\n name: string;\n socket: Socket;\n responseIndex: number | undefined;\n buildSyncError: SyncErrorBuilder;\n preferredLocale: string | null;\n user: SessionLayout | null;\n cleanupRequest: () => void;\n}): boolean {\n if (!syncObject[`${resolvedName}_client`] && !syncObject[`${resolvedName}_server`]) {\n if (shouldLogDev()) {\n getLogger().warn(`sync: ${name} has no _client or _server file`, { sync: name });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.notFound' }, preferred: preferredLocale, userLanguage: user?.language });\n return false;\n }\n\n //? SYNC: reject a CLIENT-ONLY route (a `_client` file with no `_server`) as\n //? misconfigured. The `_server` file is the documented, MANDATORY gate that\n //? owns auth (`auth.login` / `additional`) and input validation; the entire\n //? auth+validate block below lives inside `if (serverSyncEntry)`. Without\n //? this guard a `_client`-only route would run receiver-auth + the `_client`\n //? fanout with fully attacker-controlled, UNVALIDATED input and NO login\n //? check — reachable by unauthenticated sockets. Treat it as a routing error.\n if (!syncObject[`${resolvedName}_server`]) {\n if (shouldLogDev()) {\n getLogger().warn(`sync: ${resolvedName} has a _client file but no required _server file`, { sync: resolvedName });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.notFound' }, preferred: preferredLocale, userLanguage: user?.language });\n return false;\n }\n\n return true;\n}\n\n//? Stage 5 — runs auth.login, auth.additional presence check, and\n//? `validateRequest`. Returns false and emits `auth.required` / the route's\n//? auth error when the request fails any check.\nfunction runSyncAuth({\n serverSyncEntry,\n user,\n resolvedName,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n cleanupRequest,\n}: {\n serverSyncEntry: RuntimeSyncServerEntry | undefined;\n user: SessionLayout | null;\n resolvedName: string;\n socket: Socket;\n responseIndex: number | undefined;\n buildSyncError: SyncErrorBuilder;\n preferredLocale: string | null;\n cleanupRequest: () => void;\n}): boolean {\n if (!serverSyncEntry) return true;\n\n const { auth } = serverSyncEntry;\n if (auth.login && !user?.id) {\n if (shouldLogDev()) {\n getLogger().warn(`sync: ${resolvedName} requires login`, { sync: resolvedName });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'auth.required' }, preferred: preferredLocale });\n return false;\n }\n\n //? SYNC-02 — guard the anonymous `additional`-only case. When a route\n //? declares `auth.additional` predicates but NOT `auth.login`, an\n //? unauthenticated socket reaches here with `user === null`. Passing\n //? `user!` into `validateRequest` would execute `condition.key in null`\n //? → a fatal `TypeError` that, because loadSocket invokes this handler as\n //? an un-`.catch()`'d `void` IIFE, becomes a process-killing\n //? unhandledRejection. Reject as `auth.required` BEFORE the call (a route\n //? gating on session fields legitimately requires a session).\n if (auth.additional && auth.additional.length > 0 && !user) {\n if (shouldLogDev()) {\n getLogger().warn(`sync: ${resolvedName} requires a session for additional auth`, { sync: resolvedName });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'auth.required' }, preferred: preferredLocale });\n return false;\n }\n\n //? CORE-06 / SYNC-02 — `validateRequest` is now null-safe: pass the real\n //? (possibly null) session instead of the former `user!` assertion. The\n //? anonymous-additional case is still rejected explicitly above with\n //? `auth.required`; core forbids any `additional[]` predicate when no\n //? session rather than throwing on `condition.key in null`.\n const validationResult = validateRequest({ auth, user });\n if (validationResult.status === 'error') {\n if (shouldLogDev()) {\n getLogger().warn(`sync: auth failed for ${resolvedName}`, { sync: resolvedName, errorCode: validationResult.errorCode });\n }\n cleanupRequest();\n rejectSync({\n socket, responseIndex, buildSyncError,\n response: {\n status: 'error',\n errorCode: validationResult.errorCode || 'auth.forbidden',\n errorParams: validationResult.errorParams,\n httpStatus: validationResult.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n return false;\n }\n\n return true;\n}\n\n//? Stage 6 — checks framework-level receiver authorization.\n//? Returns false and emits `sync.notRoomMember` / `sync.receiverNotAllowed`\n//? when the originator is not permitted to target the requested receiver.\nfunction runReceiverAuth({\n receiver,\n resolvedName,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n user,\n cleanupRequest,\n}: {\n receiver: string;\n resolvedName: string;\n socket: Socket;\n responseIndex: number | undefined;\n buildSyncError: SyncErrorBuilder;\n preferredLocale: string | null;\n user: SessionLayout | null;\n cleanupRequest: () => void;\n}): boolean {\n //? SYNC-07 — default receiver authorization. Reject a cluster-wide `'all'`\n //? broadcast when `sync.allowClientReceiverAll` is false, and (when\n //? `sync.requireRoomMembership` is true) a room the originator socket has not\n //? actually joined. Both flags default to today's permissive behavior, so a\n //? missing key changes nothing. Runs before `preSyncAuthorize` so the\n //? framework baseline is enforced first; the hook still applies finer policy.\n const syncConfig = getProjectConfig().sync;\n const receiverAuth = authorizeSyncReceiver({\n receiver,\n allowClientReceiverAll: syncConfig.allowClientReceiverAll,\n requireRoomMembership: syncConfig.requireRoomMembership,\n //? Sockets physically JOIN the FORMATTED room (loadSocket runs the room name\n //? through formatRoomName at join time), so membership must be tested against\n //? the SAME physical name the fanout fetch uses (see physicalReceiver below) —\n //? NOT the raw client `receiver`. Otherwise a non-identity\n //? registerRoomNameFormatter (multi-tenant) makes every joined member fail the\n //? check on the socket transport while HTTP still works.\n isMember: () =>\n socket.rooms.has(\n receiver === 'all' ? 'all' : formatRoomName(receiver, { purpose: 'broadcast', userId: user?.id ?? null }),\n ),\n });\n if (!receiverAuth.allowed) {\n if (shouldLogDev()) {\n getLogger().warn(`sync: receiver authorization failed for ${resolvedName}`, { sync: resolvedName, receiver, errorCode: receiverAuth.errorCode });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: receiverAuth.errorCode, httpStatus: 403 }, preferred: preferredLocale, userLanguage: user?.language });\n return false;\n }\n return true;\n}\n\n//? Stage 7 — runs `preSyncAuthorize` (custom policy hook) and fires\n//? `postSyncAuthorize` (observational). Returns false when the hook stops\n//? the request.\nasync function runPreAuthorizeHook({\n resolvedName,\n normalizedData,\n user,\n receiver,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n cleanupRequest,\n}: {\n resolvedName: string;\n normalizedData: Record<string, unknown>;\n user: SessionLayout | null;\n receiver: string;\n socket: Socket;\n responseIndex: number | undefined;\n buildSyncError: SyncErrorBuilder;\n preferredLocale: string | null;\n cleanupRequest: () => void;\n}): Promise<boolean> {\n //? Custom authorization hook. Fires after basic auth + AuthProps check\n //? and rate-limit pass. Consumers use this to enforce room-membership\n //? rules (\"user X may only emit sync to room Y\"), per-tenant policies,\n //? or audit trails. Stop with a specific errorCode to reject without\n //? revealing input shape.\n const preAuthorizeResult = await dispatchHook('preSyncAuthorize', {\n routeName: resolvedName,\n data: normalizedData,\n user,\n receiver,\n transport: 'socket',\n });\n if (preAuthorizeResult.stopped) {\n if (shouldLogDev()) {\n getLogger().warn(`sync: preSyncAuthorize stopped ${resolvedName}`, { sync: resolvedName, errorCode: preAuthorizeResult.signal.errorCode });\n }\n cleanupRequest();\n rejectSync({\n socket, responseIndex, buildSyncError,\n response: {\n status: 'error',\n errorCode: preAuthorizeResult.signal.errorCode,\n httpStatus: preAuthorizeResult.signal.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n return false;\n }\n\n //? Observational mirror of `preSyncAuthorize`. Fires after the request\n //? passes auth + custom policy; lets audit-log / metrics subscribers\n //? record successful authorizations without forking the dispatch path.\n //? Stop signals from handlers are ignored (this is post-decision).\n void dispatchHook('postSyncAuthorize', {\n routeName: resolvedName,\n data: normalizedData,\n user,\n receiver,\n transport: 'socket',\n });\n\n return true;\n}\n\n//? Stage 8 — validates input (when mode is strict) and runs the `_server`\n//? handler. Returns `{ ok: false }` on any failure (emitting the appropriate\n//? error on the way out) and `{ ok: true, serverOutput }` on success.\nasync function runSyncServerExecution({\n serverSyncEntry,\n resolvedName,\n normalizedData,\n user,\n receiver,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n cleanupRequest,\n functionsObject,\n emitServerSyncStream,\n emitBroadcastSyncStream,\n emitStreamToTokens,\n flushPressure,\n abortController,\n}: {\n serverSyncEntry: RuntimeSyncServerEntry | undefined;\n resolvedName: string;\n normalizedData: Record<string, unknown>;\n user: SessionLayout | null;\n receiver: string;\n socket: Socket;\n responseIndex: number | undefined;\n buildSyncError: SyncErrorBuilder;\n preferredLocale: string | null;\n cleanupRequest: () => void;\n functionsObject: Record<string, unknown>;\n emitServerSyncStream: ReturnType<typeof buildSyncStreamEmitters>['emitServerSyncStream'];\n emitBroadcastSyncStream: ReturnType<typeof buildSyncStreamEmitters>['emitBroadcastSyncStream'];\n emitStreamToTokens: ReturnType<typeof buildSyncStreamEmitters>['emitStreamToTokens'];\n flushPressure: ReturnType<typeof buildSyncStreamEmitters>['flushPressure'];\n abortController: AbortController;\n}): Promise<{ ok: false } | { ok: true; serverOutput: Record<string, unknown> }> {\n if (!serverSyncEntry) return { ok: true, serverOutput: {} };\n\n const { main: serverMain, inputType, inputTypeFilePath } = serverSyncEntry;\n\n //? EXT-04 — validation-stage hooks mirroring the API pipeline. `preSyncValidate`\n //? may stop before validation; `postSyncValidate` reports the outcome.\n const preValidateResult = await dispatchHook('preSyncValidate', {\n routeName: resolvedName,\n data: normalizedData,\n user,\n receiver,\n transport: 'socket',\n });\n if (preValidateResult.stopped) {\n cleanupRequest();\n rejectSync({\n socket, responseIndex, buildSyncError,\n response: {\n status: 'error',\n errorCode: preValidateResult.signal.errorCode,\n httpStatus: preValidateResult.signal.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n return { ok: false };\n }\n\n //? Per-route validation toggle (mirrors the API handler). `'relaxed'` or\n //? `{ input: 'skip' }` skips runtime input validation entirely — for routes\n //? whose payload shape can't be modelled in TS. Default `'strict'`.\n if (resolveSyncValidationMode(serverSyncEntry.validation) === 'strict') {\n const inputValidation = await validateInputByType({\n typeText: inputType,\n value: normalizedData,\n rootKey: 'clientInput',\n filePath: inputTypeFilePath,\n });\n void dispatchHook('postSyncValidate', {\n routeName: resolvedName,\n data: normalizedData,\n user,\n receiver,\n transport: 'socket',\n validation: inputValidation.status === 'error'\n ? { status: 'error', message: inputValidation.message }\n : { status: 'success' },\n });\n if (inputValidation.status === 'error') {\n //? SYNC-04 SECURITY: do NOT echo the raw validator message (e.g.\n //? \"clientInput.userId should be string\") back to the client — that lets\n //? an unauthenticated caller enumerate a route's input schema. The\n //? DETAILED message travels to the `postSyncValidate` hook above + the\n //? dev log below only; the client receives the generic code. Mirrors the\n //? API fix in `@luckystack/api`'s socketValidationStage.\n if (shouldLogDev()) {\n getLogger().warn(`sync: input validation failed for ${resolvedName}`, { sync: resolvedName, message: inputValidation.message });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.invalidInputType' }, preferred: preferredLocale, userLanguage: user?.language });\n return { ok: false };\n }\n } else {\n void dispatchHook('postSyncValidate', {\n routeName: resolvedName,\n data: normalizedData,\n user,\n receiver,\n transport: 'socket',\n validation: { status: 'success' },\n });\n }\n\n //? EXT-04 — execution-stage hooks mirroring the API pipeline. `preSyncExecute`\n //? may stop before the `_server` runs; the single `executePayload` reference is\n //? reused so `@luckystack/error-tracking` can pin spans via WeakMap, and\n //? `postSyncExecute` fires on BOTH the success AND failure paths (the error\n //? path was previously invisible to hook consumers).\n const executePayload: PostSyncExecutePayload = {\n routeName: resolvedName,\n data: normalizedData,\n user,\n receiver,\n transport: 'socket',\n result: undefined,\n error: null,\n durationMs: 0,\n };\n const preExecuteResult = await dispatchHook('preSyncExecute', executePayload);\n if (preExecuteResult.stopped) {\n cleanupRequest();\n rejectSync({\n socket, responseIndex, buildSyncError,\n response: {\n status: 'error',\n errorCode: preExecuteResult.signal.errorCode,\n httpStatus: preExecuteResult.signal.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n return { ok: false };\n }\n\n //? if the user has passed all the checks we call the preload sync function and return the result\n const executeStart = Date.now();\n const [serverSyncError, serverSyncResult] = await tryCatch(\n async () => await serverMain({\n clientInput: normalizedData,\n user,\n functions: functionsObject,\n roomCode: receiver,\n stream: emitServerSyncStream,\n broadcastStream: emitBroadcastSyncStream,\n streamTo: emitStreamToTokens,\n abortSignal: abortController.signal,\n flushPressure,\n }),\n undefined,\n {\n handler: 'handleSyncRequest',\n sync: resolvedName,\n stage: 'server',\n userId: user?.id,\n receiver,\n transport: 'socket',\n },\n );\n executePayload.result = serverSyncResult;\n executePayload.error = serverSyncError ?? null;\n executePayload.durationMs = Date.now() - executeStart;\n await dispatchHook('postSyncExecute', executePayload);\n\n if (serverSyncError) {\n if (shouldLogDev()) {\n getLogger().error(`sync: server execution failed for ${resolvedName}`, serverSyncError, { sync: resolvedName });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.serverExecutionFailed' }, preferred: preferredLocale, userLanguage: user?.language });\n return { ok: false };\n }\n\n if (serverSyncResult?.status == 'error') {\n const normalizedServerError = buildSyncError({\n response: serverSyncResult,\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n if (shouldLogDev()) {\n getLogger().warn(`sync: server returned error for ${resolvedName}`, { sync: resolvedName, message: normalizedServerError.message });\n }\n cleanupRequest();\n if (typeof responseIndex === 'number') {\n socket.emit(buildSyncResponseEventName(responseIndex), normalizedServerError);\n }\n return { ok: false };\n }\n\n if (serverSyncResult?.status !== 'success') {\n //? badReturn means it doesnt include a status key with the value 'success' || 'error'\n if (shouldLogDev()) {\n getLogger().warn(`sync: ${resolvedName}_server returned invalid response`, { sync: resolvedName });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.invalidServerResponse' }, preferred: preferredLocale, userLanguage: user?.language });\n return { ok: false };\n }\n\n return { ok: true, serverOutput: serverSyncResult };\n}\n\n//? Stage 8 — resolves the cross-instance recipient list BEFORE the `_server`\n//? handler runs. `fetchSockets()` (via the Redis adapter) returns RemoteSocket\n//? objects spanning EVERY backend sharing the adapter — not just this process's\n//? room view — so a normal sync fan-out reaches room members connected to other\n//? instances. `remoteSocket.emit()` routes to the owning instance. (Per-sync\n//? Redis round-trip; see docs/ARCHITECTURE_MULTI_INSTANCE.md.)\n//?\n//? @adr 0063\n//? Why before execution: this query can fail (an adapter `requestsTimeout` when\n//? an instance on the channel does not answer) or come back empty. When that\n//? happened AFTER `_server` had persisted its mutation, the originator was told\n//? `error` about a change that had in fact been saved — and a retry applied it\n//? twice. Resolving first makes every error on this path a pre-commit\n//? rejection: nothing was saved, so `error` is true and a retry is safe.\n//? The cost is a recipient snapshot taken a handler-execution earlier; a socket\n//? that joins the room while `_server` runs misses this one fan-out.\n//?\n//? Route the receiver room through the core room-name formatter (PRESENCE-1)\n//? so a non-identity `registerRoomNameFormatter` targets the same physical room\n//? that sockets actually joined (which is already formatted at join time).\n//? Returns null when there are no recipients (already emitted an error).\nasync function resolveSyncRecipients({\n ioInstance,\n receiver,\n resolvedName,\n user,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n cleanupRequest,\n}: {\n ioInstance: ReturnType<typeof getIoInstance>;\n receiver: string;\n resolvedName: string;\n user: SessionLayout | null;\n socket: Socket;\n responseIndex: number | undefined;\n buildSyncError: SyncErrorBuilder;\n preferredLocale: string | null;\n cleanupRequest: () => void;\n}): Promise<RoomSocket[] | null> {\n const physicalReceiver = receiver === 'all' ? 'all' : formatRoomName(receiver, { purpose: 'broadcast', userId: user?.id ?? null });\n const sockets = physicalReceiver === 'all'\n ? await ioInstance!.fetchSockets()\n : await ioInstance!.in(physicalReceiver).fetchSockets();\n\n //? now we check if we found any sockets\n if (sockets.length === 0) {\n if (shouldLogDev()) {\n getLogger().warn('sync: no sockets found for receiver', { receiver, sync: resolvedName });\n }\n cleanupRequest();\n rejectSync({ socket, responseIndex, buildSyncError, response: { status: 'error', errorCode: 'sync.noReceiversFound' }, preferred: preferredLocale, userLanguage: user?.language });\n return null;\n }\n return sockets;\n}\n\n//? Stage 10 — runs the per-recipient fanout over the recipients resolved in\n//? stage 8 (preSyncFanout → ack originator → loop → postSyncFanout).\n//? Returns false when the fanout was refused by a hook (already emitted an error).\nasync function runSyncFanout({\n sockets,\n receiver,\n resolvedName,\n normalizedData,\n serverOutput,\n user,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n cleanupRequest,\n ignoreSelf,\n token,\n syncObject,\n functionsObject,\n}: {\n sockets: RoomSocket[];\n receiver: string;\n resolvedName: string;\n normalizedData: Record<string, unknown>;\n serverOutput: Record<string, unknown>;\n user: SessionLayout | null;\n socket: Socket;\n responseIndex: number | undefined;\n buildSyncError: SyncErrorBuilder;\n preferredLocale: string | null;\n cleanupRequest: () => void;\n ignoreSelf: boolean | undefined;\n token: string | null;\n cb: string;\n syncObject: Record<string, unknown>;\n functionsObject: Record<string, unknown>;\n}): Promise<boolean> {\n //? Single payload reference reused by pre/post — span pinning in\n //? `@luckystack/error-tracking` uses WeakMap on this object. `recipientCount`\n //? is mutated in place after fanout completes.\n const fanoutPayload: PostSyncFanoutPayload = {\n routeName: resolvedName,\n data: normalizedData,\n user,\n receiver,\n serverOutput,\n transport: 'socket',\n recipientCount: 0,\n };\n const preFanoutResult = await dispatchHook('preSyncFanout', fanoutPayload);\n if (preFanoutResult.stopped) {\n cleanupRequest();\n rejectSync({\n socket, responseIndex, buildSyncError,\n response: {\n status: 'error',\n errorCode: preFanoutResult.signal.errorCode,\n httpStatus: preFanoutResult.signal.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n return false;\n }\n\n //? SYNC-O9 — ack the originator as soon as server execution + preSyncFanout\n //? pass, BEFORE the per-recipient _client loop runs. The serial loop can take\n //? O(recipients × _client latency) on a large `receiver: 'all'` fanout, which\n //? would trip the client's requestTimeoutMs and cause a false 504 for the\n //? originator even though the server side succeeded. Recipients still get their\n //? payloads — the loop continues after the ack.\n //? Note: we intentionally do NOT call cleanupRequest() here so the disconnect\n //? listener stays active and can still abort the in-flight fanout loop.\n //? `originatorAcked` (hoisted above tryCatch) gates the error-fallback so a\n //? later fanout throw does not emit a conflicting response after the success ack.\n let originatorAcked = false;\n if (typeof responseIndex === 'number') {\n socket.emit(buildSyncResponseEventName(responseIndex), {\n status: 'success',\n message: `sync ${resolvedName} success`,\n result: serverOutput,\n });\n originatorAcked = true;\n }\n\n //? here we loop over all the connected clients\n //? Yield to the event loop periodically so a giant `receiver: 'all'` fanout\n //? doesn't starve other requests. Tunables live in projectConfig.sync.\n const { fanoutYieldEvery, fanoutYieldMs } = getProjectConfig().sync;\n //? SYNC-16 — clamp to >= 1 so a misconfigured `fanoutYieldEvery: 0` doesn't\n //? produce `n % 0 === NaN` (never truthy) → the loop never yields and a giant\n //? `receiver: 'all'` fanout can starve the event loop.\n const yieldEvery = Math.max(1, fanoutYieldEvery);\n let recipientCount = 0;\n let tempCount = 1;\n for (const tempSocket of sockets) {\n tempCount++;\n if (tempCount % yieldEvery === 0) { await new Promise(resolve => setTimeout(resolve, fanoutYieldMs)); }\n\n //? check if they have a token stored in their cookie or session based on the settings\n const tempToken = extractTokenFromSocket(tempSocket);\n\n //? Symmetry with the HTTP handler: strict equality + a `token` guard so an\n //? anonymous (token-less) socket is never treated as \"self\" (null == null).\n if (ignoreSelf && typeof ignoreSelf === 'boolean' && token && token === tempToken) {\n continue;\n }\n\n //? SYNC-22 — per-recipient fanout hook. Fires ONCE per resolved recipient,\n //? before this socket receives anything, letting a consumer FILTER the\n //? fanout (block users, per-tenant visibility) without a `_client` file. A\n //? stop signal SKIPS just this recipient — the loop continues and the\n //? recipient is NOT counted as delivered. `recipientUserId` is always null\n //? (resolving it would cost a session read per recipient); the recipient's\n //? TOKEN is already known here, so it is passed along and a handler that\n //? needs the user reads the session by it.\n //? SYNC-O8 — per-recipient hook. A stop signal with no `overrideOutput`\n //? SKIPS this recipient (existing behaviour). A stop signal WITH\n //? `overrideOutput` sends the override in place of `serverOutput` so a\n //? consumer can redact PII without excluding the socket from the fanout.\n //? This allows fine-grained per-recipient redaction even when no `_client`\n //? file is present (which would otherwise broadcast the full serverOutput).\n const preRecipientResult = await dispatchHook('preSyncRecipient', {\n routeName: resolvedName,\n receiver,\n recipientSocketId: tempSocket.id,\n recipientToken: tempToken,\n recipientUserId: null,\n serverOutput,\n });\n if (preRecipientResult.stopped && preRecipientResult.signal.overrideOutput === undefined) {\n continue;\n }\n\n //? Use the override output when the hook supplied one; fall back to the\n //? unredacted serverOutput for all other recipients.\n const effectiveServerOutput = preRecipientResult.stopped\n ? preRecipientResult.signal.overrideOutput\n : serverOutput;\n\n recipientCount++;\n\n if (syncObject[`${resolvedName}_client`]) {\n const clientSyncHandler = syncObject[`${resolvedName}_client`] as RuntimeSyncClientHandler;\n await processClientSyncForRecipient({\n tempSocket,\n tempToken,\n clientSyncHandler,\n data: normalizedData,\n functionsObject,\n serverOutput: effectiveServerOutput,\n receiver,\n resolvedName,\n //? Server-authoritative callback key (SYNC security): route recipient\n //? callbacks off the SERVER-resolved route, never the client-supplied\n //? `cb`. Otherwise a room co-member could send a legit `name` but a `cb`\n //? for a DIFFERENT route and fire other clients' handlers for that route\n //? (cross-route callback spoofing). The client `cb` stays only for the\n //? originator's own cancel handshake.\n callbackKey: resolvedName,\n transport: 'socket',\n handlerName: 'handleSyncRequest',\n logLabel: 'sync',\n shouldLogDev,\n shouldLogStream,\n buildSyncError,\n //? Socket transport prefers `x-language` over `accept-language` —\n //? preserved verbatim from the previous inlined error path.\n resolvePreferredLocale: (headers) =>\n extractLanguageFromHeader(headers['x-language'])\n || extractLanguageFromHeader(headers['accept-language']),\n sourceUserId: user?.id,\n });\n } else {\n //? No _client file — broadcast serverOutput (or the per-recipient\n //? override when the preSyncRecipient hook supplied one) to this socket.\n const result = {\n //? Server-authoritative cb (SYNC security): emit the SERVER-resolved\n //? route so a spoofed client `cb` can't route this payload to a different\n //? route's callbacks on recipients. Mirrors the _client-path callbackKey.\n cb: resolvedName,\n fullName: resolvedName,\n serverOutput: effectiveServerOutput,\n clientOutput: {},\n message: `${resolvedName} sync success`,\n status: 'success'\n };\n if (shouldLogDev()) {\n getLogger().debug(`sync: ${resolvedName} server-only success`, { result });\n }\n tempSocket.emit(socketEventNames.sync, result);\n }\n }\n\n fanoutPayload.recipientCount = recipientCount;\n await dispatchHook('postSyncFanout', fanoutPayload);\n cleanupRequest();\n\n return originatorAcked;\n}\n\n// export default async function handleSyncRequest({ name, clientData, user, serverOutput, roomCode }: syncMessage) {\n//? ET-02 — open a per-request error-tracker identity scope around the ENTIRE sync\n//? handler before any await that could interleave with another concurrent request\n//? (`readSession` below is such a boundary). The resolved session is written into\n//? the scope's ALS box the moment it resolves, so two concurrent syncs with\n//? different users can't cross-attribute captures. Each request gets its own box.\nexport default async function handleSyncRequest(args: {\n msg: syncMessage,\n socket: Socket,\n token: string | null,\n}): Promise<void> {\n await runWithErrorTrackerIdentityScope(() => handleSyncRequestInner(args));\n}\n\nasync function handleSyncRequestInner({ msg, socket, token }: {\n msg: syncMessage,\n socket: Socket,\n token: string | null,\n}) {\n\n const ioInstance = getIoInstance();\n if (!ioInstance) { return; }\n\n //? Resolve locale once up front for both the early plain-object guard and\n //? all subsequent error emits.\n const preferredLocale =\n extractLanguageFromHeader(socket.handshake.headers['x-language'])\n || extractLanguageFromHeader(socket.handshake.headers['accept-language']);\n\n // Stage 1 — validate raw message shape\n if (!validateSyncMessage({ msg, socket, preferredLocale })) return;\n\n const { responseIndex } = msg;\n\n //? EXT-02 — per-message socket interception seam (websocket counterpart to\n //? `preHttpRequest`). Fires before session lookup / route resolution / auth\n //? so a consumer can gate, throttle, or audit individual sync messages. A\n //? stop signal rejects the message: we emit a localized error envelope on the\n //? response channel (when the client supplied a `responseIndex`) and abort.\n const preMessageResult = await dispatchHook('preSocketMessage', {\n channel: 'sync',\n socketId: socket.id,\n ip: socket.handshake.address,\n authenticated: Boolean(token),\n routeName: typeof msg.name === 'string' ? msg.name : undefined,\n });\n if (preMessageResult.stopped) {\n return typeof responseIndex == 'number' && socket.emit(buildSyncResponseEventName(responseIndex), normalizeErrorResponse({\n response: {\n status: 'error',\n errorCode: preMessageResult.signal.errorCode,\n httpStatus: preMessageResult.signal.httpStatus,\n },\n preferredLocale,\n }));\n }\n\n //? Per-route formatter ref + resolved-name ref — both undefined until the\n //? sync entry is looked up. Pre-lookup errors (invalid message, unknown\n //? route) emit with global formatter only because there's no syncEntry yet.\n //? `let` (not `const`): each is declared here, captured by the `buildSyncError`\n //? closure below, and assigned only further down once the route/session resolves\n //? — so a `const` at declaration is impossible (TDZ in the closure). The\n //? flow-based `prefer-const` mis-reads the single later assignment as the sole\n //? init for the two `string | undefined` refs; disabled with that rationale.\n // eslint-disable-next-line prefer-const\n let currentRouteName: string | undefined;\n let currentPerRouteFormatter: ErrorFormatter | undefined;\n // eslint-disable-next-line prefer-const\n let currentUserId: string | undefined;\n\n const buildSyncError = ({\n response,\n preferred,\n userLanguage,\n }: {\n response: SyncErrorEnvelopeInput;\n preferred?: string | null;\n userLanguage?: string | null;\n }): RuntimeErrorResponse => buildFormattedError({\n response,\n preferred,\n userLanguage,\n routeName: currentRouteName,\n transport: 'socket',\n userId: currentUserId,\n perRouteFormatter: currentPerRouteFormatter,\n });\n\n // Stage 2 — parse and validate structured message fields\n const parsedFields = parseSyncFields({ msg, socket, responseIndex, preferredLocale, buildSyncError });\n if (!parsedFields.ok) return;\n\n const { name, normalizedData, cb, receiver, resolvedName } = parsedFields;\n currentRouteName = resolvedName;\n\n if (shouldLogDev()) {\n getLogger().debug(`sync: ${resolvedName} called`, { sync: resolvedName });\n }\n\n const user = await readSession(token);\n currentUserId = user?.id;\n //? ET-02 — bind the resolved session into the active per-request ALS identity\n //? box so every subsequent capture (server handler throw, `_client` fanout,\n //? hook subscriber) attributes to this user. Identity also still flows to the\n //? legacy global via the `preSyncAuthorize` hook subscriber; the ALS read wins\n //? at capture time.\n setCurrentErrorTrackerIdentity(user?.id ? { id: user.id, email: user.email ?? undefined, username: user.name ?? undefined } : null);\n const { syncObject, functionsObject } = await getRuntimeSyncMaps();\n\n // Stage 3 — set up AbortController + cleanup\n const { abortController, cleanupRequest } = setupAbortController({ socket, responseIndex });\n\n //? SYNC-O9 — tracks whether the originator's response channel has been\n //? settled (early-ack before the fanout loop). When true, the error-fallback\n //? must NOT emit a second response on that channel.\n let originatorAcked = false;\n\n //? SYNC-02 — top-level error envelope. The socket handler runs un-`.catch()`'d\n //? from loadSocket (`void (async () => …)()`), so ANY throw below — a\n //? `fetchSockets()` Redis-adapter timeout, a misbehaving `_server`/`_client`\n //? handler, a hook subscriber — would surface as a fatal unhandledRejection\n //? (process kill on modern Node). The HTTP twin already wraps its body the\n //? same way. On throw we run cleanup and emit `sync.serverExecutionFailed`.\n const [handlerError] = await tryCatch(async () => {\n\n // Stage 4 — verify route exists\n if (!checkRouteExists({ syncObject, resolvedName, name, socket, responseIndex, buildSyncError, preferredLocale, user, cleanupRequest })) return;\n\n const { emitServerSyncStream, emitBroadcastSyncStream, emitStreamToTokens, flushPressure } =\n buildSyncStreamEmitters({\n cb,\n receiver,\n userId: user?.id ?? null,\n resolvedName,\n logLabel: 'sync',\n signal: abortController.signal,\n originatorSocket: socket,\n emitOriginatorChunk: (payload) => {\n if (typeof responseIndex !== 'number') return;\n socket.emit(buildSyncProgressEventName(responseIndex), payload);\n },\n });\n\n //? Pipeline order: auth → rate-limit → validate → execute → respond.\n //? Auth runs first so unauthenticated probes can't consume rate-limit budget\n //? or learn input shape from `inputValidation.message`. Mirrors api handlers.\n const serverSyncEntry = syncObject[`${resolvedName}_server`] as RuntimeSyncServerEntry | undefined;\n currentPerRouteFormatter = serverSyncEntry?.errorFormatter;\n\n // Stage 5 — auth\n if (!runSyncAuth({ serverSyncEntry, user, resolvedName, socket, responseIndex, buildSyncError, preferredLocale, cleanupRequest })) return;\n\n // Stage 6 — receiver auth\n if (!runReceiverAuth({ receiver, resolvedName, socket, responseIndex, buildSyncError, preferredLocale, user, cleanupRequest })) return;\n\n //? SYNC-O4 — rate-limit runs BEFORE the consumer `preSyncAuthorize` hook so\n //? an unauthenticated (login:false) caller cannot trigger potentially-expensive\n //? DB/tenant lookups on every message with no throttle.\n const rateLimitOk = await applySyncRateLimits({\n resolvedName,\n token,\n socket,\n user,\n responseIndex,\n buildSyncError,\n preferredLocale,\n routeLimit: serverSyncEntry?.rateLimit,\n });\n if (!rateLimitOk) { cleanupRequest(); return; }\n\n // Stage 7 — pre/post authorize hooks\n if (!await runPreAuthorizeHook({ resolvedName, normalizedData, user, receiver, socket, responseIndex, buildSyncError, preferredLocale, cleanupRequest })) return;\n\n // Stage 8 — resolve recipients (before anything is persisted)\n const sockets = await resolveSyncRecipients({\n ioInstance,\n receiver,\n resolvedName,\n user,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n cleanupRequest,\n });\n if (sockets === null) return;\n\n // Stage 9 — validate input + run server handler\n const executionResult = await runSyncServerExecution({\n serverSyncEntry,\n resolvedName,\n normalizedData,\n user,\n receiver,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n cleanupRequest,\n functionsObject,\n emitServerSyncStream,\n emitBroadcastSyncStream,\n emitStreamToTokens,\n flushPressure,\n abortController,\n });\n if (!executionResult.ok) return;\n\n const { serverOutput } = executionResult;\n\n //? from here on we can assume that we have either called a server sync and got a proper result of we didnt call a server sync\n\n // Stage 10 — fanout\n const fanoutAcked = await runSyncFanout({\n sockets,\n receiver,\n resolvedName,\n normalizedData,\n serverOutput,\n user,\n socket,\n responseIndex,\n buildSyncError,\n preferredLocale,\n cleanupRequest,\n ignoreSelf: parsedFields.ignoreSelf,\n token,\n cb,\n syncObject,\n functionsObject,\n });\n if (typeof fanoutAcked === 'boolean') {\n originatorAcked = fanoutAcked || originatorAcked;\n }\n\n }, undefined, {\n handler: 'handleSyncRequest',\n sync: currentRouteName,\n stage: 'handler',\n userId: currentUserId,\n receiver,\n transport: 'socket',\n });\n if (handlerError) {\n if (shouldLogDev()) {\n getLogger().error(`sync: unhandled error for ${currentRouteName ?? msg.name}`, handlerError, { sync: currentRouteName });\n }\n cleanupRequest();\n //? Guard: if the originator was already acked (SYNC-O9 early ack), do not\n //? emit a conflicting error response — the success already settled the\n //? client's pending promise. Only log the fanout-phase error above.\n if (!originatorAcked) {\n return typeof responseIndex == 'number' && socket.emit(buildSyncResponseEventName(responseIndex), buildSyncError({\n response: { status: 'error', errorCode: 'sync.serverExecutionFailed' },\n preferred: preferredLocale,\n }));\n }\n }\n}\n","import {\n dispatchHook,\n formatRoomName,\n getIoInstance,\n getLogger,\n getProjectConfig,\n socketEventNames,\n} from '@luckystack/core';\nimport type { Socket } from 'socket.io';\nimport { shouldLogStream } from './logFlags';\nimport { redactTokens } from './redactToken';\n\n//? Chunk-index counters are intentionally per-request (built inside\n//? `buildSyncStreamEmitters`) so they are garbage-collected with the\n//? closure when the request ends. A module-level Map keyed on\n//? `routeName|recipient` would grow unbounded for the process lifetime\n//? because `bumpChunkIndex` only ever `set`s — there is no teardown\n//? hook that reliably fires per room. (SYNC-N4)\n\nexport type SyncStreamPayload = Record<string, unknown>;\n\n//? Optional helper passed to consumer handlers so an LLM/long stream can\n//? `await flushPressure()` between chunks. Resolves once the underlying\n//? Socket.io transport's pending write buffer drops below `thresholdBytes`\n//? (measured in packets, not bytes — engine.io exposes a writeBuffer of\n//? packet objects, not byte length, so we approximate via packet count).\n//? Fallback threshold (used only before config is registered) = 1 MB ≈ 1024\n//? packets at ~1KB each; the EFFECTIVE default is `sync.flushPressure.maxBufferedBytes`\n//? (5 MiB). Handlers opt in;\n//? omitting the call is fine for handlers that don't stream a lot.\nexport interface FlushPressureOptions {\n /**\n * Drain threshold in bytes. Used as a packet-count approximation —\n * we assume an average packet size of ~1024 bytes and resolve once the\n * engine.io writeBuffer length is below `thresholdBytes / 1024`.\n * When omitted, falls back to `projectConfig.sync.flushPressure.maxBufferedBytes`\n * (default 5 MiB as configured in the framework defaults).\n */\n thresholdBytes?: number;\n}\n\nexport type FlushPressure = (options?: FlushPressureOptions) => Promise<void>;\n\nexport interface SyncStreamEmitters {\n emitServerSyncStream: (payload?: SyncStreamPayload) => void;\n emitBroadcastSyncStream: (payload?: SyncStreamPayload) => void;\n emitStreamToTokens: (tokens: string | string[], payload?: SyncStreamPayload) => void;\n buildBroadcastFrame: (payload: SyncStreamPayload) => Record<string, unknown>;\n flushPressure: FlushPressure;\n}\n\n//? Fallback 1 MB threshold (per spec B2) — effective default is\n//? `sync.flushPressure.maxBufferedBytes` (5 MiB). Packet count = bytes / avg-packet-size.\nconst DEFAULT_THRESHOLD_BYTES = 1_048_576;\nconst AVG_PACKET_BYTES = 1024;\nconst POLL_INTERVAL_MS = 10;\n//? Cap sockets considered for worst-case pressure so a `receiver: 'all'`\n//? broadcast doesn't degrade to O(n). First 32 — see spec B2.\nconst MAX_SOCKETS_FOR_PRESSURE_SAMPLE = 32;\n\n//? Read the engine.io write-buffer length defensively — the underlying\n//? `socket.conn` and `transport` are present at runtime but `writeBuffer`\n//? is marked private in the engine.io typings. Narrow the shape via a\n//? runtime guard (vs `as unknown as` double-cast) to satisfy the\n//? boundary-helper lint rule.\ninterface EngineIoConnLike {\n writeBuffer?: { length: number };\n transport?: { writable?: boolean };\n}\n\nconst isEngineConnLike = (value: unknown): value is EngineIoConnLike =>\n typeof value === 'object' && value !== null;\n\nconst readSocketPressure = (socket: Socket): { packets: number; writable: boolean } => {\n const maybeConn: unknown = (socket as { conn?: unknown }).conn;\n if (!isEngineConnLike(maybeConn)) return { packets: 0, writable: true };\n const packets = maybeConn.writeBuffer?.length ?? 0;\n const writable = maybeConn.transport?.writable ?? true;\n return { packets, writable };\n};\n\n//? Poll-based drain — engine.io doesn't surface a per-socket `drain` event\n//? in the Socket.io public API. Poll every POLL_INTERVAL_MS until either\n//? buffer drops below threshold, transport is no longer writable (in\n//? which case waiting is pointless), or `isAborted()` returns true.\nconst waitUntilSocketDrained = async (\n socket: Socket,\n packetThreshold: number,\n isAborted: () => boolean,\n): Promise<void> => {\n let { packets, writable } = readSocketPressure(socket);\n while (writable && packets >= packetThreshold && !isAborted()) {\n await new Promise<void>((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n ({ packets, writable } = readSocketPressure(socket));\n }\n};\n\n//? SYNC-O13 / SYNC-O5 — LOCAL-ONLY. Uses `io.sockets.adapter.rooms` which\n//? is the per-process room view. In a multi-instance cluster (Redis adapter)\n//? members connected to OTHER instances are not visible here, so `flushPressure`\n//? only drains the LOCAL subset (up to MAX_SOCKETS_FOR_PRESSURE_SAMPLE sockets).\n//? Cross-instance backpressure cannot be measured via this API; callers should\n//? treat a resolved `flushPressure()` as \"local buffer cleared\" not \"all\n//? recipients drained\". For `streamTo` use cases the sampled room is the\n//? ORIGINAL `receiver`, not the token-named rooms; the caller's own socket\n//? (originatorSocket) is the primary pressure signal in that case.\nconst collectRoomSocketsForPressure = (receiver: string): Socket[] => {\n //? `{ raw: true }`: the per-instance view is the POINT here (local buffer\n //? sampling), so bypass the dev guard that exists for fan-out code.\n const io = getIoInstance({ raw: true });\n if (!io) return [];\n if (!receiver) return [];\n\n if (receiver === 'all') {\n const out: Socket[] = [];\n let i = 0;\n // eslint-disable-next-line luckystack/no-local-socket-enumeration -- deliberately per-instance: backpressure is a property of THIS process's socket buffers (see header comment)\n for (const [, sock] of io.sockets.sockets) {\n if (i >= MAX_SOCKETS_FOR_PRESSURE_SAMPLE) break;\n out.push(sock);\n i++;\n }\n return out;\n }\n\n // eslint-disable-next-line luckystack/no-local-socket-enumeration -- deliberately per-instance: backpressure is a property of THIS process's socket buffers (see header comment)\n const ids = io.sockets.adapter.rooms.get(receiver);\n if (!ids || ids.size === 0) return [];\n const out: Socket[] = [];\n let i = 0;\n for (const id of ids) {\n if (i >= MAX_SOCKETS_FOR_PRESSURE_SAMPLE) break;\n const sock = io.sockets.sockets.get(id);\n if (sock) out.push(sock);\n i++;\n }\n return out;\n};\n\ninterface BuildSyncStreamEmittersArgs {\n cb: string | undefined;\n receiver: string;\n /**\n * Session user id of the request originator (or null when anonymous). Threaded\n * through so `broadcastStream` / `flushPressure` can route the receiver room\n * through `formatRoomName` with the SAME `{ purpose: 'broadcast', userId }`\n * context the fanout in `handleSyncRequest` / `handleHttpSyncRequest` uses —\n * otherwise a non-identity `registerRoomNameFormatter` (multi-tenant) makes\n * broadcast streams target the UNFORMATTED room and miss every recipient.\n */\n userId?: string | null;\n resolvedName: string;\n emitOriginatorChunk: (payload: SyncStreamPayload) => void;\n logLabel: string;\n /**\n * AbortSignal sourced from the per-request controller in `handleSyncRequest`\n * / `handleHttpSyncRequest`. When aborted (client disconnect, explicit\n * `syncCancel`), every emit is short-circuited with a single dev-log line\n * and `flushPressure()` resolves immediately.\n */\n signal?: AbortSignal;\n /**\n * Originator socket — used to drive `flushPressure` measurement when the\n * stream targets only the originator. Optional because the HTTP/SSE\n * transport has no originator socket (SSE response writer is the sink).\n */\n originatorSocket?: Socket;\n}\n\n//? Shared between socket (`handleSyncRequest`) and HTTP/SSE\n//? (`handleHttpSyncRequest`) transports. The only divergence is the originator\n//? sink: socket transport unicasts a progress event back to the requesting\n//? socket; HTTP transport pipes the chunk through the SSE writer. Caller\n//? supplies that as `emitOriginatorChunk`. Broadcast/streamTo paths use\n//? Socket.io regardless of transport because recipients always live on sockets.\nexport const buildSyncStreamEmitters = ({\n cb,\n receiver,\n userId,\n resolvedName,\n emitOriginatorChunk,\n logLabel,\n signal,\n originatorSocket,\n}: BuildSyncStreamEmittersArgs): SyncStreamEmitters => {\n //? Route the receiver room through the core room-name formatter, matching how\n //? `handleSyncRequest` (runSyncFanout) + `handleHttpSyncRequest` (stageFanout)\n //? resolve the physical room before `fetchSockets()`. Sockets physically JOIN\n //? the FORMATTED room, so a non-identity formatter (multi-tenant key) means the\n //? RAW `receiver` is the wrong physical room. `'all'` and the empty-string\n //? sentinel are passed through unchanged (matching the fanout's `=== 'all'`\n //? branch + the broadcast/pressure guards on the raw `receiver` below).\n const physicalReceiver =\n !receiver || receiver === 'all'\n ? receiver\n : formatRoomName(receiver, { purpose: 'broadcast', userId: userId ?? null });\n //? Per-request chunk counters keyed by recipient. Scoped to this closure\n //? so they are released when the request ends — no process-lifetime leak.\n const chunkCounters = new Map<string, number>();\n const bumpChunkIndex = (recipient: string): number => {\n const next = (chunkCounters.get(recipient) ?? 0) + 1;\n chunkCounters.set(recipient, next);\n return next;\n };\n const dispatchStreamHooks = (recipient: string, chunk: unknown): void => {\n //? Fire-and-forget — stream emitters are sync and consumer hooks must\n //? not block chunk delivery. Errors inside hooks are swallowed by the\n //? hook dispatcher's own tryCatch.\n void dispatchHook('preSyncStream', { routeName: resolvedName, chunk, recipient });\n const chunkIndex = bumpChunkIndex(recipient);\n void dispatchHook('postSyncStream', { routeName: resolvedName, chunk, recipient, chunkIndex });\n };\n\n const buildBroadcastFrame = (payload: SyncStreamPayload) => ({\n ...payload,\n cb,\n fullName: resolvedName,\n status: 'stream' as const,\n });\n\n const isAborted = (): boolean => signal?.aborted === true;\n const logAbortedDrop = (kind: string): void => {\n if (shouldLogStream()) {\n getLogger().debug(`${logLabel}: ${resolvedName} ${kind} skipped — request aborted`);\n }\n };\n\n const emitServerSyncStream = (payload: SyncStreamPayload = {}) => {\n if (isAborted()) { logAbortedDrop('server stream'); return; }\n if (shouldLogStream()) {\n getLogger().debug(`${logLabel}: ${resolvedName} server stream`, { payload });\n }\n dispatchStreamHooks('originator', payload);\n emitOriginatorChunk(payload);\n };\n\n const emitBroadcastSyncStream = (payload: SyncStreamPayload = {}) => {\n if (isAborted()) { logAbortedDrop('broadcastStream'); return; }\n if (shouldLogStream()) {\n getLogger().debug(`${logLabel}: ${resolvedName} broadcastStream`, { payload });\n }\n if (!receiver) return;\n const io = getIoInstance();\n if (!io) return;\n\n dispatchStreamHooks(receiver, payload);\n\n //? `io.to(room).emit` fans the chunk out across EVERY server instance via\n //? the Redis adapter, so room members connected to a different instance get\n //? it too. Do NOT gate on `adapter.rooms.get(receiver)` — that is the\n //? per-process room view; in a multi-instance cluster it only sees locally\n //? connected members, so the previous \"size <= 1 ⇒ unicast to the lone\n //? socket\" optimization mis-fired whenever the other room members lived on\n //? another instance and collapsed broadcastStream into an originator-only\n //? stream. `streamTo` always used `io.to(...).emit` and never had this bug;\n //? this aligns broadcastStream with it.\n io.to(physicalReceiver).emit(socketEventNames.sync, buildBroadcastFrame(payload));\n };\n\n const emitStreamToTokens = (\n tokens: string | string[],\n payload: SyncStreamPayload = {},\n ) => {\n if (isAborted()) { logAbortedDrop('streamTo'); return; }\n const list = Array.isArray(tokens) ? tokens : [tokens];\n const filtered = list.filter((t): t is string => typeof t === 'string' && t.length > 0);\n if (filtered.length === 0) return;\n if (shouldLogStream()) {\n //? Redact the raw bearer session tokens before they reach the stream\n //? debug log — a verbatim token in logs is a usable credential. The\n //? 4-char prefix still correlates log lines.\n getLogger().debug(`${logLabel}: ${resolvedName} streamTo`, { tokens: redactTokens(filtered), payload });\n }\n const io = getIoInstance();\n if (!io) return;\n //? SYNC-N8 — hooks fire before `io.to(tokens).emit()` which is a cross-instance\n //? Redis broadcast; there is no local way to know whether any socket actually\n //? received the frame (the remote instance may have the token-holder). Hooks\n //? are therefore fire-and-forget observers, not delivery confirmations.\n for (const recipient of filtered) {\n dispatchStreamHooks(recipient, payload);\n }\n const frame = buildBroadcastFrame(payload);\n io.to(filtered).emit(socketEventNames.sync, frame);\n };\n\n //? Backpressure helper. Resolves once the worst-case pending write-buffer\n //? across the affected sockets drops below the configured threshold. Used\n //? opt-in by handlers streaming many small chunks (LLM tokens, telemetry).\n //?\n //? Sockets considered (in order of preference):\n //? 1. Originator socket (if provided) — covers `stream(payload)`.\n //? 2. Room sockets for `receiver` (up to 32) — covers `broadcastStream` / `streamTo`.\n //? If neither is available we return immediately — there's nothing to\n //? measure pressure on (e.g. HTTP/SSE only, empty room).\n const flushPressure: FlushPressure = async ({ thresholdBytes } = {}) => {\n if (isAborted()) return;\n //? SYNC-N1 — honour `sync.flushPressure.maxBufferedBytes` from projectConfig\n //? as the fallback so consumer tuning is not silently ignored. Caller-supplied\n //? `thresholdBytes` still wins; the hard-coded DEFAULT_THRESHOLD_BYTES is the\n //? last resort when config is not yet registered (early-boot / test context).\n const configuredBytes = getProjectConfig().sync.flushPressure.maxBufferedBytes;\n const effectiveThresholdBytes = typeof thresholdBytes === 'number' && thresholdBytes > 0\n ? thresholdBytes\n : (typeof configuredBytes === 'number' && configuredBytes > 0 ? configuredBytes : DEFAULT_THRESHOLD_BYTES);\n const packetThreshold = Math.max(1, Math.ceil(effectiveThresholdBytes / AVG_PACKET_BYTES));\n\n const targets: Socket[] = [];\n if (originatorSocket) targets.push(originatorSocket);\n for (const sock of collectRoomSocketsForPressure(physicalReceiver)) {\n //? Avoid duplicating the originator if it's also in the receiver room.\n if (sock !== originatorSocket) targets.push(sock);\n }\n if (targets.length === 0) return;\n\n //? Wait on every target in parallel — worst-case latency wins. Abort\n //? mid-wait short-circuits via `isAborted()` check inside the loop body.\n await Promise.all(targets.map((sock) => waitUntilSocketDrained(sock, packetThreshold, isAborted)));\n };\n\n return {\n emitServerSyncStream,\n emitBroadcastSyncStream,\n emitStreamToTokens,\n buildBroadcastFrame,\n flushPressure,\n };\n};\n","//? Logging-flag accessors shared across the SERVER-side sync transports\n//? (`handleSyncRequest`, `handleHttpSyncRequest`) + `streamEmitters` (CC-5).\n//? Each reads the live `getProjectConfig().logging.*` at call time — never\n//? cached — so a config swap (tests, hot-reload) is picked up immediately.\n//? Previously `shouldLogDev` / `shouldLogStream` were redefined in both\n//? handlers and `streamEmitters.ts`.\n//?\n//? NOTE: imports from the server `@luckystack/core` barrel, so this module is\n//? server-only. The client `syncRequest.ts` keeps its own flag lambdas\n//? (it imports from the browser-safe `@luckystack/core/client` subpath and\n//? must not pull the server barrel into the Vite client bundle).\n\nimport { getProjectConfig } from '@luckystack/core';\n\nexport const shouldLogDev = (): boolean => getProjectConfig().logging.devLogs;\nexport const shouldLogStream = (): boolean => getProjectConfig().logging.stream;\n","//? SYNC-17 — token redaction for logs + error-tracker context.\n//?\n//? Raw session tokens are bearer credentials: anyone holding one can act as the\n//? session. They must never be persisted verbatim into the error tracker\n//? (`tryCatch` context → `captureException`) or stream debug logs, where they\n//? defeat HttpOnly-cookie mode. This helper truncates a token to a short,\n//? non-reversible prefix that is still useful for correlating log lines /\n//? error events without exposing a usable credential.\n\n//? 4 chars is sufficient for log-line correlation while preventing partial\n//? brute-force of low-entropy tokens (audit finding SYNC-medium-5).\nconst VISIBLE_PREFIX = 4;\n\n/**\n * Truncate a session token to `<first 4 chars>…` for safe logging. Returns the\n * value unchanged when it is null/empty (nothing to redact) or already shorter\n * than the visible prefix.\n */\nexport const redactToken = (token: string | null): string | null => {\n if (!token) return token;\n if (token.length <= VISIBLE_PREFIX) return token;\n return `${token.slice(0, VISIBLE_PREFIX)}…`;\n};\n\n/**\n * Redact a list of tokens (e.g. the `streamTo` recipient list) for logging.\n */\nexport const redactTokens = (tokens: readonly string[]): string[] =>\n tokens.map((t) => redactToken(t) ?? t);\n","//? Shared error-envelope builders for the sync transports. Both\n//? `handleSyncRequest` (socket) and `handleHttpSyncRequest` (HTTP/SSE)\n//? previously hand-rolled an identical `buildSyncError` closure that did\n//? normalize → envelope → applyErrorFormatter, plus a duplicate\n//? `ensureSyncErrorShape`. Centralizing them removes the duplication AND the\n//? `as unknown as` double-casts: `applyErrorFormatter` is now generic over the\n//? envelope type (see `@luckystack/core` errorFormatterRegistry), so a typed\n//? envelope flows in and the SAME type flows out — no boundary cast required.\n\nimport {\n applyErrorFormatter,\n normalizeErrorResponse,\n type ErrorFormatter,\n} from '@luckystack/core';\nimport type { SyncErrorEnvelopeInput } from './syncTypes';\n\n//? The post-normalization envelope. `applyErrorFormatter` is generic over this\n//? shape, so the formatted result keeps the same type — both sync handlers can\n//? assign it directly to their `RuntimeErrorResponse` / `HttpSyncResponse`\n//? return types without casting.\nexport interface FormattedSyncErrorEnvelope {\n status: 'error';\n message: string;\n errorCode: string;\n errorParams?: { key: string; value: string | number | boolean }[];\n httpStatus?: number;\n [key: string]: unknown;\n}\n\nexport interface BuildFormattedErrorArgs {\n response: SyncErrorEnvelopeInput;\n preferred?: string | null;\n userLanguage?: string | null;\n routeName: string | undefined;\n transport: 'socket' | 'http';\n userId?: string | null;\n perRouteFormatter?: ErrorFormatter | undefined | null;\n}\n\n/**\n * Normalize an error envelope (i18n message + envelope shape), then run it\n * through the per-route → global → identity formatter chain. Transport\n * handlers pass the same logical inputs; only `transport`, `routeName`, and\n * the per-route formatter differ. Returns a typed, formatted error envelope.\n */\nexport const buildFormattedError = ({\n response,\n preferred,\n userLanguage,\n routeName,\n transport,\n userId,\n perRouteFormatter,\n}: BuildFormattedErrorArgs): FormattedSyncErrorEnvelope => {\n const normalized = normalizeErrorResponse({\n response,\n preferredLocale: preferred,\n userLanguage,\n });\n\n const baseEnvelope: FormattedSyncErrorEnvelope = {\n status: 'error',\n message: normalized.message,\n errorCode: normalized.errorCode,\n errorParams: normalized.errorParams,\n httpStatus: normalized.httpStatus,\n };\n\n return applyErrorFormatter({\n response: baseEnvelope,\n routeName: routeName ?? 'sync/unknown',\n transport,\n userId,\n perRouteFormatter,\n });\n};\n\n/**\n * Guarantee a client-rejection envelope always carries a non-empty\n * `errorCode`, falling back to `sync.clientRejected`. Shared by both\n * transports' per-recipient `_client` error path.\n */\nexport const ensureSyncErrorShape = (\n response: SyncErrorEnvelopeInput,\n): SyncErrorEnvelopeInput => {\n if (typeof response.errorCode === 'string' && response.errorCode.trim().length > 0) {\n return response;\n }\n return { ...response, errorCode: 'sync.clientRejected' };\n};\n","//? Per-recipient `_client` dispatch — shared by both sync transports.\n//?\n//? `handleSyncRequest` (socket) and `handleHttpSyncRequest` (HTTP/SSE)\n//? previously inlined an identical ~70-line loop body that, for one recipient\n//? socket, ran the route's optional `_client_v{N}` handler, normalized its\n//? result, and emitted the per-recipient `sync` envelope (stream / error /\n//? success / server-only-success). The two copies differed only in:\n//?\n//? - the `cb` value carried back to the client (raw `cb` over sockets,\n//? `callbackName` over HTTP),\n//? - the accept-/x-language header preference ORDER used to localize a\n//? per-recipient error (socket prefers `x-language`; HTTP prefers\n//? `accept-language` — preserved verbatim here), and\n//? - the `handler` / log-label strings used for tryCatch context + dev logs.\n//?\n//? Those are now explicit parameters, so the loop body itself is single-source.\n//? Behaviour (emit shapes, ordering, continue-on-error) is identical to the\n//? previous inlined copies.\n\nimport { tryCatch, socketEventNames, getLogger } from '@luckystack/core';\nimport type { RuntimeSyncClientHandler, SyncStreamPayload, SyncErrorEnvelopeInput } from './syncTypes';\nimport { ensureSyncErrorShape } from './errorBuilders';\nimport { redactToken } from './redactToken';\n\n//? Minimal surface of the per-recipient socket the fanout uses. Both\n//? `RemoteSocket` (cross-instance, via the Redis adapter) and a plain local\n//? `Socket` satisfy it, so the helper works for whichever `fetchSockets()`\n//? returns. `emit` is declared method-style (bivariant params) and returns\n//? `unknown` so socket.io's overloaded `emit(): boolean` is assignable.\ninterface FanoutRecipientSocket {\n emit(event: string, ...args: unknown[]): unknown;\n handshake: { headers: Record<string, string | string[] | undefined> };\n}\n\nexport interface ProcessClientSyncForRecipientArgs<TError extends object> {\n tempSocket: FanoutRecipientSocket;\n tempToken: string | null;\n clientSyncHandler: RuntimeSyncClientHandler;\n data: Record<string, unknown>;\n functionsObject: Record<string, unknown>;\n serverOutput: unknown;\n receiver: string;\n resolvedName: string;\n //? `cb` value echoed back to the recipient. Socket transport uses the raw\n //? client `cb`; HTTP transport uses the derived `callbackName`.\n callbackKey: string;\n //? `'socket' | 'http'` — feeds the tryCatch context + chooses the header\n //? preference order for per-recipient error localization.\n transport: 'socket' | 'http';\n handlerName: 'handleSyncRequest' | 'handleHttpSyncRequest';\n logLabel: 'sync' | 'http sync';\n shouldLogDev: () => boolean;\n shouldLogStream: () => boolean;\n buildSyncError: (args: {\n response: SyncErrorEnvelopeInput;\n preferred?: string | null;\n userLanguage?: string | null;\n }) => TError;\n //? Resolves a recipient's preferred locale from its handshake headers,\n //? honoring the transport-specific header preference order.\n resolvePreferredLocale: (headers: Record<string, string | string[] | undefined>) => string | null | undefined;\n sourceUserId?: string;\n}\n\n/**\n * Run the optional `_client` handler for ONE recipient socket and emit the\n * per-recipient `sync` envelope. When the route has no `_client` file the\n * caller emits the server-only success envelope instead (kept at the call site\n * because it does not run the handler). Behaviour-identical to the previously\n * inlined loop body in both transports.\n */\nexport const processClientSyncForRecipient = async <TError extends object>({\n tempSocket,\n tempToken,\n clientSyncHandler,\n data,\n functionsObject,\n serverOutput,\n receiver,\n resolvedName,\n callbackKey,\n transport,\n handlerName,\n logLabel,\n shouldLogDev,\n shouldLogStream,\n buildSyncError,\n resolvePreferredLocale,\n sourceUserId,\n}: ProcessClientSyncForRecipientArgs<TError>): Promise<void> => {\n const emitClientSyncStream = (payload: SyncStreamPayload = {}) => {\n if (shouldLogStream()) {\n getLogger().debug(`${logLabel}: ${resolvedName} client stream`, { payload });\n }\n\n tempSocket.emit(socketEventNames.sync, {\n ...payload,\n cb: callbackKey,\n fullName: resolvedName,\n status: 'stream',\n });\n };\n\n //? SYNC-O14 — the raw `tempToken` is passed to the `_client` handler by design:\n //? `_client` handlers receive it specifically so they can call\n //? `functions.session.getSession(token)` to look up the RECIPIENT's session\n //? without a server-side session store hit from the fanout loop. The token is\n //? NOT forwarded to the error-tracker context — `targetToken` below uses\n //? `redactToken(tempToken)` (SYNC-N2 fix).\n const [clientSyncError, clientSyncResult] = await tryCatch(\n async () => await clientSyncHandler({ clientInput: data, token: tempToken, functions: functionsObject, serverOutput, roomCode: receiver, stream: emitClientSyncStream }),\n undefined,\n {\n handler: handlerName,\n sync: resolvedName,\n stage: 'client',\n sourceUserId,\n //? Redact the raw bearer session token before it lands in the\n //? error-tracker context (`captureException`) — a verbatim token there is\n //? a usable credential (defeats HttpOnly-cookie mode). The 4-char prefix\n //? still correlates error events.\n targetToken: redactToken(tempToken),\n receiver,\n transport,\n },\n );\n const preferred = resolvePreferredLocale(tempSocket.handshake.headers);\n if (clientSyncError) {\n tempSocket.emit(socketEventNames.sync, {\n cb: callbackKey,\n fullName: resolvedName,\n ...buildSyncError({\n response: { status: 'error', errorCode: 'sync.clientExecutionFailed' },\n preferred,\n }),\n });\n return;\n }\n if (clientSyncResult?.status === 'error') {\n tempSocket.emit(socketEventNames.sync, {\n cb: callbackKey,\n fullName: resolvedName,\n ...buildSyncError({\n response: ensureSyncErrorShape(clientSyncResult),\n preferred,\n }),\n });\n return;\n }\n if (clientSyncResult?.status !== 'success') {\n tempSocket.emit(socketEventNames.sync, {\n cb: callbackKey,\n fullName: resolvedName,\n ...buildSyncError({\n response: { status: 'error', errorCode: 'sync.invalidClientResponse' },\n preferred,\n }),\n });\n return;\n }\n\n const result = {\n cb: callbackKey,\n fullName: resolvedName,\n serverOutput,\n clientOutput: clientSyncResult,\n // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- an empty message should fall back to the default too\n message: clientSyncResult.message || `${resolvedName} sync success`,\n status: 'success',\n };\n if (shouldLogDev()) {\n getLogger().debug(`${logLabel}: ${resolvedName} client success`, { result });\n }\n tempSocket.emit(socketEventNames.sync, result);\n};\n","//? Per-route input-validation toggle for sync `_server` handlers. Mirrors the\n//? API package's `resolveValidationMode` (socketValidationStage.ts) so both\n//? transports interpret the `validation` export identically:\n//?\n//? - `'relaxed'` or `{ input: 'skip' }` → skip runtime input validation\n//? entirely. Useful for routes whose payload shape can't reasonably be\n//? modelled in TypeScript (third-party webhook fan-in, dynamic blobs).\n//? - `'strict'`, `{ input: 'strict' }`, or omitted → validate (default).\n//?\n//? Before this existed, `RuntimeSyncServerEntry.validation` was declared,\n//? generated, and documented but never read — both sync handlers always\n//? validated, so the documented escape hatch silently did nothing (QUA-044).\n\nimport type { RuntimeSyncServerEntry } from './syncTypes';\n\nexport const resolveSyncValidationMode = (\n validation: RuntimeSyncServerEntry['validation'],\n): 'strict' | 'relaxed' => {\n if (!validation) return 'strict';\n //? FAIL CLOSED on an unrecognized value. Only the exact string `'relaxed'`\n //? (or the object form `{ input: 'skip' }`) skips validation; ANY other value\n //? — a typo like `'Strict'`/`'on'`, or a stray string the generator emitted —\n //? falls back to `'strict'` (validate). Returning the raw string verbatim\n //? meant a typo silently DISABLED input validation (it failed the caller's\n //? `=== 'strict'` test and skipped), a fail-open footgun.\n if (typeof validation === 'string') {\n return validation === 'relaxed' ? 'relaxed' : 'strict';\n }\n return validation.input === 'skip' ? 'relaxed' : 'strict';\n};\n","//? SYNC-07 — default receiver authorization, shared by both sync transports.\n//?\n//? Historically a client could name ANY `receiver` (a room code, or the\n//? cluster-wide `'all'` broadcast) and the framework fanned out regardless of\n//? whether the requester had actually joined that room — `preSyncAuthorize` was\n//? the only (opt-in, undocumented-as-required) gate. The core config keys\n//? `sync.allowClientReceiverAll` / `sync.requireRoomMembership` add\n//? framework-level defaults; this pure helper resolves the decision so the\n//? socket + HTTP handlers stay single-source and the rule is unit-testable.\n//?\n//? Both flags default to today's permissive behavior (`allowClientReceiverAll:\n//? true`, `requireRoomMembership: false`) so a missing key changes nothing.\n\n/** Decision returned by {@link authorizeSyncReceiver}. */\nexport type ReceiverAuthDecision =\n | { allowed: true }\n | { allowed: false; errorCode: 'sync.receiverNotAllowed' | 'sync.notRoomMember' };\n\nexport interface AuthorizeSyncReceiverInput {\n /** The (already-trimmed, non-empty) receiver the client requested. */\n receiver: string;\n /** `sync.allowClientReceiverAll` from project config. */\n allowClientReceiverAll: boolean;\n /** `sync.requireRoomMembership` from project config. */\n requireRoomMembership: boolean;\n /**\n * Membership predicate for the requested room. Pass a function that reports\n * whether the requester has actually joined `receiver` — on the socket\n * transport this is `socket.rooms.has(receiver)`; on HTTP/SSE (no originator\n * socket) derive it from the session's persisted `roomCodes`. Pass `null`\n * ONLY when membership genuinely cannot be determined for this requester\n * (e.g. an anonymous HTTP caller with no session). When `null` and\n * `requireRoomMembership` is true, this helper FAILS CLOSED (rejects) rather\n * than silently delegating the security default to the opt-in\n * `preSyncAuthorize` hook.\n */\n isMember: (() => boolean) | null;\n}\n\n/**\n * Resolve whether a client may target `receiver` for a sync fanout under the\n * configured default policy. Returns `{ allowed: true }` when permitted, or a\n * specific generic error code when rejected. The `'all'` check runs first\n * (cluster-wide broadcasts are the riskiest), then room-membership.\n */\nexport const authorizeSyncReceiver = ({\n receiver,\n allowClientReceiverAll,\n requireRoomMembership,\n isMember,\n}: AuthorizeSyncReceiverInput): ReceiverAuthDecision => {\n if (receiver === 'all' && !allowClientReceiverAll) {\n return { allowed: false, errorCode: 'sync.receiverNotAllowed' };\n }\n\n //? `'all'` is never a \"joined room\", so membership only gates concrete room\n //? codes. When `requireRoomMembership` is on we FAIL CLOSED: a known\n //? non-member is rejected, AND an UNDETERMINABLE membership (`isMember ===\n //? null`, e.g. an anonymous HTTP caller) is also rejected — previously the\n //? `null` case silently passed, so a consumer who set `requireRoomMembership:\n //? true` was protected on websockets but BYPASSED over the HTTP/SSE fallback\n //? (any `receiver`). The security default must not be silently delegated to\n //? the opt-in `preSyncAuthorize` hook.\n if (requireRoomMembership && receiver !== 'all' && !isMember?.()) {\n return { allowed: false, errorCode: 'sync.notRoomMember' };\n }\n\n return { allowed: true };\n};\n","//? SYNC-20 — targeted disables replacing the former blanket `/* eslint-disable */`.\n//? Same rationale as the socket handler: validated-string template interpolation,\n//? intentional `||` empty-string fallthrough, runtime `?.` guards on runtime-map\n//? values. (The former `user!` assertion at the `validateRequest` call site was\n//? removed once core made `validateRequest` null-safe — CORE-06.)\n/* eslint-disable @typescript-eslint/no-unnecessary-condition, @typescript-eslint/restrict-template-expressions, @typescript-eslint/prefer-nullish-coalescing, @typescript-eslint/no-non-null-assertion, eqeqeq */\nimport type { BaseSessionLayout as SessionLayout, ErrorFormatter, PostSyncFanoutPayload, PostSyncExecutePayload, RoomSocket } from '@luckystack/core';\nimport {\n readSession,\n getProjectConfig,\n getRuntimeSyncMaps as getRuntimeSyncMapsFromSource,\n validateRequest,\n extractTokenFromSocket,\n formatRoomName,\n getIoInstance,\n tryCatch,\n parseTransportRouteName,\n checkRateLimit,\n socketEventNames,\n validateInputByType,\n dispatchHook,\n getLogger,\n runWithErrorTrackerIdentityScope,\n setCurrentErrorTrackerIdentity,\n isLoopbackIp,\n extractLanguageFromHeader,\n isProductionRuntime,\n} from '@luckystack/core';\n\n\nimport { buildSyncStreamEmitters } from './_shared/streamEmitters';\nimport type {\n RuntimeSyncServerEntry,\n RuntimeSyncClientHandler,\n SyncStreamPayload,\n SyncErrorEnvelopeInput,\n} from './_shared/syncTypes';\nimport { shouldLogDev, shouldLogStream } from './_shared/logFlags';\nimport { buildFormattedError } from './_shared/errorBuilders';\nimport { processClientSyncForRecipient } from './_shared/clientFanout';\nimport { resolveSyncValidationMode } from './_shared/validationMode';\nimport { authorizeSyncReceiver } from './_shared/receiverAuth';\n\ninterface HttpSyncRequestParams {\n name: string;\n cb?: string;\n data: Record<string, unknown>;\n receiver: string;\n ignoreSelf?: boolean;\n token: string | null;\n requesterIp?: string;\n xLanguageHeader?: string | string[];\n acceptLanguageHeader?: string | string[];\n stream?: (payload: HttpSyncStreamEvent) => void;\n /**\n * Optional AbortSignal. The HTTP server (`@luckystack/server`) wires this\n * to `req.on('close', ...)` so a closed SSE connection aborts in-flight\n * stream emits. Sync handlers receive it as `abortSignal` in params.\n */\n abortSignal?: AbortSignal;\n}\n\ninterface HttpSyncResponse {\n status: 'success' | 'error';\n message: string;\n //? S22 — transport-parity envelope. The Socket.io ack (`handleSyncRequest`)\n //? is the CANONICAL shape: `{ status, message, result: serverOutput }`. The\n //? HTTP/SSE fallback previously FLATTENED `serverOutput` to the top level\n //? (`{ ...serverOutput, status, message }`), so an HTTP caller saw the route\n //? fields hoisted while a socket caller saw them nested under `result`. Both\n //? transports now nest under `result`; `errorCode`/`errorParams`/`httpStatus`\n //? remain on the error envelope only.\n result?: unknown;\n errorCode?: string;\n errorParams?: { key: string; value: string | number | boolean; }[];\n httpStatus?: number;\n}\n\ntype HttpSyncErrorBuilder = (args: {\n response: SyncErrorEnvelopeInput;\n preferred?: string | null;\n userLanguage?: string | null;\n }) => HttpSyncResponse;\n\n//? Returns an HttpSyncResponse when a rate limit was hit (caller should\n//? return it directly), or null when both buckets passed.\nconst applyHttpSyncRateLimits = async ({\n resolvedName,\n requesterIp,\n user,\n buildSyncError,\n preferredLocale,\n routeLimit,\n}: {\n resolvedName: string;\n token: string | null;\n requesterIp: string | undefined;\n user: SessionLayout | null;\n buildSyncError: HttpSyncErrorBuilder;\n preferredLocale: string | null | undefined;\n //? SYNC-11 — per-route `rateLimit` export (parity with the socket handler).\n routeLimit: number | false | undefined;\n}): Promise<HttpSyncResponse | null> => {\n const config = getProjectConfig();\n const effectiveSyncLimit = routeLimit === undefined ? config.rateLimiting.defaultApiLimit : routeLimit;\n if (effectiveSyncLimit !== false && effectiveSyncLimit > 0) {\n //? H-TWIN with the api transport: key the per-route bucket on the VALIDATED\n //? user.id (never the token) so an authenticated abuser can't reset the bucket\n //? by re-logging-in. Anonymous callers fall back to the IP ('unknown' sentinel).\n const identityCb = config.rateLimiting.identity;\n const customIdentity = identityCb?.({ routeName: resolvedName, userId: user?.id ?? null, ip: requesterIp ?? '', transport: 'http' }) ?? null;\n //? SYNC-O11 — use 'unknown' (not 'anonymous') when requesterIp is absent,\n //? matching the global-IP-bucket sentinel on line 156. 'anonymous' collapsed\n //? all unauthenticated callers with no IP into one shared per-route bucket;\n //? 'unknown' is the established sentinel that also signals a missing IP to\n //? hook subscribers (rateLimitExceeded ip field).\n const requesterIdentity = customIdentity?.id ?? user?.id ?? (requesterIp ?? 'unknown');\n const keyPrefix = customIdentity?.scope ?? (user?.id ? 'user' : 'ip');\n const rateLimitKey = `${keyPrefix}:${requesterIdentity}:sync:${resolvedName}`;\n const { allowed, resetIn } = await checkRateLimit({\n key: rateLimitKey,\n limit: effectiveSyncLimit,\n windowMs: config.rateLimiting.windowMs,\n });\n if (!allowed) {\n void dispatchHook('rateLimitExceeded', {\n //? Parity with the API handler: an anonymous per-route bucket is IP-keyed,\n //? so the scope is `ip` (with `route` still set to mark it a per-route\n //? bucket vs the global `:sync:all` IP bucket), never `route`.\n scope: user?.id ? 'user' : 'ip',\n key: rateLimitKey,\n limit: effectiveSyncLimit,\n windowMs: config.rateLimiting.windowMs,\n count: effectiveSyncLimit + 1,\n route: resolvedName,\n userId: user?.id,\n ip: user?.id ? undefined : requesterIp,\n });\n return buildSyncError({\n response: {\n status: 'error',\n errorCode: 'sync.rateLimitExceeded',\n errorParams: [{ key: 'seconds', value: resetIn }],\n httpStatus: 429,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n }\n\n const defaultIpLimit = config.rateLimiting.defaultIpLimit;\n //? Mirror handleHttpApiRequest: skip the global per-IP abuse limit for\n //? loopback traffic in non-production (dev + the scalable test suite).\n //? Per-route limits still apply; production is unaffected.\n //? Mirror handleHttpApiRequest API-O2 fix: use isLoopbackIp() + skipLoopbackInDev\n //? config flag so the loopback check is canonical and config-gated.\n const requesterIsLoopback = config.rateLimiting.skipLoopbackInDev\n && !isProductionRuntime()\n && isLoopbackIp(requesterIp ?? '');\n if (!requesterIsLoopback && defaultIpLimit !== false && defaultIpLimit > 0) {\n const ipBucket = requesterIp ?? 'unknown';\n const ipKey = `ip:${ipBucket}:sync:all`;\n const { allowed, resetIn } = await checkRateLimit({\n key: ipKey,\n limit: defaultIpLimit,\n windowMs: config.rateLimiting.windowMs,\n });\n if (!allowed) {\n void dispatchHook('rateLimitExceeded', {\n scope: 'ip',\n key: ipKey,\n limit: defaultIpLimit,\n windowMs: config.rateLimiting.windowMs,\n count: defaultIpLimit + 1,\n ip: ipBucket,\n });\n return buildSyncError({\n response: {\n status: 'error',\n errorCode: 'sync.rateLimitExceeded',\n errorParams: [{ key: 'seconds', value: resetIn }],\n httpStatus: 429,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n }\n\n return null;\n};\n\nexport type HttpSyncStreamEvent = SyncStreamPayload;\n\n// ─── Shared context threaded through staged helpers ───────────────────────────\n\ninterface HttpSyncContext {\n name: string;\n cb: string | undefined;\n data: Record<string, unknown>;\n normalizedReceiver: string;\n ignoreSelf: boolean | undefined;\n token: string | null;\n requesterIp: string | undefined;\n stream: ((payload: HttpSyncStreamEvent) => void) | undefined;\n effectiveAbortSignal: AbortSignal;\n preferredLocale: string | null;\n user: SessionLayout | null;\n buildSyncError: HttpSyncErrorBuilder;\n}\n\n// ─── Stage 1: parse and resolve the route name ───────────────────────────────\n\n//? Returns the resolved name + callback key, or an error response when parsing\n//? fails or the route is missing from the sync maps.\nasync function stageResolveRoute(\n ctx: HttpSyncContext,\n): Promise<{ resolvedName: string; callbackName: string; error?: never } | { error: HttpSyncResponse; resolvedName?: never; callbackName?: never }> {\n const { name, cb, data, normalizedReceiver, user, buildSyncError, preferredLocale } = ctx;\n\n if (!name || typeof name !== 'string') {\n return {\n error: buildSyncError({\n response: { status: 'error', errorCode: 'sync.invalidRequest' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n //? Parity with the socket transport (handleSyncRequest's parseSyncFields, which\n //? rejects `!data || typeof data != 'object' || Array.isArray(data)`). A null /\n //? non-object / array `clientInput` slips past the HTTP route's\n //? `normalizeHttpSyncParams` coercion; `typeof null === 'object'` and\n //? `typeof [] === 'object'` mean the bare object check is insufficient. Without\n //? this a non-object would reach a `_server` handler expecting an object — and\n //? under `validation: 'relaxed'` there is no further runtime shape check. The\n //? socket path rejects it outright, so the HTTP path must too.\n if (data === null || typeof data !== 'object' || Array.isArray(data)) {\n return {\n error: buildSyncError({\n response: { status: 'error', errorCode: 'sync.invalidRequest' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n const parsedRoute = parseTransportRouteName({ value: name, prefix: 'sync' });\n if (parsedRoute.status === 'error') {\n return {\n error: buildSyncError({\n response: {\n status: 'error',\n errorCode: 'routing.invalidServiceRouteName',\n errorParams: [{ key: 'name', value: name }],\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n const resolvedName = parsedRoute.normalizedFullName;\n const callbackName = typeof cb === 'string' && cb.trim().length > 0\n ? cb.trim()\n : `${parsedRoute.serviceRoute.normalizedRouteName}/${parsedRoute.version}`;\n\n if (!normalizedReceiver) {\n return {\n error: buildSyncError({\n response: { status: 'error', errorCode: 'sync.missingReceiver' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n const { syncObject } = await getRuntimeSyncMapsFromSource();\n\n if (!syncObject[`${resolvedName}_client`] && !syncObject[`${resolvedName}_server`]) {\n return {\n error: buildSyncError({\n response: { status: 'error', errorCode: 'sync.notFound' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n //? SYNC: reject a CLIENT-ONLY route (parity with the socket handler). The\n //? `_server` file is the MANDATORY auth + input-validation gate; the entire\n //? auth+validate block below lives inside `if (serverSyncEntry)`. Without\n //? this guard a `_client`-only route would fan out fully attacker-controlled,\n //? UNVALIDATED input with NO login check — reachable by unauthenticated\n //? callers. Treat a missing `_server` as a routing error.\n if (!syncObject[`${resolvedName}_server`]) {\n if (shouldLogDev()) {\n getLogger().warn(`http sync: ${resolvedName} has a _client file but no required _server file`, { sync: resolvedName, transport: 'http' });\n }\n return {\n error: buildSyncError({\n response: { status: 'error', errorCode: 'sync.notFound' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n return { resolvedName, callbackName };\n}\n\n// ─── Stage 2: auth checks ─────────────────────────────────────────────────────\n\n//? Returns an error response when auth fails, or null when auth passes.\nfunction stageCheckAuth(\n serverSyncEntry: RuntimeSyncServerEntry,\n ctx: Pick<HttpSyncContext, 'user' | 'preferredLocale' | 'buildSyncError'>,\n): HttpSyncResponse | null {\n const { user, preferredLocale, buildSyncError } = ctx;\n const { auth } = serverSyncEntry;\n\n if (auth.login && !user?.id) {\n return buildSyncError({\n response: { status: 'error', errorCode: 'auth.required' },\n preferred: preferredLocale,\n });\n }\n\n //? SYNC-02 — guard the anonymous `additional`-only case (parity with the\n //? socket handler). A route declaring `auth.additional` but not\n //? `auth.login` would otherwise pass `user! === null` into\n //? `validateRequest` → `condition.key in null` TypeError. The body's\n //? tryCatch would catch it, but it would surface as a generic\n //? `sync.serverExecutionFailed` instead of the correct `auth.required`.\n if (auth.additional && auth.additional.length > 0 && !user) {\n return buildSyncError({\n response: { status: 'error', errorCode: 'auth.required' },\n preferred: preferredLocale,\n });\n }\n\n //? CORE-06 / SYNC-02 — `validateRequest` is now null-safe: pass the real\n //? (possibly null) session instead of the former `user!` assertion (parity\n //? with the socket handler). The anonymous-additional case is still\n //? rejected explicitly above with `auth.required`.\n const validationResult = validateRequest({ auth, user });\n if (validationResult.status === 'error') {\n return buildSyncError({\n response: {\n status: 'error',\n errorCode: validationResult.errorCode || 'auth.forbidden',\n errorParams: validationResult.errorParams,\n httpStatus: validationResult.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n\n return null;\n}\n\n// ─── Stage 3: receiver authorization ─────────────────────────────────────────\n\n//? Returns an error response when receiver auth fails, or null when it passes.\nfunction stageAuthorizeReceiver(\n resolvedName: string,\n ctx: Pick<HttpSyncContext, 'normalizedReceiver' | 'user' | 'preferredLocale' | 'buildSyncError'>,\n): HttpSyncResponse | null {\n const { normalizedReceiver, user, preferredLocale, buildSyncError } = ctx;\n const syncConfig = getProjectConfig().sync;\n\n //? SYNC-07 — default receiver authorization (parity with the socket\n //? handler). Over HTTP/SSE there is no originator socket, so membership is\n //? derived from the SESSION's persisted `roomCodes` (the same list\n //? `loadSocket` re-joins on connect). This closes the bypass where a\n //? consumer who set `requireRoomMembership: true` was protected on\n //? websockets but NOT over the HTTP fallback. When there is no session\n //? (anonymous caller) membership is undeterminable → `isMember: null`, and\n //? `authorizeSyncReceiver` fails closed under `requireRoomMembership`.\n const receiverAuth = authorizeSyncReceiver({\n receiver: normalizedReceiver,\n allowClientReceiverAll: syncConfig.allowClientReceiverAll,\n requireRoomMembership: syncConfig.requireRoomMembership,\n //? A session is ALWAYS an implicit member of its OWN token-room: on the socket\n //? transport `loadSocket` auto-joins `socket.join(token)` on connect, so the\n //? socket path's `socket.rooms.has(token)` is true for the caller's own token.\n //? The HTTP path derives membership from persisted `roomCodes`, which never\n //? contains the token-room — so without this self-token allowance a client\n //? could stream to its own session over websockets but NOT over the HTTP\n //? fallback (`sync.notRoomMember`). Targeting your OWN token is safe (you own\n //? it) and grants no access to anyone else's room. Keeps the two transports\n //? symmetric under `requireRoomMembership`.\n isMember: user ? () => normalizedReceiver === user.token || Boolean(user.roomCodes?.includes(normalizedReceiver)) : null,\n });\n\n if (!receiverAuth.allowed) {\n if (shouldLogDev()) {\n getLogger().warn(`http sync: receiver authorization failed for ${resolvedName}`, { sync: resolvedName, receiver: normalizedReceiver, errorCode: receiverAuth.errorCode, transport: 'http' });\n }\n return buildSyncError({\n response: { status: 'error', errorCode: receiverAuth.errorCode, httpStatus: 403 },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n\n return null;\n}\n\n// ─── Stage 4: authorize hooks (preSyncAuthorize / postSyncAuthorize) ──────────\n\n//? Returns an error response when preSyncAuthorize stops the request, or null\n//? when the request is allowed through.\nasync function stageRunAuthorizeHooks(\n resolvedName: string,\n ctx: Pick<HttpSyncContext, 'data' | 'normalizedReceiver' | 'user' | 'preferredLocale' | 'buildSyncError'>,\n): Promise<HttpSyncResponse | null> {\n const { data, normalizedReceiver, user, preferredLocale, buildSyncError } = ctx;\n\n //? Identity propagation hook — runs after basic auth + AuthProps check\n //? and rate-limit pass. `@luckystack/error-tracking`'s\n //? auto-instrumentation subscribes here to call `setSentryUser(user)`.\n const preAuthorizeResult = await dispatchHook('preSyncAuthorize', {\n routeName: resolvedName,\n data,\n user,\n receiver: normalizedReceiver,\n transport: 'http',\n });\n if (preAuthorizeResult.stopped) {\n return buildSyncError({\n response: {\n status: 'error',\n errorCode: preAuthorizeResult.signal.errorCode,\n httpStatus: preAuthorizeResult.signal.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n\n //? Observational mirror of `preSyncAuthorize` (parity with the socket\n //? handler). Fires after the request passes auth + custom policy; lets\n //? audit-log / metrics subscribers record successful authorizations over\n //? the HTTP/SSE transport too. Stop signals are ignored (post-decision).\n void dispatchHook('postSyncAuthorize', {\n routeName: resolvedName,\n data,\n user,\n receiver: normalizedReceiver,\n transport: 'http',\n });\n\n return null;\n}\n\n// ─── Stage 6: input validation ────────────────────────────────────────────────\n\n//? Returns an error response when preSyncValidate stops or input validation\n//? fails, or null when validation passes.\nasync function stageValidateInput(\n resolvedName: string,\n serverSyncEntry: RuntimeSyncServerEntry,\n ctx: Pick<HttpSyncContext, 'data' | 'normalizedReceiver' | 'user' | 'preferredLocale' | 'buildSyncError'>,\n): Promise<HttpSyncResponse | null> {\n const { data, normalizedReceiver, user, preferredLocale, buildSyncError } = ctx;\n\n //? EXT-04 — validation-stage hooks mirroring the API pipeline + socket-sync\n //? handler. `preSyncValidate` may stop before validation; `postSyncValidate`\n //? reports the outcome.\n const preValidateResult = await dispatchHook('preSyncValidate', {\n routeName: resolvedName,\n data,\n user,\n receiver: normalizedReceiver,\n transport: 'http',\n });\n if (preValidateResult.stopped) {\n return buildSyncError({\n response: {\n status: 'error',\n errorCode: preValidateResult.signal.errorCode,\n httpStatus: preValidateResult.signal.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n\n const { inputType, inputTypeFilePath } = serverSyncEntry;\n\n //? Per-route validation toggle (mirrors the API + socket-sync handler).\n //? `'relaxed'` / `{ input: 'skip' }` skips runtime input validation.\n if (resolveSyncValidationMode(serverSyncEntry.validation) === 'strict') {\n const inputValidation = await validateInputByType({\n typeText: inputType,\n value: data,\n rootKey: 'clientInput',\n filePath: inputTypeFilePath,\n });\n void dispatchHook('postSyncValidate', {\n routeName: resolvedName,\n data,\n user,\n receiver: normalizedReceiver,\n transport: 'http',\n validation: inputValidation.status === 'error'\n ? { status: 'error', message: inputValidation.message }\n : { status: 'success' },\n });\n if (inputValidation.status === 'error') {\n //? SYNC-04 SECURITY: do NOT echo the raw validator message back to the\n //? client (schema enumeration). The detail goes to `postSyncValidate`\n //? + the dev log only; the client receives the generic code. Mirrors\n //? the socket handler + the API package's fix.\n if (shouldLogDev()) {\n getLogger().warn(`http sync: input validation failed for ${resolvedName}`, { sync: resolvedName, message: inputValidation.message, transport: 'http' });\n }\n return buildSyncError({\n response: {\n status: 'error',\n errorCode: 'sync.invalidInputType',\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n } else {\n void dispatchHook('postSyncValidate', {\n routeName: resolvedName,\n data,\n user,\n receiver: normalizedReceiver,\n transport: 'http',\n validation: { status: 'success' },\n });\n }\n\n return null;\n}\n\n// ─── Stage 7: execute the server handler ─────────────────────────────────────\n\n//? Returns the server output object on success, or an error response on\n//? failure. The payload reference is shared so span-pinning subscribers work.\nasync function stageExecuteServer(\n resolvedName: string,\n serverSyncEntry: RuntimeSyncServerEntry,\n functionsObject: Record<string, unknown>,\n ctx: Pick<HttpSyncContext, 'data' | 'normalizedReceiver' | 'name' | 'user' | 'preferredLocale' | 'buildSyncError' | 'effectiveAbortSignal' | 'cb' | 'stream'>,\n): Promise<{ serverOutput: Record<string, unknown>; error?: never } | { error: HttpSyncResponse; serverOutput?: never }> {\n const { data, normalizedReceiver, user, preferredLocale, buildSyncError, effectiveAbortSignal, cb, stream } = ctx;\n const { main: serverMain } = serverSyncEntry;\n\n const { emitServerSyncStream, emitBroadcastSyncStream, emitStreamToTokens, flushPressure } =\n buildSyncStreamEmitters({\n cb,\n receiver: normalizedReceiver,\n userId: user?.id ?? null,\n resolvedName,\n logLabel: 'http sync',\n signal: effectiveAbortSignal,\n //? No originatorSocket for HTTP/SSE — `flushPressure` falls back\n //? to room-socket measurement only. SSE backpressure is the\n //? caller's responsibility (Node's `res.write` returns a bool).\n //? Originator chunks travel back via SSE; broadcast / targeted\n //? chunks still flow over Socket.io to recipients in the receiver room.\n emitOriginatorChunk: (payload) => {\n stream?.(payload);\n },\n });\n\n //? EXT-04 — execution-stage hooks mirroring the API pipeline. `preSyncExecute`\n //? may stop before the `_server` runs; `postSyncExecute` fires on BOTH the\n //? success AND failure paths (previously invisible to hook consumers). The\n //? single payload reference is reused so span-pinning subscribers work.\n const executePayload: PostSyncExecutePayload = {\n routeName: resolvedName,\n data,\n user,\n receiver: normalizedReceiver,\n transport: 'http',\n result: undefined,\n error: null,\n durationMs: 0,\n };\n const preExecuteResult = await dispatchHook('preSyncExecute', executePayload);\n if (preExecuteResult.stopped) {\n return {\n error: buildSyncError({\n response: {\n status: 'error',\n errorCode: preExecuteResult.signal.errorCode,\n httpStatus: preExecuteResult.signal.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n const executeStart = Date.now();\n const [serverSyncError, serverSyncResult] = await tryCatch(\n async () => await serverMain({\n clientInput: data,\n user,\n functions: functionsObject,\n roomCode: normalizedReceiver,\n stream: emitServerSyncStream,\n broadcastStream: emitBroadcastSyncStream,\n streamTo: emitStreamToTokens,\n abortSignal: effectiveAbortSignal,\n flushPressure,\n }),\n undefined,\n {\n handler: 'handleHttpSyncRequest',\n sync: resolvedName,\n stage: 'server',\n userId: user?.id,\n //? Bug fix: was `name` (the raw route-name string) — should be\n //? `normalizedReceiver` to match the field's semantics and the socket handler.\n receiver: normalizedReceiver,\n transport: 'http',\n },\n );\n executePayload.result = serverSyncResult;\n executePayload.error = serverSyncError ?? null;\n executePayload.durationMs = Date.now() - executeStart;\n await dispatchHook('postSyncExecute', executePayload);\n\n if (serverSyncError) {\n return {\n error: buildSyncError({\n response: { status: 'error', errorCode: 'sync.serverExecutionFailed' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n if (serverSyncResult?.status == 'error') {\n return {\n error: buildSyncError({\n response: serverSyncResult,\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n if (serverSyncResult?.status !== 'success') {\n return {\n error: buildSyncError({\n response: { status: 'error', errorCode: 'sync.invalidServerResponse' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n\n return { serverOutput: serverSyncResult };\n}\n\n// ─── Stage 5: resolve recipients (before anything is persisted) ──────────────\n\n//? Cross-instance recipient list (RemoteSocket[]) spanning every backend on\n//? the shared Redis adapter, so an HTTP-triggered sync still fans out to room\n//? members on other instances. Branch off the NORMALIZED receiver so\n//? authorize, branch, and fetch all key off the same value (the auth check\n//? used `normalizedReceiver`); using the raw `receiver` here diverged from the\n//? socket handler and was a latent inversion hazard. Route through the core\n//? room-name formatter (PRESENCE-1) so a non-identity\n//? `registerRoomNameFormatter` targets the same physical room sockets joined.\n//?\n//? @adr 0063\n//? Runs BEFORE `_server`, same as the socket handler (`resolveSyncRecipients`):\n//? this query can fail (an adapter `requestsTimeout`) or come back empty, and\n//? when that happened after the mutation was persisted the caller was told\n//? `error` about a change that had been saved — a retry applied it twice. Every\n//? error on this path is now a pre-commit rejection, so a retry is safe.\nasync function stageResolveRecipients(\n resolvedName: string,\n ctx: Pick<HttpSyncContext, 'normalizedReceiver' | 'user' | 'buildSyncError' | 'preferredLocale'>,\n): Promise<{ sockets: RoomSocket[]; error?: never } | { error: HttpSyncResponse; sockets?: never }> {\n const { normalizedReceiver, user, buildSyncError, preferredLocale } = ctx;\n const ioInstance = getIoInstance();\n const physicalReceiver = normalizedReceiver === 'all' ? 'all' : formatRoomName(normalizedReceiver, { purpose: 'broadcast', userId: user?.id ?? null });\n const sockets = physicalReceiver === 'all'\n ? await ioInstance!.fetchSockets()\n : await ioInstance!.in(physicalReceiver).fetchSockets();\n\n //? @adr 0058\n //? Transport parity (DEV-376): an empty room is an ERROR over HTTP too. Until\n //? 0.10.0 this path treated zero recipients as \"normal over the HTTP fallback\"\n //? and answered `success`, so every room bug — wrong room name, socket not\n //? (re)joined, a formatter mismatch between join and send — was\n //? indistinguishable from a delivered broadcast on precisely the transport\n //? built for multi-instance. Same code, same status and same position as\n //? `handleSyncRequest`: before `_server` runs, so nothing has been persisted.\n if (sockets.length === 0) {\n if (shouldLogDev()) {\n getLogger().warn('http sync: no sockets found for receiver', { receiver: normalizedReceiver, sync: resolvedName, transport: 'http' });\n }\n return {\n error: buildSyncError({\n response: { status: 'error', errorCode: 'sync.noReceiversFound', httpStatus: 404 },\n preferred: preferredLocale,\n userLanguage: user?.language,\n }),\n };\n }\n return { sockets };\n}\n\n// ─── Stage 8: fanout to room members ─────────────────────────────────────────\n\n//? Fans the serverOutput out to every recipient resolved in stage 5,\n//? respecting `ignoreSelf`, per-recipient hooks, and optional `_client` handlers.\nasync function stageFanout(\n resolvedName: string,\n callbackName: string,\n serverOutput: Record<string, unknown>,\n sockets: RoomSocket[],\n syncObject: Record<string, unknown>,\n functionsObject: Record<string, unknown>,\n ctx: Pick<HttpSyncContext, 'data' | 'normalizedReceiver' | 'token' | 'ignoreSelf' | 'user' | 'buildSyncError' | 'preferredLocale'>,\n): Promise<HttpSyncResponse | null> {\n const { data, normalizedReceiver, token, ignoreSelf, user, buildSyncError, preferredLocale } = ctx;\n\n //? @adr 0059\n //? Membership is LOGICAL over HTTP: `stageAuthorizeReceiver` accepted this\n //? request on the session's persisted `roomCodes` because there is no\n //? originator socket to test physically (see docs/ARCHITECTURE_SYNC.md,\n //? \"Room membership is transport-specific\"). So a caller can pass while none\n //? of its sockets is in the room — typical right after a reconnect that has\n //? not re-joined yet. The fan-out then goes to a room the caller is not in,\n //? and `success` does not mean \"I will receive this\". The recipient list is\n //? already in hand, so say so in dev instead of leaving it to be inferred\n //? from user behaviour.\n if (\n shouldLogDev()\n && token\n && getProjectConfig().sync.requireRoomMembership\n && normalizedReceiver !== 'all'\n && normalizedReceiver !== token\n && !sockets.some((recipient) => extractTokenFromSocket(recipient) === token)\n ) {\n getLogger().warn(\n `http sync: ${resolvedName} was authorized on the session's roomCodes, but the caller has no socket in \"${normalizedReceiver}\" — it will not receive this fan-out`,\n { sync: resolvedName, receiver: normalizedReceiver, transport: 'http' },\n );\n }\n\n //? Single payload reference reused by pre/post — span pinning in\n //? `@luckystack/error-tracking` uses WeakMap on this object.\n const fanoutPayload: PostSyncFanoutPayload = {\n routeName: resolvedName,\n data,\n user,\n receiver: normalizedReceiver,\n serverOutput,\n transport: 'http',\n recipientCount: 0,\n };\n //? Parity with the socket handler (handleSyncRequest.ts runSyncFanout): capture\n //? the hook result and bail when the hook stops the fanout.\n const preFanoutResult = await dispatchHook('preSyncFanout', fanoutPayload);\n if (preFanoutResult.stopped) {\n //? Parity with the socket handler: a preSyncFanout stop is a DENY decision,\n //? so the HTTP/SSE transport must surface it as an error response — not a\n //? silent success (which would let a deny hook be bypassed over HTTP).\n return buildSyncError({\n response: {\n status: 'error',\n errorCode: preFanoutResult.signal.errorCode,\n httpStatus: preFanoutResult.signal.httpStatus,\n },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n\n let recipientCount = 0;\n //? Yield to the event loop periodically so a giant `receiver: 'all'` fanout\n //? doesn't starve other requests (parity with the socket handler). Tunables\n //? live in projectConfig.sync. Clamp to >= 1 so a misconfigured\n //? `fanoutYieldEvery: 0` doesn't produce `n % 0 === NaN` (never truthy).\n const { fanoutYieldEvery, fanoutYieldMs } = getProjectConfig().sync;\n const yieldEvery = Math.max(1, fanoutYieldEvery);\n let fanoutIterCount = 1;\n for (const tempSocket of sockets) {\n fanoutIterCount++;\n if (fanoutIterCount % yieldEvery === 0) { await new Promise(resolve => setTimeout(resolve, fanoutYieldMs)); }\n\n const tempToken = extractTokenFromSocket(tempSocket);\n\n //? SYNC-O10 — `token &&` guard: an anonymous (token-less) originator is\n //? never matched as \"self\" (null === null is always true). Parity with\n //? the socket handler; `ignoreSelf` is a no-op for anonymous callers by design.\n if (ignoreSelf && typeof ignoreSelf === 'boolean' && token && token === tempToken) {\n continue;\n }\n\n //? SYNC-22 — per-recipient fanout hook (parity with the socket handler).\n //? A stop signal SKIPS just this recipient (loop continues; not counted).\n //? `recipientUserId` is always null (no per-recipient session read on the\n //? hot path); the recipient's TOKEN is already known here, so it is passed\n //? along and a handler that needs the user reads the session by it.\n const preRecipientResult = await dispatchHook('preSyncRecipient', {\n routeName: resolvedName,\n receiver: normalizedReceiver,\n recipientSocketId: tempSocket.id,\n recipientToken: tempToken,\n recipientUserId: null,\n serverOutput,\n });\n //? Parity with the socket handler (SYNC-O8): a stop signal with no\n //? overrideOutput skips this recipient entirely; a stop signal WITH\n //? overrideOutput sends the override in place of serverOutput.\n if (preRecipientResult.stopped && preRecipientResult.signal.overrideOutput === undefined) {\n continue;\n }\n\n const effectiveServerOutput = preRecipientResult.stopped\n ? preRecipientResult.signal.overrideOutput\n : serverOutput;\n\n //? Count every recipient the request fanned out to — including ones whose\n //? per-recipient `_client` handler later errors — matching the Socket.io\n //? handler (handleSyncRequest.ts) so `postSyncFanout` sees the same total.\n recipientCount++;\n\n if (syncObject[`${resolvedName}_client`]) {\n const clientSyncHandler = syncObject[`${resolvedName}_client`] as RuntimeSyncClientHandler;\n await processClientSyncForRecipient({\n tempSocket,\n tempToken,\n clientSyncHandler,\n data,\n functionsObject,\n serverOutput: effectiveServerOutput,\n receiver: normalizedReceiver,\n resolvedName,\n callbackKey: callbackName,\n transport: 'http',\n handlerName: 'handleHttpSyncRequest',\n logLabel: 'http sync',\n shouldLogDev,\n shouldLogStream,\n buildSyncError,\n //? HTTP transport prefers `accept-language` over `x-language`\n //? (reversed vs. the socket handler) — preserved verbatim from the\n //? previous inlined error path.\n resolvePreferredLocale: (headers) =>\n extractLanguageFromHeader(headers['accept-language'] || headers['x-language']),\n sourceUserId: user?.id,\n });\n continue;\n }\n\n tempSocket.emit(socketEventNames.sync, {\n cb: callbackName,\n fullName: resolvedName,\n serverOutput: effectiveServerOutput,\n clientOutput: {},\n message: `${resolvedName} sync success`,\n status: 'success',\n });\n }\n\n fanoutPayload.recipientCount = recipientCount;\n await dispatchHook('postSyncFanout', fanoutPayload);\n return null;\n}\n\n//? ET-02 — wrap the whole HTTP/SSE sync request in a per-request error-tracker\n//? identity scope (opened before `readSession`, the first interleaving await).\n//? The resolved session is written into the scope's ALS box the moment it\n//? resolves, so concurrent HTTP syncs with different users can't cross-attribute\n//? captures. Each request gets its own isolated box.\nexport default async function handleHttpSyncRequest(args: HttpSyncRequestParams): Promise<HttpSyncResponse> {\n return runWithErrorTrackerIdentityScope(() => handleHttpSyncRequestScoped(args));\n}\n\nasync function handleHttpSyncRequestScoped({\n name,\n cb,\n data,\n receiver,\n ignoreSelf,\n token,\n requesterIp,\n xLanguageHeader,\n acceptLanguageHeader,\n stream,\n abortSignal,\n}: HttpSyncRequestParams): Promise<HttpSyncResponse> {\n if (shouldLogDev()) {\n getLogger().debug(`http sync: ${name} called`);\n }\n\n //? B1 — HTTP/SSE transport. The caller (typically `@luckystack/server`'s\n //? SSE bridge) wires `req.on('close', ...)` to a controller and passes its\n //? signal in. If no signal was provided we build a dummy controller so\n //? `signal` is always defined for handler param shape. The dummy never\n //? aborts on its own, which preserves current behavior for callers that\n //? don't opt in.\n const effectiveAbortSignal = abortSignal ?? new AbortController().signal;\n\n const normalizedReceiver = typeof receiver === 'string' ? receiver.trim() : '';\n const preferredLocale =\n extractLanguageFromHeader(xLanguageHeader)\n || extractLanguageFromHeader(acceptLanguageHeader);\n const user = await readSession(token);\n //? ET-02 — bind the resolved session into the active per-request ALS identity\n //? box so every capture in this request attributes to this user. Identity also\n //? still flows to the legacy global via the `preSyncAuthorize` hook subscriber;\n //? the ALS read wins at capture time.\n setCurrentErrorTrackerIdentity(user?.id ? { id: user.id, email: user.email ?? undefined, username: user.name ?? undefined } : null);\n\n //? Per-route formatter ref. Mirrors the socket-sync + API handler pattern —\n //? set after the syncEntry lookup; pre-lookup errors fall through to global\n //? formatter only because there's no entry yet to read from.\n let currentRouteName: string | undefined;\n let currentPerRouteFormatter: ErrorFormatter | undefined;\n\n const buildSyncError = ({\n response,\n preferred,\n userLanguage,\n }: {\n response: SyncErrorEnvelopeInput;\n preferred?: string | null;\n userLanguage?: string | null;\n }): HttpSyncResponse => buildFormattedError({\n response,\n preferred,\n userLanguage,\n routeName: currentRouteName,\n transport: 'http',\n userId: user?.id,\n perRouteFormatter: currentPerRouteFormatter,\n });\n\n const ioInstance = getIoInstance();\n\n //? Wrap the body so the span always closes — including on an unexpected\n //? throw. tryCatch returns `[error, value]` so we can call `span.end()`\n //? in one place after the inner work resolves.\n const [bodyError, bodyResult] = await tryCatch(async () => {\n if (!ioInstance) {\n return buildSyncError({\n response: { status: 'error', errorCode: 'sync.ioUnavailable' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n\n // Build the shared context once — all stage helpers read from this.\n const ctx: HttpSyncContext = {\n name,\n cb,\n data,\n normalizedReceiver,\n ignoreSelf,\n token,\n requesterIp,\n stream,\n effectiveAbortSignal,\n preferredLocale,\n user,\n buildSyncError,\n };\n\n // Stage 1: parse and resolve the route name.\n const routeResult = await stageResolveRoute(ctx);\n if (routeResult.error) return routeResult.error;\n const { resolvedName, callbackName } = routeResult;\n currentRouteName = resolvedName;\n\n const { syncObject, functionsObject } = await getRuntimeSyncMapsFromSource();\n const serverSyncEntry = syncObject[`${resolvedName}_server`] as RuntimeSyncServerEntry | undefined;\n currentPerRouteFormatter = serverSyncEntry?.errorFormatter;\n\n // Stage 2: auth checks (only when a _server entry exists, which is always true after stage 1).\n if (serverSyncEntry) {\n const authError = stageCheckAuth(serverSyncEntry, ctx);\n if (authError) return authError;\n }\n\n // Stage 3: receiver authorization.\n const receiverError = stageAuthorizeReceiver(resolvedName, ctx);\n if (receiverError) return receiverError;\n\n //? SYNC-O4 — rate-limit runs BEFORE the consumer `preSyncAuthorize` hook\n //? so an unauthenticated (login:false) caller cannot trigger potentially-\n //? expensive DB/tenant lookups on every message with no throttle.\n const rateLimitResult = await applyHttpSyncRateLimits({\n resolvedName,\n token,\n requesterIp,\n user,\n buildSyncError,\n preferredLocale,\n routeLimit: serverSyncEntry?.rateLimit,\n });\n if (rateLimitResult) return rateLimitResult;\n\n // Stage 4: authorize hooks.\n const authorizeHookError = await stageRunAuthorizeHooks(resolvedName, ctx);\n if (authorizeHookError) return authorizeHookError;\n\n // Stage 5: resolve recipients — before the server handler persists anything.\n const recipientsResult = await stageResolveRecipients(resolvedName, ctx);\n if (recipientsResult.error) return recipientsResult.error;\n const { sockets } = recipientsResult;\n\n let serverOutput: Record<string, unknown> = {};\n if (serverSyncEntry) {\n // Stage 6: input validation.\n const validationError = await stageValidateInput(resolvedName, serverSyncEntry, ctx);\n if (validationError) return validationError;\n\n // Stage 7: execute the server handler.\n const executeResult = await stageExecuteServer(resolvedName, serverSyncEntry, functionsObject, ctx);\n if (executeResult.error) return executeResult.error;\n serverOutput = executeResult.serverOutput;\n }\n\n // Stage 8: fanout to room members.\n const fanoutError = await stageFanout(resolvedName, callbackName, serverOutput, sockets, syncObject, functionsObject, ctx);\n if (fanoutError) return fanoutError;\n\n if (shouldLogDev()) {\n getLogger().debug(`http sync: ${resolvedName} completed`);\n }\n\n //? S22 — conform to the CANONICAL Socket.io ack envelope: nest the route's\n //? `serverOutput` under `result` (was: flattened to the top level). The\n //? socket handler emits `{ status, message, result: serverOutput }`; the\n //? HTTP/SSE fallback now returns the identical shape so a consumer reading\n //? `response.result` gets the route's fields on BOTH transports. The\n //? `message` still prefers the route's own message when it supplied one,\n //? falling back to the generic success line (HttpSyncResponse requires it).\n const serverMessage = (serverOutput as { message?: unknown }).message;\n return {\n status: 'success' as const,\n message: typeof serverMessage === 'string' ? serverMessage : `${resolvedName} sync success`,\n result: serverOutput,\n };\n });\n if (bodyError) {\n getLogger().error(`http sync: ${name} threw`, bodyError, { sync: name });\n return buildSyncError({\n response: { status: 'error', errorCode: 'sync.serverExecutionFailed' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n }\n return bodyResult ?? buildSyncError({\n response: { status: 'error', errorCode: 'sync.serverExecutionFailed' },\n preferred: preferredLocale,\n userLanguage: user?.language,\n });\n}\n","import { getProjectConfig } from '@luckystack/core';\n\n//? Stream-chunk throttle. Coalesces tiny pieces of data (e.g. AI-provider\n//? tokens of 3-10 characters each) into bigger chunks before they're sent\n//? over the wire, cutting message count by 10-100x with no perceptible\n//? latency hit.\n//?\n//? Two flush triggers:\n//? - `flushAtChars` — buffered length crossed the byte threshold.\n//? - `flushEveryMs` — the throttle's internal timer fired.\n//?\n//? Whichever happens first flushes the buffer. The author calls `push(text, emit)`\n//? in the AI loop and `flush(emit)` once after the loop finishes. The `emit`\n//? argument is whichever stream callback the route is using (`stream`,\n//? `broadcastStream`, `streamTo` partial, etc.) — the throttle stays\n//? agnostic so it works with any of the three primitives.\n\nexport interface CreateStreamThrottleOptions {\n /**\n * Flush buffered text once it crosses this many characters. Default: 32.\n * Lower = more updates, more network traffic.\n * Higher = fewer updates, choppier UI.\n */\n flushAtChars?: number;\n /**\n * Flush buffered text after this many milliseconds even if the char\n * threshold hasn't been hit. Default: 50ms — fast enough that the user\n * perceives \"live typing\", slow enough that 50–100 tokens batch into a\n * single message on a fast LLM stream.\n *\n * Set to `false` to disable the timer (only flush at char threshold or\n * on explicit `flush()`).\n */\n flushEveryMs?: number | false;\n /**\n * Field name on the emitted payload that carries the buffered text.\n * Default: `'chunk'`. Override if your stream payload uses a different\n * key (e.g. `'text'`, `'delta'`).\n */\n field?: string;\n}\n\nexport interface StreamThrottle {\n /** Append text to the buffer. May trigger a flush. */\n push: (text: string, emit: (payload: Record<string, unknown>) => void) => void;\n /** Force-flush whatever is in the buffer right now. Call after the source loop ends. */\n flush: (emit: (payload: Record<string, unknown>) => void) => void;\n /** Drop the buffered text without emitting. Useful on abort. */\n reset: () => void;\n}\n\n/**\n * Build a chunk throttle for streaming use cases. Designed for LLM token\n * streams where the provider yields very small pieces (3–10 chars) and you\n * don't want to send a separate socket message for each one.\n *\n * @example\n * const throttle = createStreamThrottle({ flushEveryMs: 50, flushAtChars: 32 });\n * for await (const chunk of openaiStream) {\n * throttle.push(chunk.text, broadcastStream);\n * }\n * throttle.flush(broadcastStream);\n */\nexport const createStreamThrottle = (\n options: CreateStreamThrottleOptions = {},\n): StreamThrottle => {\n const defaults = getProjectConfig().sync.streamThrottle;\n const flushAtChars = options.flushAtChars ?? defaults.flushAtChars;\n const flushEveryMs = options.flushEveryMs ?? defaults.flushEveryMs;\n const field = options.field ?? defaults.field;\n\n let buffer = '';\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n const clearTimer = () => {\n if (timer !== null) {\n clearTimeout(timer);\n timer = null;\n }\n };\n\n const flushNow = (emit: (payload: Record<string, unknown>) => void) => {\n if (buffer.length === 0) {\n clearTimer();\n return;\n }\n const payload: Record<string, unknown> = { [field]: buffer };\n buffer = '';\n clearTimer();\n emit(payload);\n };\n\n return {\n push: (text, emit) => {\n if (!text) return;\n buffer += text;\n\n if (buffer.length >= flushAtChars) {\n flushNow(emit);\n return;\n }\n\n if (flushEveryMs !== false && timer === null) {\n timer = setTimeout(() => {\n flushNow(emit);\n }, flushEveryMs);\n //? Allow process exit even if the throttle has a pending flush.\n //? Prevents tests + short scripts from hanging waiting on a timer.\n if (typeof timer === 'object' && 'unref' in timer) {\n (timer as { unref: () => void }).unref();\n }\n }\n },\n flush: (emit) => {\n flushNow(emit);\n },\n reset: () => {\n buffer = '';\n clearTimer();\n },\n };\n};\n"],"mappings":"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","names":["getProjectConfig","formatRoomName","getIoInstance","tryCatch","socketEventNames","dispatchHook","getLogger","normalizeErrorResponse","getProjectConfig","out","i","getProjectConfig","socketEventNames","getLogger","shouldLogDev","shouldLogStream","getLogger","socketEventNames","getProjectConfig","dispatchHook","getLogger","normalizeErrorResponse","socketEventNames","formatRoomName","tryCatch","getIoInstance","readSession","getProjectConfig","validateRequest","extractTokenFromSocket","formatRoomName","getIoInstance","tryCatch","parseTransportRouteName","checkRateLimit","socketEventNames","validateInputByType","dispatchHook","getLogger","runWithErrorTrackerIdentityScope","setCurrentErrorTrackerIdentity","isLoopbackIp","extractLanguageFromHeader","isProductionRuntime","getProjectConfig","checkRateLimit","dispatchHook","isProductionRuntime","isLoopbackIp","parseTransportRouteName","getLogger","validateRequest","validateInputByType","tryCatch","getIoInstance","formatRoomName","extractTokenFromSocket","extractLanguageFromHeader","socketEventNames","runWithErrorTrackerIdentityScope","readSession","setCurrentErrorTrackerIdentity","getProjectConfig"]}
|