@luckystack/sync 0.9.2 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,22 @@ All notable changes to `@luckystack/sync` are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [
|
|
8
|
+
## [0.10.0] - 2026-09-03
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **BREAKING (behaviour): the HTTP / `routed-http` fan-out rejects an empty room with `sync.noReceiversFound` (404)**, exactly like the socket transport and at the same position. Until now the HTTP path answered `success` with zero recipients, so a wrong room name, a socket that had not re-joined, or a join/send formatter mismatch was indistinguishable from a delivered broadcast — on precisely the transport built for multi-instance (three consumer bugs stayed invisible for months, DEV-376). A caller that relied on HTTP-success for an empty room must handle the code the socket transport already produced. Where that position sits relative to `_server` is the next entry.
|
|
13
|
+
- **BREAKING (behaviour): recipients are resolved BEFORE the `_server` handler runs, on both transports.** The cross-instance `fetchSockets()` lookup moved from after execution to right before input validation. It can fail on its own — the Redis adapter's request timeout when an instance on the same adapter key does not answer (a dev laptop tunnelled into the staging Redis, asleep) — and it can come back empty; when either happened after `_server` had persisted its mutation, the originator was told `error` about a change that had been saved, and a retry applied it twice. Now `sync.noReceiversFound` and a lookup-failure `sync.serverExecutionFailed` are pre-commit rejections: nothing was persisted, a retry is safe. Behaviour change for a UI that read `sync.noReceiversFound` as "saved, but nobody was listening" — that reading is now wrong. The recipient snapshot is taken one handler-execution earlier, so a socket that joins the room while `_server` runs misses that one fan-out.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **`SYNC_ERROR_CODES` / `SyncErrorCode`** exported from `@luckystack/sync` AND `@luckystack/sync/client`: the canonical list of every framework-emitted `sync.*` error code (both transports, the `_client` stage, and the server's HTTP sync route). Write a parity test of your locale files against it instead of retyping `docs/error-states.md` — `translate()` renders a missing key as the raw key. A framework test keeps the list equal to the source literals and the scaffold locales in parity with it.
|
|
18
|
+
- **Dev warning on `routed-http` when membership passed on the session's `roomCodes` but the caller has no socket in the target room.** Over HTTP membership is LOGICAL (there is no originator socket to test), so a successful `syncRequest` does not prove you are in the room or will receive the fan-out; the recipient list is already in hand, so the handler now says so in dev. The asymmetry itself is deliberate and documented in `docs/ARCHITECTURE_SYNC.md`.
|
|
19
|
+
- `preSyncRecipient` receives `recipientToken` on both transports (see `@luckystack/core`).
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- `docs/error-states.md` lacked `sync.receiverNotAllowed` and `sync.notRoomMember` (403, BOTH transports) and claimed a built-in i18n catalog that does not exist. `docs/room-fanout.md` still described the fan-out as per-instance (`adapter.rooms`) and advised sticky sessions, while the code has used cross-instance `fetchSockets()` for several releases — `_client` handlers DO run for remote recipients. That doc taught two consumer bugs.
|
|
9
24
|
|
|
10
25
|
## [0.8.4] - 2026-08-17
|
|
11
26
|
|
package/CLAUDE.md
CHANGED
|
@@ -32,6 +32,7 @@ Real-time sync transport for LuckyStack. Provides type-safe, room-based fanout o
|
|
|
32
32
|
| `handleHttpSyncRequest(req, res)` | HTTP/SSE fallback for sync requests when websockets are blocked. | → `docs/sync-request.md` |
|
|
33
33
|
| `createStreamThrottle({ flushEveryMs?, flushAtChars?, field? })` | Coalesce tiny stream pieces (LLM tokens) into bigger chunks before emit. | → `docs/streaming.md` |
|
|
34
34
|
| Type: `HttpSyncStreamEvent` | SSE event shape emitted by the HTTP fallback. | → `docs/sync-request.md` |
|
|
35
|
+
| `SYNC_ERROR_CODES` (readonly array) + type `SyncErrorCode` | Canonical list of every `sync.*` error code the framework can emit (both transports + the server's HTTP sync route). Also exported from `/client`. Write a locale-parity test against it instead of retyping a doc table. | → `docs/error-states.md` |
|
|
35
36
|
| Type: `StreamThrottle` / `CreateStreamThrottleOptions` | Throttle handle + options. | → `docs/streaming.md` |
|
|
36
37
|
|
|
37
38
|
### Client entry (`@luckystack/sync/client`)
|
|
@@ -44,6 +45,7 @@ Real-time sync transport for LuckyStack. Provides type-safe, room-based fanout o
|
|
|
44
45
|
| `initSyncRequest({ setSocketStatus, sessionRef })` | One-time wiring of socket lifecycle handlers (connect/disconnect/reconnectAttempt/userAfk/userBack/connectError) into the socket-status provider. | → `docs/callback-registration.md` |
|
|
45
46
|
| Type: `SyncRequestStreamEvent<T>` | Payload shape passed to `onStream` on the originator side. | → `docs/streaming.md` |
|
|
46
47
|
| Type: `SyncRouteStreamEvent<T>` | Payload shape passed to `upsertSyncEventStreamCallback` on recipients. | → `docs/streaming.md` |
|
|
48
|
+
| `SYNC_ERROR_CODES` + type `SyncErrorCode` | Same canonical `sync.*` code list as the server barrel, for client-side locale parity tests and exhaustive `switch`es. | → `docs/error-states.md` |
|
|
47
49
|
|
|
48
50
|
### Streaming primitives (received inside `_server_v{N}.ts` params)
|
|
49
51
|
|
|
@@ -66,7 +68,7 @@ Real-time sync transport for LuckyStack. Provides type-safe, room-based fanout o
|
|
|
66
68
|
| `preSyncExecute` | Before the `_server` handler runs. Stop to short-circuit (mirrors `preApiExecute`). | → `docs/server-vs-client-handlers.md` |
|
|
67
69
|
| `postSyncExecute` | After `_server` resolves OR throws, carrying `{ result, error, durationMs }`. Fires on the FAILURE path too (mirrors `postApiExecute`). | → `docs/server-vs-client-handlers.md` |
|
|
68
70
|
| `preSyncFanout` | After `_server` runs, before any recipient receives the payload. Stop to abort fanout. | → `docs/room-fanout.md` |
|
|
69
|
-
| `preSyncRecipient` | Per recipient, before that ONE socket receives the payload. Carries `{ routeName, receiver, recipientSocketId, recipientUserId, serverOutput }`. A stop signal SKIPS just that recipient (the loop continues; it is not counted as delivered) — it does NOT abort the whole fanout. `recipientUserId` is null
|
|
71
|
+
| `preSyncRecipient` | Per recipient (both transports, remote recipients included), before that ONE socket receives the payload. Carries `{ routeName, receiver, recipientSocketId, recipientToken, recipientUserId, serverOutput }`. A stop signal SKIPS just that recipient (the loop continues; it is not counted as delivered) — it does NOT abort the whole fanout; a stop WITH `overrideOutput` delivers the override instead. `recipientToken` is the recipient's session token (`null` for an anonymous socket); `recipientUserId` is ALWAYS null — there is no resolver option, read the session by `recipientToken` yourself when needed. | → `docs/room-fanout.md` |
|
|
70
72
|
| `postSyncFanout` | After all recipients have been emitted to. Receives `recipientCount`. | → `docs/room-fanout.md` |
|
|
71
73
|
| `preSyncStream` | Per stream chunk, before it is emitted (`stream` / `broadcastStream` / `streamTo`). Carries `{ routeName, chunk, recipient }` (`recipient` = `'originator'`, the room, or a token). Observational. | → `docs/streaming.md` |
|
|
72
74
|
| `postSyncStream` | Per stream chunk, after emit. Adds a 1-based per-stream `chunkIndex` to the `preSyncStream` payload. Observational. | → `docs/streaming.md` |
|
|
@@ -84,8 +86,9 @@ Real-time sync transport for LuckyStack. Provides type-safe, room-based fanout o
|
|
|
84
86
|
- `sync.fanoutYieldEvery` — yield to the event loop every N recipients during a giant fanout. Clamped to `>= 1` (a configured `0` would make the modulo `NaN` and never yield).
|
|
85
87
|
- `sync.fanoutYieldMs` — duration of the yield `setTimeout`.
|
|
86
88
|
- `sync.requestTimeoutMs` — client-side ack-timeout for `syncRequest` (CORE-06). After this elapses with no acknowledgement the promise settles with `{ status:'error', errorCode:'sync.requestTimeout', httpStatus:504 }` instead of hanging. `false` disables. Default `30000`.
|
|
87
|
-
- `sync.allowClientReceiverAll` — when `false`, a client requesting the broadcast receiver `'all'` is rejected (`sync.receiverNotAllowed`, 403) on both transports (SYNC-07). **Default `false` (0.2.0 secure-default flip — was `true`); opt back into cluster-wide broadcast explicitly or approve via `preSyncAuthorize`.**
|
|
88
|
-
- `sync.requireRoomMembership` — when `true`, a client may only target a room it
|
|
89
|
+
- `sync.allowClientReceiverAll` — when `false`, a client requesting the broadcast receiver `'all'` is rejected (`sync.receiverNotAllowed`, 403) on both transports (SYNC-07). Listed in `docs/error-states.md` §3. **Default `false` (0.2.0 secure-default flip — was `true`); opt back into cluster-wide broadcast explicitly or approve via `preSyncAuthorize`.**
|
|
90
|
+
- `sync.requireRoomMembership` — when `true`, a client may only target a room it is a member of; otherwise rejected (`sync.notRoomMember`, 403; listed in `docs/error-states.md` §3). Enforced on BOTH transports but from DIFFERENT sources, deliberately: the SOCKET path tests PHYSICAL membership (`socket.rooms` of the originating socket), the HTTP/SSE path tests LOGICAL membership (the session's persisted `roomCodes` + its own token-room) because it has no originator socket. Consequence: on `routed-http` a successful `syncRequest` does not prove you are in the room yourself or that you will receive the fan-out (dev-mode warning when this happens) — see `/docs/ARCHITECTURE_SYNC.md` → "Room membership is transport-specific". An anonymous HTTP caller (no session) has undeterminable membership and is rejected (fail-closed). **Default `true` (0.2.0 secure-default flip — was `false`); set `false` for the legacy any-room behavior.**
|
|
91
|
+
- Empty target room → `sync.noReceiversFound` (404) on BOTH transports since 0.10.0 (the HTTP path used to answer `success` with zero recipients). Recipients are resolved BEFORE `_server` runs on both transports, so this error — and a `fetchSockets()` adapter timeout (`sync.serverExecutionFailed`) — means nothing was persisted; a retry is safe. See `docs/room-fanout.md` §1.
|
|
89
92
|
- `sync.flushPressure.maxBufferedBytes` — default drain threshold for the `flushPressure` backpressure helper when no per-call `thresholdBytes` is given (SYNC-15). Default `5_242_880` (5 MiB).
|
|
90
93
|
- `sync.flushPressure.highWaterMarkChunks` — upper bound (in packets) on the derived flush-pressure threshold. Default `1000`. (`lowWaterMarkChunks` is surfaced in core but full chunk-watermark hysteresis is a residual — see fix report.)
|
|
91
94
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// src/_shared/errorCodes.ts
|
|
2
|
+
var SYNC_ERROR_CODES = [
|
|
3
|
+
//? `syncRequest` (client-side, before the message hits the wire)
|
|
4
|
+
"sync.invalidName",
|
|
5
|
+
"sync.invalidVersion",
|
|
6
|
+
"sync.missingReceiver",
|
|
7
|
+
"sync.ioUnavailable",
|
|
8
|
+
"sync.failedRequest",
|
|
9
|
+
"sync.invalidServerResponse",
|
|
10
|
+
"sync.invalidRequestFormat",
|
|
11
|
+
"sync.requestTimeout",
|
|
12
|
+
//? `handleSyncRequest` / `handleHttpSyncRequest` (both transports)
|
|
13
|
+
"sync.invalidRequest",
|
|
14
|
+
"sync.invalidCallback",
|
|
15
|
+
"sync.notFound",
|
|
16
|
+
"sync.rateLimitExceeded",
|
|
17
|
+
"sync.invalidInputType",
|
|
18
|
+
"sync.serverExecutionFailed",
|
|
19
|
+
"sync.receiverNotAllowed",
|
|
20
|
+
"sync.notRoomMember",
|
|
21
|
+
"sync.noReceiversFound",
|
|
22
|
+
//? per-recipient `_client` stage (both transports)
|
|
23
|
+
"sync.clientExecutionFailed",
|
|
24
|
+
"sync.invalidClientResponse",
|
|
25
|
+
"sync.clientRejected",
|
|
26
|
+
//? `@luckystack/server` HTTP sync route (before the handler is reached)
|
|
27
|
+
"sync.disabled",
|
|
28
|
+
"sync.methodNotAllowed",
|
|
29
|
+
"sync.devToolsUnavailable"
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
export {
|
|
33
|
+
SYNC_ERROR_CODES
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=chunk-AJ36D2PQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/_shared/errorCodes.ts"],"sourcesContent":["//? The canonical, exported list of every `sync.*` error code the framework can\n//? emit — from `syncRequest` before the wire, from both transport handlers, from\n//? the per-recipient `_client` stage, and from `@luckystack/server`'s HTTP sync\n//? route (multi-instance handoff, DEV-376).\n//?\n//? Why a runtime export and not just a doc table: `translate()` returns the KEY\n//? itself when a locale lacks it, so a consumer whose locale files were typed\n//? from `docs/error-states.md` shows users a literal `sync.notRoomMember` the\n//? day this list grows. The list is framework-owned; the consumer cannot know\n//? when it changes. With this export a consumer writes ONE parity test\n//? (`for code of SYNC_ERROR_CODES: expect(locale.sync[code.slice(5)]).toBeDefined()`)\n//? instead of retyping a table. `errorCodes.test.ts` keeps this list equal to\n//? the literals in the source AND keeps the scaffold's four locale files in\n//? parity with it, so the export cannot drift from either side.\n//?\n//? Deliberately NOT in the list: `sync.ignore` — the client-side sentinel a\n//? `_client` handler returns to suppress delivery; it is never shown to anyone.\n\nexport const SYNC_ERROR_CODES = [\n //? `syncRequest` (client-side, before the message hits the wire)\n 'sync.invalidName',\n 'sync.invalidVersion',\n 'sync.missingReceiver',\n 'sync.ioUnavailable',\n 'sync.failedRequest',\n 'sync.invalidServerResponse',\n 'sync.invalidRequestFormat',\n 'sync.requestTimeout',\n //? `handleSyncRequest` / `handleHttpSyncRequest` (both transports)\n 'sync.invalidRequest',\n 'sync.invalidCallback',\n 'sync.notFound',\n 'sync.rateLimitExceeded',\n 'sync.invalidInputType',\n 'sync.serverExecutionFailed',\n 'sync.receiverNotAllowed',\n 'sync.notRoomMember',\n 'sync.noReceiversFound',\n //? per-recipient `_client` stage (both transports)\n 'sync.clientExecutionFailed',\n 'sync.invalidClientResponse',\n 'sync.clientRejected',\n //? `@luckystack/server` HTTP sync route (before the handler is reached)\n 'sync.disabled',\n 'sync.methodNotAllowed',\n 'sync.devToolsUnavailable',\n] as const;\n\n/** Union of every framework-emitted `sync.*` error code. */\nexport type SyncErrorCode = (typeof SYNC_ERROR_CODES)[number];\n"],"mappings":";AAkBO,IAAM,mBAAmB;AAAA;AAAA,EAE9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AACF;","names":[]}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { StreamPayload, statusContent, BaseSessionLayout, SyncTypeMap } from '@luckystack/core/client';
|
|
2
2
|
import { Dispatch, SetStateAction, RefObject } from 'react';
|
|
3
3
|
import { Socket } from 'socket.io-client';
|
|
4
|
+
export { S as SYNC_ERROR_CODES, a as SyncErrorCode } from './errorCodes-B8GoTenr.js';
|
|
4
5
|
|
|
5
6
|
type SyncRequestStreamEvent<T extends StreamPayload = StreamPayload> = T;
|
|
6
7
|
type SyncRouteStreamEvent<T extends StreamPayload = StreamPayload> = T;
|
package/dist/client.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SYNC_ERROR_CODES
|
|
3
|
+
} from "./chunk-AJ36D2PQ.js";
|
|
4
|
+
|
|
1
5
|
// src/syncRequest.ts
|
|
2
6
|
import {
|
|
3
7
|
getLogger,
|
|
@@ -749,6 +753,7 @@ var initSyncRequest = async ({
|
|
|
749
753
|
socket.on(socketEventNames.connectError, connectError);
|
|
750
754
|
};
|
|
751
755
|
export {
|
|
756
|
+
SYNC_ERROR_CODES,
|
|
752
757
|
attachSyncReceiver,
|
|
753
758
|
initSyncRequest,
|
|
754
759
|
syncRequest,
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/syncRequest.ts"],"sourcesContent":["//? All cross-package imports go through `@luckystack/core/client` (the\n//? browser-safe subpath) — never the main `@luckystack/core` barrel which\n//? re-exports server-only modules (paths.ts, db.ts, redis.ts) that must\n//? not enter a Vite client bundle.\nimport type {\n BaseSessionLayout as SessionLayout,\n StreamPayload,\n SyncTypeMap,\n statusContent,\n} from \"@luckystack/core/client\";\nimport {\n getLogger,\n getProjectConfig,\n notify,\n incrementResponseIndex,\n socket,\n waitForSocket,\n enqueueSyncRequest,\n removeSyncQueueItem,\n isOnline,\n normalizeErrorResponseCore,\n parseServiceRouteName,\n buildSyncProgressEventName,\n buildSyncResponseEventName,\n socketEventNames,\n invokeRoutedHttp,\n} from \"@luckystack/core/client\";\nimport { Dispatch, RefObject, SetStateAction, useCallback, useEffect, useRef } from \"react\";\nimport { Socket } from \"socket.io-client\";\n\nexport type SyncRequestStreamEvent<T extends StreamPayload = StreamPayload> = T;\n\nexport type SyncRouteStreamEvent<T extends StreamPayload = StreamPayload> = T;\n\ntype SyncRequestStreamCallback = (event: SyncRequestStreamEvent) => void;\ntype SyncEventStreamCallback = (params: { stream: SyncRouteStreamEvent }) => void;\n\nconst shouldLogDev = () => getProjectConfig().logging.devLogs;\nconst shouldNotifyDev = () => getProjectConfig().logging.devNotifications;\nconst shouldLogSocketStatus = () => getProjectConfig().logging.socketStatus;\nconst shouldLogStream = () => getProjectConfig().logging.stream;\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// Type Helpers for Sync Requests\n// ═══════════════════════════════════════════════════════════════════════════════\n\n// Check if data input is required (i.e., T does NOT allow empty object)\n// Unions like {a:1} | {b:1} do NOT allow {}, so data will be required\ntype DataRequired<T> = Record<string, never> extends T ? false : true;\n\ntype UnionToIntersection<U> =\n (U extends unknown ? (arg: U) => void : never) extends ((arg: infer I) => void)\n ? I\n : never;\n\ntype Prettify<T> = { [K in keyof T]: T[K] } & {};\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// Global Sync Params\n// ═══════════════════════════════════════════════════════════════════════════════\n\n// All possible sync names across all pages\ntype SyncRouteRecord = UnionToIntersection<{\n [P in keyof SyncTypeMap]: {\n [N in keyof SyncTypeMap[P] as P extends 'root'\n ? `system/${Extract<N, string>}`\n : `${Extract<P, string>}/${Extract<N, string>}`]: SyncTypeMap[P][N]\n }\n}[keyof SyncTypeMap]>;\n\ntype SyncFullName = Extract<keyof SyncRouteRecord, string>;\ntype VersionsForFullName<F extends SyncFullName> = Extract<keyof SyncRouteRecord[F], string>;\n\ntype ClientInputForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> = SyncRouteRecord[F][V] extends { clientInput: infer I }\n ? I\n : never;\n\ntype ServerOutputForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> = SyncRouteRecord[F][V] extends { serverOutput: infer O }\n ? O\n : never;\n\ntype ClientOutputForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> = SyncRouteRecord[F][V] extends { clientOutput: infer O }\n ? O\n : never;\n\ntype ServerStreamForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> = SyncRouteRecord[F][V] extends { serverStream: infer O }\n ? O\n : never;\n\ntype ClientStreamForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> = SyncRouteRecord[F][V] extends { clientStream: infer O }\n ? O\n : never;\n\ntype SyncRequestStreamCallbackForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> =\n [ServerStreamForFullName<F, V>] extends [never]\n ? never\n : (event: SyncRequestStreamEvent<Prettify<ServerStreamForFullName<F, V> extends StreamPayload ? ServerStreamForFullName<F, V> : StreamPayload>>) => void;\n\n//? Recipients see chunks from THREE sources, all on the same wire channel:\n//? 1. `_client_v{n}.ts`'s `stream(...)` (per-recipient, runs after _server)\n//? 2. `_server_v{n}.ts`'s `broadcastStream(...)` (room-wide fan-out)\n//? 3. `_server_v{n}.ts`'s `streamTo(tokens, ...)` (selective fan-out)\n//? All three flow into `upsertSyncEventCallback`'s `stream` argument. Both\n//? serverStream and clientStream are folded into the union so the callback\n//? sees every shape the route can emit. If neither side ever streams, the\n//? callback type collapses to never (compile error to register one).\ntype CombinedRouteStream<F extends SyncFullName, V extends VersionsForFullName<F>> =\n | (ClientStreamForFullName<F, V> extends never ? never : ClientStreamForFullName<F, V>)\n | (ServerStreamForFullName<F, V> extends never ? never : ServerStreamForFullName<F, V>);\n\ntype SyncRouteStreamCallbackForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> =\n [CombinedRouteStream<F, V>] extends [never]\n ? never\n : (params: { stream: SyncRouteStreamEvent<Prettify<CombinedRouteStream<F, V> extends StreamPayload ? CombinedRouteStream<F, V> : StreamPayload>> }) => void;\n\ntype SyncParamsForFullName<\n F extends SyncFullName,\n V extends VersionsForFullName<F>\n> = DataRequired<ClientInputForFullName<F, V>> extends true\n ? {\n name: F;\n version: V;\n data: ClientInputForFullName<F, V>;\n receiver: string;\n ignoreSelf?: boolean;\n onStream?: SyncRequestStreamCallbackForFullName<F, V>;\n /**\n * Per-request override of `projectConfig.offlineQueue.dropPolicy`. Lets a\n * specific sync (\"editor cursor move\") pick `'drop-oldest'` while the\n * app default stays `'reject'` for safer sends. When omitted, falls back\n * to the global config.\n */\n offlineDropPolicy?: 'drop-oldest' | 'drop-newest' | 'reject';\n /**\n * Optional AbortSignal. When aborted the client emits `syncCancel { cb }`\n * to the server and resolves locally with\n * `{ status: 'error', errorCode: 'request.aborted' }`.\n */\n signal?: AbortSignal;\n }\n : {\n name: F;\n version: V;\n data?: ClientInputForFullName<F, V>;\n receiver: string;\n ignoreSelf?: boolean;\n onStream?: SyncRequestStreamCallbackForFullName<F, V>;\n /** Per-request override (see typed branch). */\n offlineDropPolicy?: 'drop-oldest' | 'drop-newest' | 'reject';\n /** Optional AbortSignal — see typed branch. */\n signal?: AbortSignal;\n };\n\ninterface RuntimeSyncParams {\n name?: string;\n version?: string;\n data?: unknown;\n receiver?: string;\n ignoreSelf?: boolean;\n onStream?: SyncRequestStreamCallback;\n offlineDropPolicy?: 'drop-oldest' | 'drop-newest' | 'reject';\n signal?: AbortSignal;\n}\n\ninterface SyncErrorParam { key: string; value: string | number | boolean };\n\ninterface SyncResponseError {\n status: 'error';\n message: string;\n errorCode: string;\n errorParams?: SyncErrorParam[];\n httpStatus?: number;\n}\n\ntype RoutedSyncFailureKind = 'timeout' | 'aborted' | 'network-error' | 'invalid-response';\n\nconst routedSyncErrorCode = (kind: RoutedSyncFailureKind): string => {\n if (kind === 'timeout') return 'sync.requestTimeout';\n if (kind === 'aborted') return 'request.aborted';\n if (kind === 'invalid-response') return 'sync.invalidServerResponse';\n return 'sync.ioUnavailable';\n};\n\ninterface SyncAckResponse {\n status?: 'success' | 'error';\n message?: string;\n result?: unknown;\n errorCode?: string;\n errorParams?: SyncErrorParam[];\n httpStatus?: number;\n}\n\ntype SyncResultForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> =\n [ServerOutputForFullName<F, V>] extends [never]\n ? Record<string, never>\n : ServerOutputForFullName<F, V>;\n\ntype SyncRequestResponseForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> =\n | SyncResponseError\n | {\n status: 'success';\n message: string;\n result: SyncResultForFullName<F, V>;\n };\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// Sync Event Callbacks Registry\n// ═══════════════════════════════════════════════════════════════════════════════\n\ntype SyncEventCallback = (params: { clientOutput: unknown; serverOutput: unknown }) => void;\nconst syncEvents: Partial<Record<string, SyncEventCallback[]>> = {};\nconst syncStreamEvents: Partial<Record<string, SyncEventStreamCallback[]>> = {};\nconst noop = () => null;\n\ninterface SyncLifecycleHandlers {\n connect: () => void;\n disconnect: () => void;\n reconnectAttempt: (attempt: number) => void;\n userAfk: (payload: { userId: string; endTime?: number }) => void;\n userBack: (payload: { userId: string }) => void;\n connectError: (err: { message: string }) => void;\n}\n\nlet activeLifecycleHandlers: SyncLifecycleHandlers | null = null;\n\nconst canSendNow = (socketInstance: Socket) => {\n if (!socketInstance.connected) return false;\n return isOnline();\n};\n\nconst createQueueId = () => {\n return `${String(Date.now())}-${String(Math.random())}`;\n};\n\nconst getCallbacksForRoute = (route: string): SyncEventCallback[] => {\n syncEvents[route] ??= [];\n return syncEvents[route];\n};\n\nconst getStreamCallbacksForRoute = (route: string): SyncEventStreamCallback[] => {\n syncStreamEvents[route] ??= [];\n return syncStreamEvents[route];\n};\n\nconst triggerSyncCallbacks = (name: string, clientOutput: unknown, serverOutput: unknown) => {\n const callbacks = syncEvents[name] ?? [];\n if (callbacks.length === 0) {\n //? Streaming-only routes legitimately register ONLY a stream callback —\n //? the final success envelope is implicit in the stream completing. Only\n //? warn when NEITHER callback type is registered for the route.\n const streamCallbacks = syncStreamEvents[name] ?? [];\n if (streamCallbacks.length === 0 && shouldLogDev()) {\n getLogger().warn(`Sync event ${name} has no registered callback on this page`);\n }\n return;\n }\n\n for (const callback of callbacks) {\n callback({ clientOutput, serverOutput });\n }\n};\n\nconst triggerSyncStreamCallbacks = (name: string, stream: SyncRouteStreamEvent) => {\n const callbacks = syncStreamEvents[name] ?? [];\n if (callbacks.length === 0) {\n return;\n }\n\n for (const callback of callbacks) {\n callback({ stream });\n }\n};\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// syncRequest Function Overloads\n// ═══════════════════════════════════════════════════════════════════════════════\n\nconst normalizeSyncError = ({\n response,\n fallbackErrorCode,\n}: {\n response: SyncAckResponse;\n fallbackErrorCode: string;\n}): SyncResponseError => {\n const normalized = normalizeErrorResponseCore({\n response,\n fallbackErrorCode,\n resolveMessage: ({ errorCode }) => {\n if (typeof response.message === 'string' && response.message.trim().length > 0) {\n return response.message;\n }\n\n return errorCode;\n },\n });\n\n return {\n status: 'error',\n message: normalized.message,\n errorCode: normalized.errorCode,\n errorParams: normalized.errorParams,\n httpStatus: normalized.httpStatus,\n };\n};\n\ntype SyncRequestParamsWithOptions<F extends SyncFullName, V extends VersionsForFullName<F>> =\n SyncParamsForFullName<F, V>;\n\n//? Outcome of the pre-flight validation phase of a sync send. Either a\n//? normalized error envelope to resolve the request with, or the sanitized\n//? values the send phase needs. Extracted from `syncRequestInternal` so the\n//? \"validate first, execute second\" split is explicit (the orchestrator stays\n//? a thin promise wrapper around prepare → run).\ntype PreparedSyncRequest =\n | { ok: false; error: SyncResponseError }\n | { ok: true; sanitizedName: string; version: string; data: object; normalizedReceiver: string };\n\n//? Pure-ish validation chain (logs + dev-notifies on failure, same as the\n//? previous inlined block). Async because the socket-readiness gate\n//? (`waitForSocket`) is awaited last, after the cheap structural checks. Each\n//? failure path returns the SAME normalized error envelope the inlined code\n//? resolved with — behaviour-identical.\nconst prepareSyncRequest = async ({\n name,\n version,\n receiver,\n payloadData,\n}: {\n name: unknown;\n version: unknown;\n receiver: unknown;\n payloadData: unknown;\n}): Promise<PreparedSyncRequest> => {\n if (!name || typeof name !== \"string\") {\n if (shouldLogDev()) {\n getLogger().error(\"Invalid name for syncRequest\");\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'sync.invalidName' });\n }\n return { ok: false, error: normalizeSyncError({\n response: { status: 'error', errorCode: 'sync.invalidName' },\n fallbackErrorCode: 'sync.invalidName',\n }) };\n }\n\n const parsedRoute = parseServiceRouteName(name);\n if (parsedRoute.status === 'error') {\n if (shouldLogDev()) {\n getLogger().error(`[syncRequest] Invalid service route name '${name}'`, undefined, { reason: parsedRoute.reason });\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'routing.invalidServiceRouteName' });\n }\n return { ok: false, error: normalizeSyncError({\n response: {\n status: 'error',\n errorCode: 'routing.invalidServiceRouteName',\n errorParams: [{ key: 'name', value: name }],\n },\n fallbackErrorCode: 'routing.invalidServiceRouteName',\n }) };\n }\n\n const sanitizedName = parsedRoute.normalizedRouteName;\n\n const data = payloadData && typeof payloadData === \"object\" ? payloadData : {};\n\n if (!version || typeof version !== 'string') {\n if (shouldLogDev()) {\n getLogger().error(\"Invalid version for syncRequest\");\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'sync.invalidVersion' });\n }\n return { ok: false, error: normalizeSyncError({\n response: { status: 'error', errorCode: 'sync.invalidVersion' },\n fallbackErrorCode: 'sync.invalidVersion',\n }) };\n }\n\n const normalizedReceiver = typeof receiver === 'string' ? receiver.trim() : '';\n\n if (!normalizedReceiver) {\n if (shouldLogDev()) {\n getLogger().error(\"You need to provide a receiver for syncRequest, this can be either 'all' to trigger all sockets which we do not recommend or it can be any value such as a code e.g 'Ag2cg4'. this works together with the joinRoom and leaveRoom function\");\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'sync.missingReceiver' });\n }\n return { ok: false, error: normalizeSyncError({\n response: { status: 'error', errorCode: 'sync.missingReceiver' },\n fallbackErrorCode: 'sync.missingReceiver',\n }) };\n }\n\n if (!await waitForSocket()) {\n return { ok: false, error: normalizeSyncError({\n response: { status: 'error', errorCode: 'sync.ioUnavailable' },\n fallbackErrorCode: 'sync.ioUnavailable',\n }) };\n }\n if (!socket) {\n return { ok: false, error: normalizeSyncError({\n response: { status: 'error', errorCode: 'sync.ioUnavailable' },\n fallbackErrorCode: 'sync.ioUnavailable',\n }) };\n }\n\n return { ok: true, sanitizedName, version, data, normalizedReceiver };\n};\n\nconst syncRequestInternal = <F extends SyncFullName, V extends VersionsForFullName<F>>(\n params: SyncRequestParamsWithOptions<F, V>\n): Promise<Prettify<SyncRequestResponseForFullName<F, V>>> => {\n const runtimeParams = params as RuntimeSyncParams;\n const { name, version, receiver, ignoreSelf, onStream, offlineDropPolicy, signal: externalSignal } = runtimeParams;\n const payloadData = runtimeParams.data;\n\n type RequestOutput = Prettify<SyncRequestResponseForFullName<F, V>>;\n\n return new Promise<RequestOutput>((resolve) => {\n void (async () => {\n //? B1 — if the consumer-supplied signal is already aborted at call\n //? time, short-circuit before we even touch the socket.\n if (externalSignal?.aborted) {\n resolve(normalizeSyncError({\n response: { status: 'error', errorCode: 'request.aborted' },\n fallbackErrorCode: 'request.aborted',\n }));\n return;\n }\n\n const prepared = await prepareSyncRequest({ name, version, receiver, payloadData });\n if (!prepared.ok) {\n resolve(prepared.error);\n return;\n }\n const { sanitizedName, version: resolvedVersion, data, normalizedReceiver } = prepared;\n\n //? Re-narrow `socket` for the closures below. `prepareSyncRequest`\n //? already guaranteed it is non-null (returns an `ioUnavailable` error\n //? otherwise), but that guard lives in another function so TS can't\n //? carry the narrowing across the call boundary.\n const activeSocket = socket;\n if (!activeSocket) {\n resolve(normalizeSyncError({\n response: { status: 'error', errorCode: 'sync.ioUnavailable' },\n fallbackErrorCode: 'sync.ioUnavailable',\n }));\n return;\n }\n\n const fullName = `sync/${sanitizedName}/${resolvedVersion}`;\n let queueId: string | null = null;\n\n const runRequest = (socketInstance: Socket) => {\n if (!canSendNow(socketInstance)) {\n queueId ??= createQueueId();\n //? For the immediate reject-new path (`drop-newest` / `reject`\n //? policy) THIS item's `onDrop` fires SYNCHRONOUSLY inside\n //? `enqueueSyncRequest`. We keep surfacing that as the historical\n //? `offline.queueFull` via the `!enqueued` branch, so suppress the\n //? `onDrop` resolve during the synchronous enqueue window and re-arm\n //? it only if the item was actually queued (so a LATER async eviction\n //? — drop-oldest by a future enqueue, or age expiry — still settles).\n let suppressOnDrop = true;\n //? `enqueueSyncRequest` returns `false` when the offline queue is\n //? full and `dropPolicy: 'reject'` is active. Resolve with a\n //? normalized error envelope so the caller can branch instead of\n //? awaiting forever.\n const enqueued = enqueueSyncRequest({\n id: queueId,\n key: fullName,\n run: (s) => {\n runRequest(s);\n },\n createdAt: Date.now(),\n dropPolicy: offlineDropPolicy,\n //? SYNC-09 — settle the awaiting caller when this QUEUED request is\n //? later EVICTED (drop-oldest by a future enqueue / age expiry)\n //? instead of ever running. Without it the promise would hang\n //? forever, since `run` is the only thing that could otherwise\n //? resolve it. The default `offlineQueue.dropPolicy` is\n //? `'drop-oldest'`, so async eviction is the NORMAL overflow path\n //? for high-churn syncs (cursor moves), not an edge case.\n onDrop: (reason) => {\n if (suppressOnDrop) return;\n resolve(normalizeSyncError({\n response: { status: 'error', errorCode: 'offline.dropped', errorParams: [{ key: 'reason', value: reason }] },\n fallbackErrorCode: 'offline.dropped',\n }));\n },\n });\n //? Past the synchronous enqueue window: if the item is sitting in the\n //? queue, a future eviction should settle via `onDrop`.\n suppressOnDrop = false;\n if (!enqueued) {\n resolve(normalizeSyncError({\n response: { status: 'error', errorCode: 'offline.queueFull' },\n fallbackErrorCode: 'offline.queueFull',\n }));\n } else if (externalSignal && queueId) {\n const capturedQueueId = queueId;\n externalSignal.addEventListener('abort', () => {\n removeSyncQueueItem(capturedQueueId);\n resolve(normalizeSyncError({\n response: { status: 'error', errorCode: 'request.aborted' },\n fallbackErrorCode: 'request.aborted',\n }));\n }, { once: true });\n }\n return;\n }\n\n if (getProjectConfig().transport.invocation === 'routed-http') {\n void (async () => {\n const routed = await invokeRoutedHttp<SyncAckResponse, SyncRequestStreamEvent>({\n path: `/sync/${sanitizedName}/${resolvedVersion}`,\n method: 'POST',\n data: {\n data,\n receiver: normalizedReceiver,\n ignoreSelf: ignoreSelf ?? false,\n },\n stream: onStream,\n signals: [externalSignal],\n timeoutMs: getProjectConfig().sync.requestTimeoutMs,\n });\n if (queueId) removeSyncQueueItem(queueId);\n\n if (routed.kind !== 'response') {\n const errorCode = routedSyncErrorCode(routed.kind);\n resolve(normalizeSyncError({\n response: {\n status: 'error',\n errorCode,\n httpStatus: routed.kind === 'timeout' ? 504 : undefined,\n },\n fallbackErrorCode: errorCode,\n }));\n return;\n }\n\n const responseData = routed.response;\n if (responseData.status === 'error') {\n const normalizedError = normalizeSyncError({\n response: responseData,\n fallbackErrorCode: 'sync.failedRequest',\n });\n if (shouldNotifyDev()) {\n notify.error({ key: normalizedError.errorCode, params: normalizedError.errorParams });\n }\n resolve(normalizedError);\n return;\n }\n if (responseData.status !== 'success') {\n resolve(normalizeSyncError({\n response: responseData,\n fallbackErrorCode: 'sync.invalidServerResponse',\n }));\n return;\n }\n\n const result = responseData.result && typeof responseData.result === 'object'\n ? responseData.result\n : {};\n //? HTTP response boundary: generated route typing supplies the\n //? precise result shape, while JSON parsing necessarily starts at unknown.\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- routed response boundary\n resolve({\n status: 'success',\n message: typeof responseData.message === 'string' && responseData.message.trim().length > 0\n ? responseData.message\n : `sync ${sanitizedName} success`,\n result,\n } as RequestOutput);\n })();\n return;\n }\n\n const tempIndex = incrementResponseIndex();\n\n let cleanupProgressListener: (() => void) | null = null;\n //? CORE-06 — ack-timeout. Armed right after the request is emitted so a\n //? lost acknowledgement (server restart/crash between emit and reply)\n //? settles the promise with `sync.requestTimeout` (504) instead of\n //? hanging the awaiting caller forever. Mirrors `apiRequest`'s\n //? `api.requestTimeoutMs` wiring.\n let responseTimeout: ReturnType<typeof setTimeout> | null = null;\n const clearResponseTimeout = () => {\n if (responseTimeout) {\n clearTimeout(responseTimeout);\n responseTimeout = null;\n }\n };\n\n if (shouldLogDev()) {\n getLogger().debug(`Client Sync Request(${String(tempIndex)})`, { syncName: sanitizedName, data, receiver: normalizedReceiver, ignoreSelf });\n }\n\n //? S13 — server-issued cancel id. The server emits a `{ __cancelId }`\n //? handshake frame on the progress channel before any work runs; we\n //? capture it so an abort can target THIS exact request (not a callback\n //? name reused across concurrent same-route requests, which corrupted\n //? the server-side abort registry). The progress listener is ALWAYS\n //? registered now — even without `onStream` — so the handshake is caught\n //? on non-streaming routes too. The reserved `__cancelId` frame is\n //? filtered out of `onStream` delivery.\n let serverCancelId: string | null = null;\n const progressEventName = buildSyncProgressEventName(tempIndex);\n const progressListener = (streamPayload: SyncRequestStreamEvent & { __cancelId?: string }) => {\n if (typeof streamPayload.__cancelId === 'string') {\n serverCancelId = streamPayload.__cancelId;\n return;\n }\n\n if (typeof onStream !== 'function') return;\n\n if (shouldLogStream()) {\n getLogger().debug(`Server Sync Stream(${String(tempIndex)})`, { syncName: sanitizedName, streamPayload });\n }\n\n onStream(streamPayload);\n };\n\n socketInstance.on(progressEventName, progressListener);\n cleanupProgressListener = () => {\n socketInstance.off(progressEventName, progressListener);\n };\n\n //? Fallback cancel key for the narrow window before the `__cancelId`\n //? handshake frame arrives (abort fired immediately on a slow link).\n //? Best-effort only — once the handshake lands `serverCancelId` is the\n //? authoritative, per-request-unique key the server registered under.\n const syncCb = `${sanitizedName}/${resolvedVersion}`;\n socketInstance.emit(socketEventNames.sync, { name: fullName, data, cb: syncCb, receiver: normalizedReceiver, responseIndex: tempIndex, ignoreSelf });\n\n //? B1 / S13 — bridge the consumer's AbortSignal to the server. When the\n //? signal fires we emit `syncCancel { cb: <serverCancelId> }` so the\n //? server-side handler stops emitting new chunks. We also resolve\n //? locally with `request.aborted` so the awaiting caller settles.\n const responseEventName = buildSyncResponseEventName(tempIndex);\n //? Forward-declared so the abort/timeout paths can proactively `off()`\n //? the lingering ack listener instead of waiting for a reply that was\n //? cancelled / will never arrive.\n let cleanupResponseListener: (() => void) | null = null;\n\n let cleanupExternalAbort: (() => void) | null = null;\n if (externalSignal) {\n const externalAbortHandler = () => {\n clearResponseTimeout();\n socketInstance.emit(socketEventNames.syncCancel, { cb: serverCancelId ?? syncCb });\n cleanupProgressListener?.();\n cleanupProgressListener = null;\n cleanupResponseListener?.();\n cleanupResponseListener = null;\n cleanupExternalAbort?.();\n cleanupExternalAbort = null;\n resolve(normalizeSyncError({\n response: { status: 'error', errorCode: 'request.aborted' },\n fallbackErrorCode: 'request.aborted',\n }));\n };\n externalSignal.addEventListener('abort', externalAbortHandler);\n cleanupExternalAbort = () => {\n externalSignal.removeEventListener('abort', externalAbortHandler);\n };\n }\n\n //? Arm the ack-timeout. `sync.requestTimeoutMs` (default 30000) may be\n //? `false` to disable. On expiry we tear down every listener and settle\n //? with a 504 envelope so the awaiting caller never hangs.\n const effectiveTimeoutMs = getProjectConfig().sync.requestTimeoutMs;\n if (typeof effectiveTimeoutMs === 'number' && effectiveTimeoutMs > 0) {\n responseTimeout = setTimeout(() => {\n responseTimeout = null;\n //? SYNC — on ack-timeout, tell the server to STOP the in-flight work\n //? before tearing down locally. Previously the timeout only cleaned up\n //? the client listeners + settled 504, leaving the `_server` handler\n //? (and any fanout/streaming) running to completion uncancelled. The\n //? `__cancelId` handshake has long since arrived by the timeout window\n //? (the server emits it immediately), so `serverCancelId` is the\n //? authoritative key here; `syncCb` is only the sub-RTT fallback.\n socketInstance.emit(socketEventNames.syncCancel, { cb: serverCancelId ?? syncCb });\n cleanupProgressListener?.();\n cleanupProgressListener = null;\n cleanupResponseListener?.();\n cleanupResponseListener = null;\n cleanupExternalAbort?.();\n cleanupExternalAbort = null;\n if (shouldLogDev()) {\n getLogger().error(`Sync ${sanitizedName} timed out`, undefined, { responseIndex: tempIndex });\n }\n resolve(normalizeSyncError({\n response: { status: 'error', errorCode: 'sync.requestTimeout', httpStatus: 504 },\n fallbackErrorCode: 'sync.requestTimeout',\n }));\n }, effectiveTimeoutMs);\n }\n\n const responseListener = (responseData: SyncAckResponse) => {\n clearResponseTimeout();\n cleanupProgressListener?.();\n cleanupProgressListener = null;\n cleanupResponseListener = null;\n cleanupExternalAbort?.();\n cleanupExternalAbort = null;\n\n if (responseData.status === \"error\") {\n const normalizedError = normalizeSyncError({\n response: responseData,\n fallbackErrorCode: 'sync.failedRequest',\n });\n\n if (shouldLogDev()) {\n getLogger().error(`Sync ${sanitizedName} failed`, undefined, { message: normalizedError.message });\n }\n if (shouldNotifyDev()) {\n notify.error({\n key: 'sync.failedRequest',\n params: [\n { key: 'name', value: sanitizedName },\n { key: 'message', value: normalizedError.message },\n ],\n });\n }\n resolve(normalizedError);\n return;\n }\n\n if (responseData.status !== 'success') {\n resolve(normalizeSyncError({\n response: responseData,\n fallbackErrorCode: 'sync.invalidServerResponse',\n }));\n return;\n }\n\n const result = responseData.result && typeof responseData.result === 'object'\n ? responseData.result\n : {};\n\n //? `RequestOutput.result` is a generic `Record<string, never>` shape\n //? that the runtime response can't structurally satisfy from the\n //? untyped `responseData.result` (server-side typing lives on the\n //? other side of the socket). The cast is the documented socket\n //? response boundary.\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- socket response boundary\n resolve({\n status: 'success',\n message: typeof responseData.message === 'string' && responseData.message.trim().length > 0\n ? responseData.message\n : `sync ${sanitizedName} success`,\n result,\n } as RequestOutput);\n };\n\n socketInstance.once(responseEventName, responseListener);\n cleanupResponseListener = () => {\n socketInstance.off(responseEventName, responseListener);\n };\n };\n\n runRequest(activeSocket);\n })();\n });\n};\n\nexport function syncRequest<F extends SyncFullName, V extends VersionsForFullName<F>>(\n params: SyncRequestParamsWithOptions<F, V>\n): Promise<Prettify<SyncRequestResponseForFullName<F, V>>> {\n return syncRequestInternal(params);\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// useSyncEvents Hook - Type-Safe Event Registration\n// ═══════════════════════════════════════════════════════════════════════════════\n\n//? Hoisted to module scope so the emitted `.d.ts` for `useSyncEvents` can\n//? reference them. Local interface declarations inside an exported function\n//? trigger TS4025 (\"has or is using private name\") under `declaration: true`.\ninterface TypedCallbackParams<F extends SyncFullName, V extends VersionsForFullName<F>> {\n clientOutput: ClientOutputForFullName<F, V>;\n serverOutput: ServerOutputForFullName<F, V>;\n}\n\ninterface UpsertParams<F extends SyncFullName, V extends VersionsForFullName<F>> {\n name: F;\n version: V;\n callback: (params: TypedCallbackParams<F, V>) => void;\n}\n\ninterface UpsertStreamParams<F extends SyncFullName, V extends VersionsForFullName<F>> {\n name: F;\n version: V;\n callback: SyncRouteStreamCallbackForFullName<F, V>;\n}\n\nexport const useSyncEvents = () => {\n const localRegistryRef = useRef<Map<string, SyncEventCallback>>(new Map());\n const localStreamRegistryRef = useRef<Map<string, SyncEventStreamCallback>>(new Map());\n\n const upsertSyncEventCallback = useCallback(<F extends SyncFullName, V extends VersionsForFullName<F>>(\n params: UpsertParams<F, V>\n ): (() => void) => {\n\n if (typeof params.version !== 'string') {\n if (shouldLogDev()) {\n getLogger().error(\"Invalid version for upsertSyncEventCallback\");\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'sync.invalidVersion' });\n }\n return noop;\n }\n\n if (typeof params.callback !== 'function') {\n if (shouldLogDev()) {\n getLogger().error(\"Invalid callback for upsertSyncEventCallback\");\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'sync.invalidCallback' });\n }\n return noop;\n }\n\n const routeName = params.name;\n const parsedRoute = parseServiceRouteName(routeName);\n if (parsedRoute.status === 'error') {\n if (shouldLogDev()) {\n getLogger().error(`Invalid name for upsertSyncEventCallback`, undefined, { routeName, reason: parsedRoute.reason });\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'routing.invalidServiceRouteName' });\n }\n return noop;\n }\n const sanitizedName = parsedRoute.normalizedRouteName;\n\n const routeVersion = params.version;\n const fullName = `sync/${sanitizedName}/${routeVersion}`;\n const callback: SyncEventCallback = ({ clientOutput, serverOutput }) => {\n params.callback({\n clientOutput: clientOutput as ClientOutputForFullName<F, V>,\n serverOutput: serverOutput as ServerOutputForFullName<F, V>,\n });\n };\n const callbacks = getCallbacksForRoute(fullName);\n\n const previousForRoute = localRegistryRef.current.get(fullName);\n if (previousForRoute) {\n syncEvents[fullName] = callbacks.filter((cb) => cb !== previousForRoute);\n }\n\n const nextCallbacks = getCallbacksForRoute(fullName);\n // Multiple components can intentionally subscribe to the same sync event.\n // Only warn when the exact same callback is registered twice.\n if (nextCallbacks.includes(callback)) {\n if (shouldLogDev()) {\n getLogger().warn(`[SyncEvents] Duplicate callback registration was ignored`, { fullName });\n }\n\n localRegistryRef.current.set(fullName, callback);\n\n return () => {\n const current = getCallbacksForRoute(fullName);\n syncEvents[fullName] = current.filter((cb) => cb !== callback);\n\n if (localRegistryRef.current.get(fullName) === callback) {\n localRegistryRef.current.delete(fullName);\n }\n };\n }\n\n nextCallbacks.push(callback);\n syncEvents[fullName] = nextCallbacks;\n localRegistryRef.current.set(fullName, callback);\n\n return () => {\n const current = getCallbacksForRoute(fullName);\n syncEvents[fullName] = current.filter((cb) => cb !== callback);\n\n if (localRegistryRef.current.get(fullName) === callback) {\n localRegistryRef.current.delete(fullName);\n }\n };\n }, []);\n\n const upsertSyncEventStreamCallback = useCallback(<F extends SyncFullName, V extends VersionsForFullName<F>>(\n params: UpsertStreamParams<F, V>\n ): (() => void) => {\n\n if (typeof params.version !== 'string') {\n if (shouldLogDev()) {\n getLogger().error(\"Invalid version for upsertSyncEventStreamCallback\");\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'sync.invalidVersion' });\n }\n return noop;\n }\n\n if (typeof params.callback !== 'function') {\n if (shouldLogDev()) {\n getLogger().error(\"Invalid callback for upsertSyncEventStreamCallback\");\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'sync.invalidCallback' });\n }\n return noop;\n }\n\n const routeName = params.name;\n const parsedRoute = parseServiceRouteName(routeName);\n if (parsedRoute.status === 'error') {\n if (shouldLogDev()) {\n getLogger().error(`Invalid name for upsertSyncEventStreamCallback`, undefined, { routeName, reason: parsedRoute.reason });\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'routing.invalidServiceRouteName' });\n }\n return noop;\n }\n const sanitizedName = parsedRoute.normalizedRouteName;\n\n const routeVersion = params.version;\n const fullName = `sync/${sanitizedName}/${routeVersion}`;\n //? Combined union: both `serverStream` (from `broadcastStream` /\n //? `streamTo`) and `clientStream` (from `_client_v{n}.ts`) flow through\n //? this callback. The type matches `SyncRouteStreamCallbackForFullName`.\n const typedCallback = params.callback as (params: {\n stream: SyncRouteStreamEvent<Prettify<CombinedRouteStream<F, V> extends StreamPayload ? CombinedRouteStream<F, V> : StreamPayload>>;\n }) => void;\n const callback: SyncEventStreamCallback = ({ stream }) => {\n typedCallback({\n stream: stream as SyncRouteStreamEvent<Prettify<CombinedRouteStream<F, V> extends StreamPayload ? CombinedRouteStream<F, V> : StreamPayload>>,\n });\n };\n const callbacks = getStreamCallbacksForRoute(fullName);\n\n const previousForRoute = localStreamRegistryRef.current.get(fullName);\n if (previousForRoute) {\n syncStreamEvents[fullName] = callbacks.filter((cb) => cb !== previousForRoute);\n }\n\n const nextCallbacks = getStreamCallbacksForRoute(fullName);\n if (nextCallbacks.includes(callback)) {\n if (shouldLogDev()) {\n getLogger().warn(`[SyncEvents] Duplicate stream callback registration was ignored`, { fullName });\n }\n\n localStreamRegistryRef.current.set(fullName, callback);\n\n return () => {\n const current = getStreamCallbacksForRoute(fullName);\n syncStreamEvents[fullName] = current.filter((cb) => cb !== callback);\n\n if (localStreamRegistryRef.current.get(fullName) === callback) {\n localStreamRegistryRef.current.delete(fullName);\n }\n };\n }\n\n nextCallbacks.push(callback);\n syncStreamEvents[fullName] = nextCallbacks;\n localStreamRegistryRef.current.set(fullName, callback);\n\n return () => {\n const current = getStreamCallbacksForRoute(fullName);\n syncStreamEvents[fullName] = current.filter((cb) => cb !== callback);\n\n if (localStreamRegistryRef.current.get(fullName) === callback) {\n localStreamRegistryRef.current.delete(fullName);\n }\n };\n }, []);\n\n useEffect(() => {\n const localRegistry = localRegistryRef.current;\n const localStreamRegistry = localStreamRegistryRef.current;\n\n return () => {\n for (const [fullName, callback] of localRegistry.entries()) {\n const current = getCallbacksForRoute(fullName);\n syncEvents[fullName] = current.filter((cb) => cb !== callback);\n }\n\n for (const [fullName, callback] of localStreamRegistry.entries()) {\n const current = getStreamCallbacksForRoute(fullName);\n syncStreamEvents[fullName] = current.filter((cb) => cb !== callback);\n }\n\n localRegistry.clear();\n localStreamRegistry.clear();\n };\n }, []);\n\n return { upsertSyncEventCallback, upsertSyncEventStreamCallback };\n}\n\nexport const useSyncEventTrigger = () => {\n const triggerSyncEvent = useCallback((name: string, clientOutput: unknown = {}, serverOutput: unknown = {}) => {\n triggerSyncCallbacks(name, clientOutput, serverOutput);\n }, []);\n\n const triggerSyncStreamEvent = useCallback((name: string, stream: SyncRouteStreamEvent) => {\n triggerSyncStreamCallbacks(name, stream);\n }, []);\n\n return { triggerSyncEvent, triggerSyncStreamEvent }\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// Sync Receive Bridge — attachSyncReceiver\n// ═══════════════════════════════════════════════════════════════════════════════\n\n//? Shape of the `sync` socket event the server emits to clients. Mirrors the\n//? server's emit payload; extra keys are stream chunk fields.\ninterface SyncEventPayload {\n cb?: string;\n clientOutput?: unknown;\n serverOutput?: unknown;\n message?: string;\n status?: 'success' | 'error' | 'stream';\n fullName?: string;\n errorCode?: string;\n errorParams?: { key: string; value: string | number | boolean }[];\n httpStatus?: number;\n [key: string]: unknown;\n}\n\nconst normalizeSyncRouteKey = (value: string): string => {\n const sanitized = value.replaceAll(/^\\/+|\\/+$/g, '');\n if (sanitized.length === 0) return '';\n if (sanitized.startsWith('sync/')) return sanitized;\n return `sync/${sanitized}`;\n};\n\nconst getSyncRouteKeys = ({ fullName, cb }: { fullName?: string; cb?: string }): string[] => {\n const keys = new Set<string>();\n if (typeof fullName === 'string') {\n const normalized = normalizeSyncRouteKey(fullName);\n if (normalized) keys.add(normalized);\n }\n if (typeof cb === 'string') {\n const normalized = normalizeSyncRouteKey(cb);\n if (normalized) keys.add(normalized);\n }\n return [...keys];\n};\n\n//? Per-socket idempotency guard — attaching twice to the same socket would\n//? double-dispatch every sync event.\nconst attachedSyncSockets = new WeakSet<Socket>();\n\n//? Wire the incoming `sync` socket listener that routes server fan-out into the\n//? registered `upsertSyncEventCallback` / `upsertSyncEventStreamCallback`\n//? subscribers. Previously this logic was inlined in the consumer's\n//? `socketInitializer.ts`; relocating it here makes `@luckystack/sync` own its\n//? own receive path, so a consumer only has to dynamic-import this and call it\n//? (the add-later sync wiring is then a single line, not a copy-paste block).\nexport const attachSyncReceiver = (socketInstance: Socket): void => {\n if (attachedSyncSockets.has(socketInstance)) return;\n attachedSyncSockets.add(socketInstance);\n\n socketInstance.on(socketEventNames.sync, (payload: SyncEventPayload) => {\n const { cb, clientOutput, serverOutput, message, status, fullName, errorCode, errorParams } = payload;\n if (shouldLogDev()) {\n getLogger().debug('Server Sync Response', { payload });\n }\n\n const routeKeys = getSyncRouteKeys({ fullName, cb });\n\n if (status === 'stream') {\n if (routeKeys.length === 0) return;\n\n //? SYNC-N7 — strip all reserved envelope keys from the forwarded stream\n //? payload so a consumer handler that accidentally emits `errorCode`,\n //? `errorParams`, `httpStatus`, or `message` in a stream chunk doesn't\n //? pollute the client callback's stream argument with error-envelope fields.\n //? `status`, `fullName`, `cb` were already stripped; the others are added here.\n const streamPayload = { ...payload };\n delete streamPayload.status;\n delete streamPayload.fullName;\n delete streamPayload.cb;\n delete streamPayload.errorCode;\n delete streamPayload.errorParams;\n delete streamPayload.httpStatus;\n delete streamPayload.message;\n\n if (shouldLogStream()) {\n getLogger().debug('Server Sync Stream', { routeKeys, streamPayload });\n }\n\n for (const routeKey of routeKeys) {\n triggerSyncStreamCallbacks(routeKey, streamPayload);\n }\n return;\n }\n\n if (status === 'error') {\n if (errorCode === 'sync.ignore' || message === 'sync.ignore') return;\n if (shouldNotifyDev()) {\n if (errorCode) {\n notify.error({ key: errorCode, params: errorParams });\n } else if (message) {\n notify.error({ key: message });\n }\n }\n return;\n }\n\n if (routeKeys.length === 0) {\n const errorMessage = `Sync response is missing fullName for cb '${cb ?? 'unknown'}'.`;\n if (shouldLogDev()) {\n getLogger().error(errorMessage);\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'sync.invalidRequestFormat' });\n }\n //? SYNC-10 — degrade to a logged warning instead of throwing. This runs\n //? inside the `socket.on(sync)` listener; a `throw` here is an uncaught\n //? exception on a server-controlled (malformed) frame that can kill other\n //? listeners bound to the same emit. The error is already logged + notified\n //? above, so `return` loses no information.\n return;\n }\n\n for (const routeKey of routeKeys) {\n triggerSyncCallbacks(routeKey, clientOutput, serverOutput);\n }\n });\n};\n\ntype SocketStatusSetter = Dispatch<\n SetStateAction<{\n self: statusContent;\n [userId: string]: statusContent;\n }>\n>;\n\nconst buildConnectHandler = ({ setSocketStatus }: { setSocketStatus: SocketStatusSetter }) => () => {\n if (shouldLogSocketStatus()) getLogger().info(\"Connected to server\");\n setSocketStatus(prev => ({ ...prev, self: { ...prev.self, status: \"CONNECTED\" } }));\n};\n\nconst buildDisconnectHandler = ({ setSocketStatus }: { setSocketStatus: SocketStatusSetter }) => () => {\n setSocketStatus(prev => ({ ...prev, self: { ...prev.self, status: \"DISCONNECTED\" } }));\n if (shouldLogSocketStatus()) getLogger().info(\"Disconnected, trying to reconnect...\");\n};\n\nconst buildReconnectAttemptHandler = ({ setSocketStatus }: { setSocketStatus: SocketStatusSetter }) => (attempt: number) => {\n setSocketStatus(prev => ({ ...prev, self: { ...prev.self, status: \"RECONNECTING\", reconnectAttempt: attempt } }));\n if (shouldLogSocketStatus()) getLogger().info(`Reconnecting attempt ${String(attempt)}...`);\n};\n\nconst buildUserAfkHandler = ({\n setSocketStatus, sessionRef,\n}: {\n setSocketStatus: SocketStatusSetter;\n sessionRef: RefObject<SessionLayout | null>;\n}) => ({ userId, endTime }: { userId: string; endTime?: number }) => {\n if (sessionRef.current !== null && userId === sessionRef.current.id) {\n setSocketStatus(prev => ({\n ...prev,\n self: { status: \"DISCONNECTED\", reconnectAttempt: undefined, endTime },\n }));\n } else {\n setSocketStatus(prev => ({\n ...prev,\n [userId]: { status: \"DISCONNECTED\", endTime },\n }));\n }\n};\n\nconst buildUserBackHandler = ({ setSocketStatus }: { setSocketStatus: SocketStatusSetter }) => ({ userId }: { userId: string }) => {\n if (shouldLogSocketStatus()) getLogger().debug(\"userBack\", { userId });\n setSocketStatus(prev => ({\n ...prev,\n [userId]: { status: \"CONNECTED\", endTime: undefined },\n }));\n};\n\nconst buildConnectErrorHandler = ({ setSocketStatus }: { setSocketStatus: SocketStatusSetter }) => (err: { message: string }) => {\n if (shouldLogSocketStatus()) getLogger().debug(\"connect_error\", { err });\n setSocketStatus(prev => ({\n ...prev,\n self: { ...prev.self, status: \"DISCONNECTED\", reconnectAttempt: undefined },\n }));\n if (shouldLogDev()) getLogger().error(`Connection error`, err);\n if (shouldNotifyDev()) notify.error({ key: 'common.connectionError' });\n};\n\n//? SYNC-N6 — `initSyncRequest` owns the canonical lifecycle listeners\n//? (`connect`, `disconnect`, `reconnect_attempt`, `userAfk`, `userBack`,\n//? `connect_error`). A consumer's `socketInitializer.ts` that also registers\n//? `disconnect`/`reconnect_attempt` on the same socket instance creates\n//? duplicate handlers — both fire on every event. Since `initSyncRequest` is\n//? idempotent (tears down the previous set before re-binding), consumer code\n//? should delegate lifecycle status updates here and avoid re-registering\n//? those events directly. Duplicate `console.log` in the consumer is harmless\n//? but produces double log lines.\nexport const initSyncRequest = async ({\n setSocketStatus,\n sessionRef\n}: {\n setSocketStatus: SocketStatusSetter;\n sessionRef: RefObject<SessionLayout | null> | null;\n}) => {\n\n if (!await waitForSocket()) { return; }\n if (!socket) { return; }\n if (!sessionRef) { return; }\n\n if (activeLifecycleHandlers) {\n socket.off(socketEventNames.connect, activeLifecycleHandlers.connect);\n socket.off(socketEventNames.disconnect, activeLifecycleHandlers.disconnect);\n socket.off(socketEventNames.reconnectAttempt, activeLifecycleHandlers.reconnectAttempt);\n socket.off(socketEventNames.userAfk, activeLifecycleHandlers.userAfk);\n socket.off(socketEventNames.userBack, activeLifecycleHandlers.userBack);\n socket.off(socketEventNames.connectError, activeLifecycleHandlers.connectError);\n }\n\n const connect = buildConnectHandler({ setSocketStatus });\n const disconnect = buildDisconnectHandler({ setSocketStatus });\n const reconnectAttempt = buildReconnectAttemptHandler({ setSocketStatus });\n const userAfk = buildUserAfkHandler({ setSocketStatus, sessionRef });\n const userBack = buildUserBackHandler({ setSocketStatus });\n const connectError = buildConnectErrorHandler({ setSocketStatus });\n\n activeLifecycleHandlers = {\n connect,\n disconnect,\n reconnectAttempt,\n userAfk,\n userBack,\n connectError,\n };\n\n socket.on(socketEventNames.connect, connect);\n socket.on(socketEventNames.disconnect, disconnect);\n socket.on(socketEventNames.reconnectAttempt, reconnectAttempt);\n socket.on(socketEventNames.userAfk, userAfk);\n socket.on(socketEventNames.userBack, userBack);\n socket.on(socketEventNames.connectError, connectError);\n\n}"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/syncRequest.ts"],"sourcesContent":["//? All cross-package imports go through `@luckystack/core/client` (the\n//? browser-safe subpath) — never the main `@luckystack/core` barrel which\n//? re-exports server-only modules (paths.ts, db.ts, redis.ts) that must\n//? not enter a Vite client bundle.\nimport type {\n BaseSessionLayout as SessionLayout,\n StreamPayload,\n SyncTypeMap,\n statusContent,\n} from \"@luckystack/core/client\";\nimport {\n getLogger,\n getProjectConfig,\n notify,\n incrementResponseIndex,\n socket,\n waitForSocket,\n enqueueSyncRequest,\n removeSyncQueueItem,\n isOnline,\n normalizeErrorResponseCore,\n parseServiceRouteName,\n buildSyncProgressEventName,\n buildSyncResponseEventName,\n socketEventNames,\n invokeRoutedHttp,\n} from \"@luckystack/core/client\";\nimport { Dispatch, RefObject, SetStateAction, useCallback, useEffect, useRef } from \"react\";\nimport { Socket } from \"socket.io-client\";\n\nexport type SyncRequestStreamEvent<T extends StreamPayload = StreamPayload> = T;\n\nexport type SyncRouteStreamEvent<T extends StreamPayload = StreamPayload> = T;\n\ntype SyncRequestStreamCallback = (event: SyncRequestStreamEvent) => void;\ntype SyncEventStreamCallback = (params: { stream: SyncRouteStreamEvent }) => void;\n\nconst shouldLogDev = () => getProjectConfig().logging.devLogs;\nconst shouldNotifyDev = () => getProjectConfig().logging.devNotifications;\nconst shouldLogSocketStatus = () => getProjectConfig().logging.socketStatus;\nconst shouldLogStream = () => getProjectConfig().logging.stream;\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// Type Helpers for Sync Requests\n// ═══════════════════════════════════════════════════════════════════════════════\n\n// Check if data input is required (i.e., T does NOT allow empty object)\n// Unions like {a:1} | {b:1} do NOT allow {}, so data will be required\ntype DataRequired<T> = Record<string, never> extends T ? false : true;\n\ntype UnionToIntersection<U> =\n (U extends unknown ? (arg: U) => void : never) extends ((arg: infer I) => void)\n ? I\n : never;\n\ntype Prettify<T> = { [K in keyof T]: T[K] } & {};\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// Global Sync Params\n// ═══════════════════════════════════════════════════════════════════════════════\n\n// All possible sync names across all pages\ntype SyncRouteRecord = UnionToIntersection<{\n [P in keyof SyncTypeMap]: {\n [N in keyof SyncTypeMap[P] as P extends 'root'\n ? `system/${Extract<N, string>}`\n : `${Extract<P, string>}/${Extract<N, string>}`]: SyncTypeMap[P][N]\n }\n}[keyof SyncTypeMap]>;\n\ntype SyncFullName = Extract<keyof SyncRouteRecord, string>;\ntype VersionsForFullName<F extends SyncFullName> = Extract<keyof SyncRouteRecord[F], string>;\n\ntype ClientInputForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> = SyncRouteRecord[F][V] extends { clientInput: infer I }\n ? I\n : never;\n\ntype ServerOutputForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> = SyncRouteRecord[F][V] extends { serverOutput: infer O }\n ? O\n : never;\n\ntype ClientOutputForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> = SyncRouteRecord[F][V] extends { clientOutput: infer O }\n ? O\n : never;\n\ntype ServerStreamForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> = SyncRouteRecord[F][V] extends { serverStream: infer O }\n ? O\n : never;\n\ntype ClientStreamForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> = SyncRouteRecord[F][V] extends { clientStream: infer O }\n ? O\n : never;\n\ntype SyncRequestStreamCallbackForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> =\n [ServerStreamForFullName<F, V>] extends [never]\n ? never\n : (event: SyncRequestStreamEvent<Prettify<ServerStreamForFullName<F, V> extends StreamPayload ? ServerStreamForFullName<F, V> : StreamPayload>>) => void;\n\n//? Recipients see chunks from THREE sources, all on the same wire channel:\n//? 1. `_client_v{n}.ts`'s `stream(...)` (per-recipient, runs after _server)\n//? 2. `_server_v{n}.ts`'s `broadcastStream(...)` (room-wide fan-out)\n//? 3. `_server_v{n}.ts`'s `streamTo(tokens, ...)` (selective fan-out)\n//? All three flow into `upsertSyncEventCallback`'s `stream` argument. Both\n//? serverStream and clientStream are folded into the union so the callback\n//? sees every shape the route can emit. If neither side ever streams, the\n//? callback type collapses to never (compile error to register one).\ntype CombinedRouteStream<F extends SyncFullName, V extends VersionsForFullName<F>> =\n | (ClientStreamForFullName<F, V> extends never ? never : ClientStreamForFullName<F, V>)\n | (ServerStreamForFullName<F, V> extends never ? never : ServerStreamForFullName<F, V>);\n\ntype SyncRouteStreamCallbackForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> =\n [CombinedRouteStream<F, V>] extends [never]\n ? never\n : (params: { stream: SyncRouteStreamEvent<Prettify<CombinedRouteStream<F, V> extends StreamPayload ? CombinedRouteStream<F, V> : StreamPayload>> }) => void;\n\ntype SyncParamsForFullName<\n F extends SyncFullName,\n V extends VersionsForFullName<F>\n> = DataRequired<ClientInputForFullName<F, V>> extends true\n ? {\n name: F;\n version: V;\n data: ClientInputForFullName<F, V>;\n receiver: string;\n ignoreSelf?: boolean;\n onStream?: SyncRequestStreamCallbackForFullName<F, V>;\n /**\n * Per-request override of `projectConfig.offlineQueue.dropPolicy`. Lets a\n * specific sync (\"editor cursor move\") pick `'drop-oldest'` while the\n * app default stays `'reject'` for safer sends. When omitted, falls back\n * to the global config.\n */\n offlineDropPolicy?: 'drop-oldest' | 'drop-newest' | 'reject';\n /**\n * Optional AbortSignal. When aborted the client emits `syncCancel { cb }`\n * to the server and resolves locally with\n * `{ status: 'error', errorCode: 'request.aborted' }`.\n */\n signal?: AbortSignal;\n }\n : {\n name: F;\n version: V;\n data?: ClientInputForFullName<F, V>;\n receiver: string;\n ignoreSelf?: boolean;\n onStream?: SyncRequestStreamCallbackForFullName<F, V>;\n /** Per-request override (see typed branch). */\n offlineDropPolicy?: 'drop-oldest' | 'drop-newest' | 'reject';\n /** Optional AbortSignal — see typed branch. */\n signal?: AbortSignal;\n };\n\ninterface RuntimeSyncParams {\n name?: string;\n version?: string;\n data?: unknown;\n receiver?: string;\n ignoreSelf?: boolean;\n onStream?: SyncRequestStreamCallback;\n offlineDropPolicy?: 'drop-oldest' | 'drop-newest' | 'reject';\n signal?: AbortSignal;\n}\n\ninterface SyncErrorParam { key: string; value: string | number | boolean };\n\ninterface SyncResponseError {\n status: 'error';\n message: string;\n errorCode: string;\n errorParams?: SyncErrorParam[];\n httpStatus?: number;\n}\n\ntype RoutedSyncFailureKind = 'timeout' | 'aborted' | 'network-error' | 'invalid-response';\n\nconst routedSyncErrorCode = (kind: RoutedSyncFailureKind): string => {\n if (kind === 'timeout') return 'sync.requestTimeout';\n if (kind === 'aborted') return 'request.aborted';\n if (kind === 'invalid-response') return 'sync.invalidServerResponse';\n return 'sync.ioUnavailable';\n};\n\ninterface SyncAckResponse {\n status?: 'success' | 'error';\n message?: string;\n result?: unknown;\n errorCode?: string;\n errorParams?: SyncErrorParam[];\n httpStatus?: number;\n}\n\ntype SyncResultForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> =\n [ServerOutputForFullName<F, V>] extends [never]\n ? Record<string, never>\n : ServerOutputForFullName<F, V>;\n\ntype SyncRequestResponseForFullName<F extends SyncFullName, V extends VersionsForFullName<F>> =\n | SyncResponseError\n | {\n status: 'success';\n message: string;\n result: SyncResultForFullName<F, V>;\n };\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// Sync Event Callbacks Registry\n// ═══════════════════════════════════════════════════════════════════════════════\n\ntype SyncEventCallback = (params: { clientOutput: unknown; serverOutput: unknown }) => void;\nconst syncEvents: Partial<Record<string, SyncEventCallback[]>> = {};\nconst syncStreamEvents: Partial<Record<string, SyncEventStreamCallback[]>> = {};\nconst noop = () => null;\n\ninterface SyncLifecycleHandlers {\n connect: () => void;\n disconnect: () => void;\n reconnectAttempt: (attempt: number) => void;\n userAfk: (payload: { userId: string; endTime?: number }) => void;\n userBack: (payload: { userId: string }) => void;\n connectError: (err: { message: string }) => void;\n}\n\nlet activeLifecycleHandlers: SyncLifecycleHandlers | null = null;\n\nconst canSendNow = (socketInstance: Socket) => {\n if (!socketInstance.connected) return false;\n return isOnline();\n};\n\nconst createQueueId = () => {\n return `${String(Date.now())}-${String(Math.random())}`;\n};\n\nconst getCallbacksForRoute = (route: string): SyncEventCallback[] => {\n syncEvents[route] ??= [];\n return syncEvents[route];\n};\n\nconst getStreamCallbacksForRoute = (route: string): SyncEventStreamCallback[] => {\n syncStreamEvents[route] ??= [];\n return syncStreamEvents[route];\n};\n\nconst triggerSyncCallbacks = (name: string, clientOutput: unknown, serverOutput: unknown) => {\n const callbacks = syncEvents[name] ?? [];\n if (callbacks.length === 0) {\n //? Streaming-only routes legitimately register ONLY a stream callback —\n //? the final success envelope is implicit in the stream completing. Only\n //? warn when NEITHER callback type is registered for the route.\n const streamCallbacks = syncStreamEvents[name] ?? [];\n if (streamCallbacks.length === 0 && shouldLogDev()) {\n getLogger().warn(`Sync event ${name} has no registered callback on this page`);\n }\n return;\n }\n\n for (const callback of callbacks) {\n callback({ clientOutput, serverOutput });\n }\n};\n\nconst triggerSyncStreamCallbacks = (name: string, stream: SyncRouteStreamEvent) => {\n const callbacks = syncStreamEvents[name] ?? [];\n if (callbacks.length === 0) {\n return;\n }\n\n for (const callback of callbacks) {\n callback({ stream });\n }\n};\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// syncRequest Function Overloads\n// ═══════════════════════════════════════════════════════════════════════════════\n\nconst normalizeSyncError = ({\n response,\n fallbackErrorCode,\n}: {\n response: SyncAckResponse;\n fallbackErrorCode: string;\n}): SyncResponseError => {\n const normalized = normalizeErrorResponseCore({\n response,\n fallbackErrorCode,\n resolveMessage: ({ errorCode }) => {\n if (typeof response.message === 'string' && response.message.trim().length > 0) {\n return response.message;\n }\n\n return errorCode;\n },\n });\n\n return {\n status: 'error',\n message: normalized.message,\n errorCode: normalized.errorCode,\n errorParams: normalized.errorParams,\n httpStatus: normalized.httpStatus,\n };\n};\n\ntype SyncRequestParamsWithOptions<F extends SyncFullName, V extends VersionsForFullName<F>> =\n SyncParamsForFullName<F, V>;\n\n//? Outcome of the pre-flight validation phase of a sync send. Either a\n//? normalized error envelope to resolve the request with, or the sanitized\n//? values the send phase needs. Extracted from `syncRequestInternal` so the\n//? \"validate first, execute second\" split is explicit (the orchestrator stays\n//? a thin promise wrapper around prepare → run).\ntype PreparedSyncRequest =\n | { ok: false; error: SyncResponseError }\n | { ok: true; sanitizedName: string; version: string; data: object; normalizedReceiver: string };\n\n//? Pure-ish validation chain (logs + dev-notifies on failure, same as the\n//? previous inlined block). Async because the socket-readiness gate\n//? (`waitForSocket`) is awaited last, after the cheap structural checks. Each\n//? failure path returns the SAME normalized error envelope the inlined code\n//? resolved with — behaviour-identical.\nconst prepareSyncRequest = async ({\n name,\n version,\n receiver,\n payloadData,\n}: {\n name: unknown;\n version: unknown;\n receiver: unknown;\n payloadData: unknown;\n}): Promise<PreparedSyncRequest> => {\n if (!name || typeof name !== \"string\") {\n if (shouldLogDev()) {\n getLogger().error(\"Invalid name for syncRequest\");\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'sync.invalidName' });\n }\n return { ok: false, error: normalizeSyncError({\n response: { status: 'error', errorCode: 'sync.invalidName' },\n fallbackErrorCode: 'sync.invalidName',\n }) };\n }\n\n const parsedRoute = parseServiceRouteName(name);\n if (parsedRoute.status === 'error') {\n if (shouldLogDev()) {\n getLogger().error(`[syncRequest] Invalid service route name '${name}'`, undefined, { reason: parsedRoute.reason });\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'routing.invalidServiceRouteName' });\n }\n return { ok: false, error: normalizeSyncError({\n response: {\n status: 'error',\n errorCode: 'routing.invalidServiceRouteName',\n errorParams: [{ key: 'name', value: name }],\n },\n fallbackErrorCode: 'routing.invalidServiceRouteName',\n }) };\n }\n\n const sanitizedName = parsedRoute.normalizedRouteName;\n\n const data = payloadData && typeof payloadData === \"object\" ? payloadData : {};\n\n if (!version || typeof version !== 'string') {\n if (shouldLogDev()) {\n getLogger().error(\"Invalid version for syncRequest\");\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'sync.invalidVersion' });\n }\n return { ok: false, error: normalizeSyncError({\n response: { status: 'error', errorCode: 'sync.invalidVersion' },\n fallbackErrorCode: 'sync.invalidVersion',\n }) };\n }\n\n const normalizedReceiver = typeof receiver === 'string' ? receiver.trim() : '';\n\n if (!normalizedReceiver) {\n if (shouldLogDev()) {\n getLogger().error(\"You need to provide a receiver for syncRequest, this can be either 'all' to trigger all sockets which we do not recommend or it can be any value such as a code e.g 'Ag2cg4'. this works together with the joinRoom and leaveRoom function\");\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'sync.missingReceiver' });\n }\n return { ok: false, error: normalizeSyncError({\n response: { status: 'error', errorCode: 'sync.missingReceiver' },\n fallbackErrorCode: 'sync.missingReceiver',\n }) };\n }\n\n if (!await waitForSocket()) {\n return { ok: false, error: normalizeSyncError({\n response: { status: 'error', errorCode: 'sync.ioUnavailable' },\n fallbackErrorCode: 'sync.ioUnavailable',\n }) };\n }\n if (!socket) {\n return { ok: false, error: normalizeSyncError({\n response: { status: 'error', errorCode: 'sync.ioUnavailable' },\n fallbackErrorCode: 'sync.ioUnavailable',\n }) };\n }\n\n return { ok: true, sanitizedName, version, data, normalizedReceiver };\n};\n\nconst syncRequestInternal = <F extends SyncFullName, V extends VersionsForFullName<F>>(\n params: SyncRequestParamsWithOptions<F, V>\n): Promise<Prettify<SyncRequestResponseForFullName<F, V>>> => {\n const runtimeParams = params as RuntimeSyncParams;\n const { name, version, receiver, ignoreSelf, onStream, offlineDropPolicy, signal: externalSignal } = runtimeParams;\n const payloadData = runtimeParams.data;\n\n type RequestOutput = Prettify<SyncRequestResponseForFullName<F, V>>;\n\n return new Promise<RequestOutput>((resolve) => {\n void (async () => {\n //? B1 — if the consumer-supplied signal is already aborted at call\n //? time, short-circuit before we even touch the socket.\n if (externalSignal?.aborted) {\n resolve(normalizeSyncError({\n response: { status: 'error', errorCode: 'request.aborted' },\n fallbackErrorCode: 'request.aborted',\n }));\n return;\n }\n\n const prepared = await prepareSyncRequest({ name, version, receiver, payloadData });\n if (!prepared.ok) {\n resolve(prepared.error);\n return;\n }\n const { sanitizedName, version: resolvedVersion, data, normalizedReceiver } = prepared;\n\n //? Re-narrow `socket` for the closures below. `prepareSyncRequest`\n //? already guaranteed it is non-null (returns an `ioUnavailable` error\n //? otherwise), but that guard lives in another function so TS can't\n //? carry the narrowing across the call boundary.\n const activeSocket = socket;\n if (!activeSocket) {\n resolve(normalizeSyncError({\n response: { status: 'error', errorCode: 'sync.ioUnavailable' },\n fallbackErrorCode: 'sync.ioUnavailable',\n }));\n return;\n }\n\n const fullName = `sync/${sanitizedName}/${resolvedVersion}`;\n let queueId: string | null = null;\n\n const runRequest = (socketInstance: Socket) => {\n if (!canSendNow(socketInstance)) {\n queueId ??= createQueueId();\n //? For the immediate reject-new path (`drop-newest` / `reject`\n //? policy) THIS item's `onDrop` fires SYNCHRONOUSLY inside\n //? `enqueueSyncRequest`. We keep surfacing that as the historical\n //? `offline.queueFull` via the `!enqueued` branch, so suppress the\n //? `onDrop` resolve during the synchronous enqueue window and re-arm\n //? it only if the item was actually queued (so a LATER async eviction\n //? — drop-oldest by a future enqueue, or age expiry — still settles).\n let suppressOnDrop = true;\n //? `enqueueSyncRequest` returns `false` when the offline queue is\n //? full and `dropPolicy: 'reject'` is active. Resolve with a\n //? normalized error envelope so the caller can branch instead of\n //? awaiting forever.\n const enqueued = enqueueSyncRequest({\n id: queueId,\n key: fullName,\n run: (s) => {\n runRequest(s);\n },\n createdAt: Date.now(),\n dropPolicy: offlineDropPolicy,\n //? SYNC-09 — settle the awaiting caller when this QUEUED request is\n //? later EVICTED (drop-oldest by a future enqueue / age expiry)\n //? instead of ever running. Without it the promise would hang\n //? forever, since `run` is the only thing that could otherwise\n //? resolve it. The default `offlineQueue.dropPolicy` is\n //? `'drop-oldest'`, so async eviction is the NORMAL overflow path\n //? for high-churn syncs (cursor moves), not an edge case.\n onDrop: (reason) => {\n if (suppressOnDrop) return;\n resolve(normalizeSyncError({\n response: { status: 'error', errorCode: 'offline.dropped', errorParams: [{ key: 'reason', value: reason }] },\n fallbackErrorCode: 'offline.dropped',\n }));\n },\n });\n //? Past the synchronous enqueue window: if the item is sitting in the\n //? queue, a future eviction should settle via `onDrop`.\n suppressOnDrop = false;\n if (!enqueued) {\n resolve(normalizeSyncError({\n response: { status: 'error', errorCode: 'offline.queueFull' },\n fallbackErrorCode: 'offline.queueFull',\n }));\n } else if (externalSignal && queueId) {\n const capturedQueueId = queueId;\n externalSignal.addEventListener('abort', () => {\n removeSyncQueueItem(capturedQueueId);\n resolve(normalizeSyncError({\n response: { status: 'error', errorCode: 'request.aborted' },\n fallbackErrorCode: 'request.aborted',\n }));\n }, { once: true });\n }\n return;\n }\n\n if (getProjectConfig().transport.invocation === 'routed-http') {\n void (async () => {\n const routed = await invokeRoutedHttp<SyncAckResponse, SyncRequestStreamEvent>({\n path: `/sync/${sanitizedName}/${resolvedVersion}`,\n method: 'POST',\n data: {\n data,\n receiver: normalizedReceiver,\n ignoreSelf: ignoreSelf ?? false,\n },\n stream: onStream,\n signals: [externalSignal],\n timeoutMs: getProjectConfig().sync.requestTimeoutMs,\n });\n if (queueId) removeSyncQueueItem(queueId);\n\n if (routed.kind !== 'response') {\n const errorCode = routedSyncErrorCode(routed.kind);\n resolve(normalizeSyncError({\n response: {\n status: 'error',\n errorCode,\n httpStatus: routed.kind === 'timeout' ? 504 : undefined,\n },\n fallbackErrorCode: errorCode,\n }));\n return;\n }\n\n const responseData = routed.response;\n if (responseData.status === 'error') {\n const normalizedError = normalizeSyncError({\n response: responseData,\n fallbackErrorCode: 'sync.failedRequest',\n });\n if (shouldNotifyDev()) {\n notify.error({ key: normalizedError.errorCode, params: normalizedError.errorParams });\n }\n resolve(normalizedError);\n return;\n }\n if (responseData.status !== 'success') {\n resolve(normalizeSyncError({\n response: responseData,\n fallbackErrorCode: 'sync.invalidServerResponse',\n }));\n return;\n }\n\n const result = responseData.result && typeof responseData.result === 'object'\n ? responseData.result\n : {};\n //? HTTP response boundary: generated route typing supplies the\n //? precise result shape, while JSON parsing necessarily starts at unknown.\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- routed response boundary\n resolve({\n status: 'success',\n message: typeof responseData.message === 'string' && responseData.message.trim().length > 0\n ? responseData.message\n : `sync ${sanitizedName} success`,\n result,\n } as RequestOutput);\n })();\n return;\n }\n\n const tempIndex = incrementResponseIndex();\n\n let cleanupProgressListener: (() => void) | null = null;\n //? CORE-06 — ack-timeout. Armed right after the request is emitted so a\n //? lost acknowledgement (server restart/crash between emit and reply)\n //? settles the promise with `sync.requestTimeout` (504) instead of\n //? hanging the awaiting caller forever. Mirrors `apiRequest`'s\n //? `api.requestTimeoutMs` wiring.\n let responseTimeout: ReturnType<typeof setTimeout> | null = null;\n const clearResponseTimeout = () => {\n if (responseTimeout) {\n clearTimeout(responseTimeout);\n responseTimeout = null;\n }\n };\n\n if (shouldLogDev()) {\n getLogger().debug(`Client Sync Request(${String(tempIndex)})`, { syncName: sanitizedName, data, receiver: normalizedReceiver, ignoreSelf });\n }\n\n //? S13 — server-issued cancel id. The server emits a `{ __cancelId }`\n //? handshake frame on the progress channel before any work runs; we\n //? capture it so an abort can target THIS exact request (not a callback\n //? name reused across concurrent same-route requests, which corrupted\n //? the server-side abort registry). The progress listener is ALWAYS\n //? registered now — even without `onStream` — so the handshake is caught\n //? on non-streaming routes too. The reserved `__cancelId` frame is\n //? filtered out of `onStream` delivery.\n let serverCancelId: string | null = null;\n const progressEventName = buildSyncProgressEventName(tempIndex);\n const progressListener = (streamPayload: SyncRequestStreamEvent & { __cancelId?: string }) => {\n if (typeof streamPayload.__cancelId === 'string') {\n serverCancelId = streamPayload.__cancelId;\n return;\n }\n\n if (typeof onStream !== 'function') return;\n\n if (shouldLogStream()) {\n getLogger().debug(`Server Sync Stream(${String(tempIndex)})`, { syncName: sanitizedName, streamPayload });\n }\n\n onStream(streamPayload);\n };\n\n socketInstance.on(progressEventName, progressListener);\n cleanupProgressListener = () => {\n socketInstance.off(progressEventName, progressListener);\n };\n\n //? Fallback cancel key for the narrow window before the `__cancelId`\n //? handshake frame arrives (abort fired immediately on a slow link).\n //? Best-effort only — once the handshake lands `serverCancelId` is the\n //? authoritative, per-request-unique key the server registered under.\n const syncCb = `${sanitizedName}/${resolvedVersion}`;\n socketInstance.emit(socketEventNames.sync, { name: fullName, data, cb: syncCb, receiver: normalizedReceiver, responseIndex: tempIndex, ignoreSelf });\n\n //? B1 / S13 — bridge the consumer's AbortSignal to the server. When the\n //? signal fires we emit `syncCancel { cb: <serverCancelId> }` so the\n //? server-side handler stops emitting new chunks. We also resolve\n //? locally with `request.aborted` so the awaiting caller settles.\n const responseEventName = buildSyncResponseEventName(tempIndex);\n //? Forward-declared so the abort/timeout paths can proactively `off()`\n //? the lingering ack listener instead of waiting for a reply that was\n //? cancelled / will never arrive.\n let cleanupResponseListener: (() => void) | null = null;\n\n let cleanupExternalAbort: (() => void) | null = null;\n if (externalSignal) {\n const externalAbortHandler = () => {\n clearResponseTimeout();\n socketInstance.emit(socketEventNames.syncCancel, { cb: serverCancelId ?? syncCb });\n cleanupProgressListener?.();\n cleanupProgressListener = null;\n cleanupResponseListener?.();\n cleanupResponseListener = null;\n cleanupExternalAbort?.();\n cleanupExternalAbort = null;\n resolve(normalizeSyncError({\n response: { status: 'error', errorCode: 'request.aborted' },\n fallbackErrorCode: 'request.aborted',\n }));\n };\n externalSignal.addEventListener('abort', externalAbortHandler);\n cleanupExternalAbort = () => {\n externalSignal.removeEventListener('abort', externalAbortHandler);\n };\n }\n\n //? Arm the ack-timeout. `sync.requestTimeoutMs` (default 30000) may be\n //? `false` to disable. On expiry we tear down every listener and settle\n //? with a 504 envelope so the awaiting caller never hangs.\n const effectiveTimeoutMs = getProjectConfig().sync.requestTimeoutMs;\n if (typeof effectiveTimeoutMs === 'number' && effectiveTimeoutMs > 0) {\n responseTimeout = setTimeout(() => {\n responseTimeout = null;\n //? SYNC — on ack-timeout, tell the server to STOP the in-flight work\n //? before tearing down locally. Previously the timeout only cleaned up\n //? the client listeners + settled 504, leaving the `_server` handler\n //? (and any fanout/streaming) running to completion uncancelled. The\n //? `__cancelId` handshake has long since arrived by the timeout window\n //? (the server emits it immediately), so `serverCancelId` is the\n //? authoritative key here; `syncCb` is only the sub-RTT fallback.\n socketInstance.emit(socketEventNames.syncCancel, { cb: serverCancelId ?? syncCb });\n cleanupProgressListener?.();\n cleanupProgressListener = null;\n cleanupResponseListener?.();\n cleanupResponseListener = null;\n cleanupExternalAbort?.();\n cleanupExternalAbort = null;\n if (shouldLogDev()) {\n getLogger().error(`Sync ${sanitizedName} timed out`, undefined, { responseIndex: tempIndex });\n }\n resolve(normalizeSyncError({\n response: { status: 'error', errorCode: 'sync.requestTimeout', httpStatus: 504 },\n fallbackErrorCode: 'sync.requestTimeout',\n }));\n }, effectiveTimeoutMs);\n }\n\n const responseListener = (responseData: SyncAckResponse) => {\n clearResponseTimeout();\n cleanupProgressListener?.();\n cleanupProgressListener = null;\n cleanupResponseListener = null;\n cleanupExternalAbort?.();\n cleanupExternalAbort = null;\n\n if (responseData.status === \"error\") {\n const normalizedError = normalizeSyncError({\n response: responseData,\n fallbackErrorCode: 'sync.failedRequest',\n });\n\n if (shouldLogDev()) {\n getLogger().error(`Sync ${sanitizedName} failed`, undefined, { message: normalizedError.message });\n }\n if (shouldNotifyDev()) {\n notify.error({\n key: 'sync.failedRequest',\n params: [\n { key: 'name', value: sanitizedName },\n { key: 'message', value: normalizedError.message },\n ],\n });\n }\n resolve(normalizedError);\n return;\n }\n\n if (responseData.status !== 'success') {\n resolve(normalizeSyncError({\n response: responseData,\n fallbackErrorCode: 'sync.invalidServerResponse',\n }));\n return;\n }\n\n const result = responseData.result && typeof responseData.result === 'object'\n ? responseData.result\n : {};\n\n //? `RequestOutput.result` is a generic `Record<string, never>` shape\n //? that the runtime response can't structurally satisfy from the\n //? untyped `responseData.result` (server-side typing lives on the\n //? other side of the socket). The cast is the documented socket\n //? response boundary.\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- socket response boundary\n resolve({\n status: 'success',\n message: typeof responseData.message === 'string' && responseData.message.trim().length > 0\n ? responseData.message\n : `sync ${sanitizedName} success`,\n result,\n } as RequestOutput);\n };\n\n socketInstance.once(responseEventName, responseListener);\n cleanupResponseListener = () => {\n socketInstance.off(responseEventName, responseListener);\n };\n };\n\n runRequest(activeSocket);\n })();\n });\n};\n\nexport function syncRequest<F extends SyncFullName, V extends VersionsForFullName<F>>(\n params: SyncRequestParamsWithOptions<F, V>\n): Promise<Prettify<SyncRequestResponseForFullName<F, V>>> {\n return syncRequestInternal(params);\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// useSyncEvents Hook - Type-Safe Event Registration\n// ═══════════════════════════════════════════════════════════════════════════════\n\n//? Hoisted to module scope so the emitted `.d.ts` for `useSyncEvents` can\n//? reference them. Local interface declarations inside an exported function\n//? trigger TS4025 (\"has or is using private name\") under `declaration: true`.\ninterface TypedCallbackParams<F extends SyncFullName, V extends VersionsForFullName<F>> {\n clientOutput: ClientOutputForFullName<F, V>;\n serverOutput: ServerOutputForFullName<F, V>;\n}\n\ninterface UpsertParams<F extends SyncFullName, V extends VersionsForFullName<F>> {\n name: F;\n version: V;\n callback: (params: TypedCallbackParams<F, V>) => void;\n}\n\ninterface UpsertStreamParams<F extends SyncFullName, V extends VersionsForFullName<F>> {\n name: F;\n version: V;\n callback: SyncRouteStreamCallbackForFullName<F, V>;\n}\n\nexport const useSyncEvents = () => {\n const localRegistryRef = useRef<Map<string, SyncEventCallback>>(new Map());\n const localStreamRegistryRef = useRef<Map<string, SyncEventStreamCallback>>(new Map());\n\n const upsertSyncEventCallback = useCallback(<F extends SyncFullName, V extends VersionsForFullName<F>>(\n params: UpsertParams<F, V>\n ): (() => void) => {\n\n if (typeof params.version !== 'string') {\n if (shouldLogDev()) {\n getLogger().error(\"Invalid version for upsertSyncEventCallback\");\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'sync.invalidVersion' });\n }\n return noop;\n }\n\n if (typeof params.callback !== 'function') {\n if (shouldLogDev()) {\n getLogger().error(\"Invalid callback for upsertSyncEventCallback\");\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'sync.invalidCallback' });\n }\n return noop;\n }\n\n const routeName = params.name;\n const parsedRoute = parseServiceRouteName(routeName);\n if (parsedRoute.status === 'error') {\n if (shouldLogDev()) {\n getLogger().error(`Invalid name for upsertSyncEventCallback`, undefined, { routeName, reason: parsedRoute.reason });\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'routing.invalidServiceRouteName' });\n }\n return noop;\n }\n const sanitizedName = parsedRoute.normalizedRouteName;\n\n const routeVersion = params.version;\n const fullName = `sync/${sanitizedName}/${routeVersion}`;\n const callback: SyncEventCallback = ({ clientOutput, serverOutput }) => {\n params.callback({\n clientOutput: clientOutput as ClientOutputForFullName<F, V>,\n serverOutput: serverOutput as ServerOutputForFullName<F, V>,\n });\n };\n const callbacks = getCallbacksForRoute(fullName);\n\n const previousForRoute = localRegistryRef.current.get(fullName);\n if (previousForRoute) {\n syncEvents[fullName] = callbacks.filter((cb) => cb !== previousForRoute);\n }\n\n const nextCallbacks = getCallbacksForRoute(fullName);\n // Multiple components can intentionally subscribe to the same sync event.\n // Only warn when the exact same callback is registered twice.\n if (nextCallbacks.includes(callback)) {\n if (shouldLogDev()) {\n getLogger().warn(`[SyncEvents] Duplicate callback registration was ignored`, { fullName });\n }\n\n localRegistryRef.current.set(fullName, callback);\n\n return () => {\n const current = getCallbacksForRoute(fullName);\n syncEvents[fullName] = current.filter((cb) => cb !== callback);\n\n if (localRegistryRef.current.get(fullName) === callback) {\n localRegistryRef.current.delete(fullName);\n }\n };\n }\n\n nextCallbacks.push(callback);\n syncEvents[fullName] = nextCallbacks;\n localRegistryRef.current.set(fullName, callback);\n\n return () => {\n const current = getCallbacksForRoute(fullName);\n syncEvents[fullName] = current.filter((cb) => cb !== callback);\n\n if (localRegistryRef.current.get(fullName) === callback) {\n localRegistryRef.current.delete(fullName);\n }\n };\n }, []);\n\n const upsertSyncEventStreamCallback = useCallback(<F extends SyncFullName, V extends VersionsForFullName<F>>(\n params: UpsertStreamParams<F, V>\n ): (() => void) => {\n\n if (typeof params.version !== 'string') {\n if (shouldLogDev()) {\n getLogger().error(\"Invalid version for upsertSyncEventStreamCallback\");\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'sync.invalidVersion' });\n }\n return noop;\n }\n\n if (typeof params.callback !== 'function') {\n if (shouldLogDev()) {\n getLogger().error(\"Invalid callback for upsertSyncEventStreamCallback\");\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'sync.invalidCallback' });\n }\n return noop;\n }\n\n const routeName = params.name;\n const parsedRoute = parseServiceRouteName(routeName);\n if (parsedRoute.status === 'error') {\n if (shouldLogDev()) {\n getLogger().error(`Invalid name for upsertSyncEventStreamCallback`, undefined, { routeName, reason: parsedRoute.reason });\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'routing.invalidServiceRouteName' });\n }\n return noop;\n }\n const sanitizedName = parsedRoute.normalizedRouteName;\n\n const routeVersion = params.version;\n const fullName = `sync/${sanitizedName}/${routeVersion}`;\n //? Combined union: both `serverStream` (from `broadcastStream` /\n //? `streamTo`) and `clientStream` (from `_client_v{n}.ts`) flow through\n //? this callback. The type matches `SyncRouteStreamCallbackForFullName`.\n const typedCallback = params.callback as (params: {\n stream: SyncRouteStreamEvent<Prettify<CombinedRouteStream<F, V> extends StreamPayload ? CombinedRouteStream<F, V> : StreamPayload>>;\n }) => void;\n const callback: SyncEventStreamCallback = ({ stream }) => {\n typedCallback({\n stream: stream as SyncRouteStreamEvent<Prettify<CombinedRouteStream<F, V> extends StreamPayload ? CombinedRouteStream<F, V> : StreamPayload>>,\n });\n };\n const callbacks = getStreamCallbacksForRoute(fullName);\n\n const previousForRoute = localStreamRegistryRef.current.get(fullName);\n if (previousForRoute) {\n syncStreamEvents[fullName] = callbacks.filter((cb) => cb !== previousForRoute);\n }\n\n const nextCallbacks = getStreamCallbacksForRoute(fullName);\n if (nextCallbacks.includes(callback)) {\n if (shouldLogDev()) {\n getLogger().warn(`[SyncEvents] Duplicate stream callback registration was ignored`, { fullName });\n }\n\n localStreamRegistryRef.current.set(fullName, callback);\n\n return () => {\n const current = getStreamCallbacksForRoute(fullName);\n syncStreamEvents[fullName] = current.filter((cb) => cb !== callback);\n\n if (localStreamRegistryRef.current.get(fullName) === callback) {\n localStreamRegistryRef.current.delete(fullName);\n }\n };\n }\n\n nextCallbacks.push(callback);\n syncStreamEvents[fullName] = nextCallbacks;\n localStreamRegistryRef.current.set(fullName, callback);\n\n return () => {\n const current = getStreamCallbacksForRoute(fullName);\n syncStreamEvents[fullName] = current.filter((cb) => cb !== callback);\n\n if (localStreamRegistryRef.current.get(fullName) === callback) {\n localStreamRegistryRef.current.delete(fullName);\n }\n };\n }, []);\n\n useEffect(() => {\n const localRegistry = localRegistryRef.current;\n const localStreamRegistry = localStreamRegistryRef.current;\n\n return () => {\n for (const [fullName, callback] of localRegistry.entries()) {\n const current = getCallbacksForRoute(fullName);\n syncEvents[fullName] = current.filter((cb) => cb !== callback);\n }\n\n for (const [fullName, callback] of localStreamRegistry.entries()) {\n const current = getStreamCallbacksForRoute(fullName);\n syncStreamEvents[fullName] = current.filter((cb) => cb !== callback);\n }\n\n localRegistry.clear();\n localStreamRegistry.clear();\n };\n }, []);\n\n return { upsertSyncEventCallback, upsertSyncEventStreamCallback };\n}\n\nexport const useSyncEventTrigger = () => {\n const triggerSyncEvent = useCallback((name: string, clientOutput: unknown = {}, serverOutput: unknown = {}) => {\n triggerSyncCallbacks(name, clientOutput, serverOutput);\n }, []);\n\n const triggerSyncStreamEvent = useCallback((name: string, stream: SyncRouteStreamEvent) => {\n triggerSyncStreamCallbacks(name, stream);\n }, []);\n\n return { triggerSyncEvent, triggerSyncStreamEvent }\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// Sync Receive Bridge — attachSyncReceiver\n// ═══════════════════════════════════════════════════════════════════════════════\n\n//? Shape of the `sync` socket event the server emits to clients. Mirrors the\n//? server's emit payload; extra keys are stream chunk fields.\ninterface SyncEventPayload {\n cb?: string;\n clientOutput?: unknown;\n serverOutput?: unknown;\n message?: string;\n status?: 'success' | 'error' | 'stream';\n fullName?: string;\n errorCode?: string;\n errorParams?: { key: string; value: string | number | boolean }[];\n httpStatus?: number;\n [key: string]: unknown;\n}\n\nconst normalizeSyncRouteKey = (value: string): string => {\n const sanitized = value.replaceAll(/^\\/+|\\/+$/g, '');\n if (sanitized.length === 0) return '';\n if (sanitized.startsWith('sync/')) return sanitized;\n return `sync/${sanitized}`;\n};\n\nconst getSyncRouteKeys = ({ fullName, cb }: { fullName?: string; cb?: string }): string[] => {\n const keys = new Set<string>();\n if (typeof fullName === 'string') {\n const normalized = normalizeSyncRouteKey(fullName);\n if (normalized) keys.add(normalized);\n }\n if (typeof cb === 'string') {\n const normalized = normalizeSyncRouteKey(cb);\n if (normalized) keys.add(normalized);\n }\n return [...keys];\n};\n\n//? Per-socket idempotency guard — attaching twice to the same socket would\n//? double-dispatch every sync event.\nconst attachedSyncSockets = new WeakSet<Socket>();\n\n//? Wire the incoming `sync` socket listener that routes server fan-out into the\n//? registered `upsertSyncEventCallback` / `upsertSyncEventStreamCallback`\n//? subscribers. Previously this logic was inlined in the consumer's\n//? `socketInitializer.ts`; relocating it here makes `@luckystack/sync` own its\n//? own receive path, so a consumer only has to dynamic-import this and call it\n//? (the add-later sync wiring is then a single line, not a copy-paste block).\nexport const attachSyncReceiver = (socketInstance: Socket): void => {\n if (attachedSyncSockets.has(socketInstance)) return;\n attachedSyncSockets.add(socketInstance);\n\n socketInstance.on(socketEventNames.sync, (payload: SyncEventPayload) => {\n const { cb, clientOutput, serverOutput, message, status, fullName, errorCode, errorParams } = payload;\n if (shouldLogDev()) {\n getLogger().debug('Server Sync Response', { payload });\n }\n\n const routeKeys = getSyncRouteKeys({ fullName, cb });\n\n if (status === 'stream') {\n if (routeKeys.length === 0) return;\n\n //? SYNC-N7 — strip all reserved envelope keys from the forwarded stream\n //? payload so a consumer handler that accidentally emits `errorCode`,\n //? `errorParams`, `httpStatus`, or `message` in a stream chunk doesn't\n //? pollute the client callback's stream argument with error-envelope fields.\n //? `status`, `fullName`, `cb` were already stripped; the others are added here.\n const streamPayload = { ...payload };\n delete streamPayload.status;\n delete streamPayload.fullName;\n delete streamPayload.cb;\n delete streamPayload.errorCode;\n delete streamPayload.errorParams;\n delete streamPayload.httpStatus;\n delete streamPayload.message;\n\n if (shouldLogStream()) {\n getLogger().debug('Server Sync Stream', { routeKeys, streamPayload });\n }\n\n for (const routeKey of routeKeys) {\n triggerSyncStreamCallbacks(routeKey, streamPayload);\n }\n return;\n }\n\n if (status === 'error') {\n if (errorCode === 'sync.ignore' || message === 'sync.ignore') return;\n if (shouldNotifyDev()) {\n if (errorCode) {\n notify.error({ key: errorCode, params: errorParams });\n } else if (message) {\n notify.error({ key: message });\n }\n }\n return;\n }\n\n if (routeKeys.length === 0) {\n const errorMessage = `Sync response is missing fullName for cb '${cb ?? 'unknown'}'.`;\n if (shouldLogDev()) {\n getLogger().error(errorMessage);\n }\n if (shouldNotifyDev()) {\n notify.error({ key: 'sync.invalidRequestFormat' });\n }\n //? SYNC-10 — degrade to a logged warning instead of throwing. This runs\n //? inside the `socket.on(sync)` listener; a `throw` here is an uncaught\n //? exception on a server-controlled (malformed) frame that can kill other\n //? listeners bound to the same emit. The error is already logged + notified\n //? above, so `return` loses no information.\n return;\n }\n\n for (const routeKey of routeKeys) {\n triggerSyncCallbacks(routeKey, clientOutput, serverOutput);\n }\n });\n};\n\ntype SocketStatusSetter = Dispatch<\n SetStateAction<{\n self: statusContent;\n [userId: string]: statusContent;\n }>\n>;\n\nconst buildConnectHandler = ({ setSocketStatus }: { setSocketStatus: SocketStatusSetter }) => () => {\n if (shouldLogSocketStatus()) getLogger().info(\"Connected to server\");\n setSocketStatus(prev => ({ ...prev, self: { ...prev.self, status: \"CONNECTED\" } }));\n};\n\nconst buildDisconnectHandler = ({ setSocketStatus }: { setSocketStatus: SocketStatusSetter }) => () => {\n setSocketStatus(prev => ({ ...prev, self: { ...prev.self, status: \"DISCONNECTED\" } }));\n if (shouldLogSocketStatus()) getLogger().info(\"Disconnected, trying to reconnect...\");\n};\n\nconst buildReconnectAttemptHandler = ({ setSocketStatus }: { setSocketStatus: SocketStatusSetter }) => (attempt: number) => {\n setSocketStatus(prev => ({ ...prev, self: { ...prev.self, status: \"RECONNECTING\", reconnectAttempt: attempt } }));\n if (shouldLogSocketStatus()) getLogger().info(`Reconnecting attempt ${String(attempt)}...`);\n};\n\nconst buildUserAfkHandler = ({\n setSocketStatus, sessionRef,\n}: {\n setSocketStatus: SocketStatusSetter;\n sessionRef: RefObject<SessionLayout | null>;\n}) => ({ userId, endTime }: { userId: string; endTime?: number }) => {\n if (sessionRef.current !== null && userId === sessionRef.current.id) {\n setSocketStatus(prev => ({\n ...prev,\n self: { status: \"DISCONNECTED\", reconnectAttempt: undefined, endTime },\n }));\n } else {\n setSocketStatus(prev => ({\n ...prev,\n [userId]: { status: \"DISCONNECTED\", endTime },\n }));\n }\n};\n\nconst buildUserBackHandler = ({ setSocketStatus }: { setSocketStatus: SocketStatusSetter }) => ({ userId }: { userId: string }) => {\n if (shouldLogSocketStatus()) getLogger().debug(\"userBack\", { userId });\n setSocketStatus(prev => ({\n ...prev,\n [userId]: { status: \"CONNECTED\", endTime: undefined },\n }));\n};\n\nconst buildConnectErrorHandler = ({ setSocketStatus }: { setSocketStatus: SocketStatusSetter }) => (err: { message: string }) => {\n if (shouldLogSocketStatus()) getLogger().debug(\"connect_error\", { err });\n setSocketStatus(prev => ({\n ...prev,\n self: { ...prev.self, status: \"DISCONNECTED\", reconnectAttempt: undefined },\n }));\n if (shouldLogDev()) getLogger().error(`Connection error`, err);\n if (shouldNotifyDev()) notify.error({ key: 'common.connectionError' });\n};\n\n//? SYNC-N6 — `initSyncRequest` owns the canonical lifecycle listeners\n//? (`connect`, `disconnect`, `reconnect_attempt`, `userAfk`, `userBack`,\n//? `connect_error`). A consumer's `socketInitializer.ts` that also registers\n//? `disconnect`/`reconnect_attempt` on the same socket instance creates\n//? duplicate handlers — both fire on every event. Since `initSyncRequest` is\n//? idempotent (tears down the previous set before re-binding), consumer code\n//? should delegate lifecycle status updates here and avoid re-registering\n//? those events directly. Duplicate `console.log` in the consumer is harmless\n//? but produces double log lines.\nexport const initSyncRequest = async ({\n setSocketStatus,\n sessionRef\n}: {\n setSocketStatus: SocketStatusSetter;\n sessionRef: RefObject<SessionLayout | null> | null;\n}) => {\n\n if (!await waitForSocket()) { return; }\n if (!socket) { return; }\n if (!sessionRef) { return; }\n\n if (activeLifecycleHandlers) {\n socket.off(socketEventNames.connect, activeLifecycleHandlers.connect);\n socket.off(socketEventNames.disconnect, activeLifecycleHandlers.disconnect);\n socket.off(socketEventNames.reconnectAttempt, activeLifecycleHandlers.reconnectAttempt);\n socket.off(socketEventNames.userAfk, activeLifecycleHandlers.userAfk);\n socket.off(socketEventNames.userBack, activeLifecycleHandlers.userBack);\n socket.off(socketEventNames.connectError, activeLifecycleHandlers.connectError);\n }\n\n const connect = buildConnectHandler({ setSocketStatus });\n const disconnect = buildDisconnectHandler({ setSocketStatus });\n const reconnectAttempt = buildReconnectAttemptHandler({ setSocketStatus });\n const userAfk = buildUserAfkHandler({ setSocketStatus, sessionRef });\n const userBack = buildUserBackHandler({ setSocketStatus });\n const connectError = buildConnectErrorHandler({ setSocketStatus });\n\n activeLifecycleHandlers = {\n connect,\n disconnect,\n reconnectAttempt,\n userAfk,\n userBack,\n connectError,\n };\n\n socket.on(socketEventNames.connect, connect);\n socket.on(socketEventNames.disconnect, disconnect);\n socket.on(socketEventNames.reconnectAttempt, reconnectAttempt);\n socket.on(socketEventNames.userAfk, userAfk);\n socket.on(socketEventNames.userBack, userBack);\n socket.on(socketEventNames.connectError, connectError);\n\n}"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
declare const SYNC_ERROR_CODES: readonly ["sync.invalidName", "sync.invalidVersion", "sync.missingReceiver", "sync.ioUnavailable", "sync.failedRequest", "sync.invalidServerResponse", "sync.invalidRequestFormat", "sync.requestTimeout", "sync.invalidRequest", "sync.invalidCallback", "sync.notFound", "sync.rateLimitExceeded", "sync.invalidInputType", "sync.serverExecutionFailed", "sync.receiverNotAllowed", "sync.notRoomMember", "sync.noReceiversFound", "sync.clientExecutionFailed", "sync.invalidClientResponse", "sync.clientRejected", "sync.disabled", "sync.methodNotAllowed", "sync.devToolsUnavailable"];
|
|
2
|
+
/** Union of every framework-emitted `sync.*` error code. */
|
|
3
|
+
type SyncErrorCode = (typeof SYNC_ERROR_CODES)[number];
|
|
4
|
+
|
|
5
|
+
export { SYNC_ERROR_CODES as S, type SyncErrorCode as a };
|
package/dist/index.d.ts
CHANGED