@luckystack/sync 0.13.0 → 0.15.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 +19 -0
- package/dist/_shared/clientFanout.d.ts +1 -2
- package/dist/_shared/errorCodes.d.ts +1 -1
- package/dist/_shared/physicalReceiver.d.ts +4 -0
- package/dist/_shared/redactToken.d.ts +8 -0
- package/dist/_shared/streamEmitters.d.ts +6 -2
- package/dist/{chunk-AJ36D2PQ.js → chunk-IFVFF47D.js} +2 -1
- package/dist/{chunk-AJ36D2PQ.js.map → chunk-IFVFF47D.js.map} +1 -1
- package/dist/client.js +19 -3
- package/dist/client.js.map +1 -1
- package/dist/handleHttpSyncRequest.d.ts +6 -0
- package/dist/index.js +149 -116
- package/dist/index.js.map +1 -1
- package/docs/room-fanout.md +5 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,25 @@ 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
|
+
## [0.15.0] - 2026-10-19
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **Breaking:** the HTTP/SSE sync transport answers the sender as soon as the change is saved and `preSyncFanout` allows delivery; delivery to recipients continues in the background. That is the point where websockets already answered (ADR 0071). Before, a slow fan-out to a large room could time out the sender after the change was saved, and a retry applied it twice. Upgrade: don't assume recipients have been reached when an HTTP sync call resolves; code or tests that need delivery to be complete should listen to the `postSyncFanout` hook.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **`broadcastStream` to receiver `'all'` reaches every connected socket** across instances, like the final fan-out. It used to target a literal room called `'all'` and reached nobody.
|
|
17
|
+
- **Syncing to your own session token works under a custom room-name formatter.** It failed with `sync.notRoomMember` over websockets and `sync.noReceiversFound` over HTTP; the token room is now addressed unformatted, the same way it is joined.
|
|
18
|
+
- **The error tracker no longer stores the raw session token as `receiver`** when a sync targets a token room. It is shortened to its first 4 characters, as `targetToken` already was.
|
|
19
|
+
- **The socket status reaches `RECONNECTING` with the attempt number during reconnects.** socket.io-client v4 emits `reconnect_attempt` only on the Manager, so the listener on the Socket never fired.
|
|
20
|
+
- **A socket `syncRequest` whose connection drops before the acknowledgement settles at once with the new error code `sync.disconnected`** (added to `SYNC_ERROR_CODES`), like `apiRequest` does with `api.disconnected`. Before, it waited for `sync.requestTimeoutMs` (30 s), or forever with the timeout disabled, and leaked two listeners. Projects with their own locale files should add a `sync.disconnected` translation; the scaffold's locales have it from `create-luckystack-app` 0.15.0.
|
|
21
|
+
|
|
22
|
+
### Security
|
|
23
|
+
|
|
24
|
+
- **Over the HTTP/SSE transport a room member could choose the callback name other members received** (`cb` in the request body), and so trigger another route's callbacks with data that never passed that route's server checks. Recipients now always receive the server-resolved route name, as on websockets; the body `cb` is ignored.
|
|
25
|
+
- **Stream chunks from `broadcastStream`, `streamTo` and a `_client` handler's `stream` carried the sender's callback name** on both transports, so they could trigger another route's stream callbacks. They are now keyed on the server-resolved route.
|
|
26
|
+
|
|
8
27
|
## [0.12.0] - 2026-10-15
|
|
9
28
|
|
|
10
29
|
### Changed
|
|
@@ -14,7 +14,6 @@ export interface ProcessClientSyncForRecipientArgs<TError extends object> {
|
|
|
14
14
|
serverOutput: unknown;
|
|
15
15
|
receiver: string;
|
|
16
16
|
resolvedName: string;
|
|
17
|
-
callbackKey: string;
|
|
18
17
|
transport: 'socket' | 'http';
|
|
19
18
|
handlerName: 'handleSyncRequest' | 'handleHttpSyncRequest';
|
|
20
19
|
logLabel: 'sync' | 'http sync';
|
|
@@ -35,5 +34,5 @@ export interface ProcessClientSyncForRecipientArgs<TError extends object> {
|
|
|
35
34
|
* because it does not run the handler). Behaviour-identical to the previously
|
|
36
35
|
* inlined loop body in both transports.
|
|
37
36
|
*/
|
|
38
|
-
export declare const processClientSyncForRecipient: <TError extends object>({ tempSocket, tempToken, clientSyncHandler, data, functionsObject, serverOutput, receiver, resolvedName,
|
|
37
|
+
export declare const processClientSyncForRecipient: <TError extends object>({ tempSocket, tempToken, clientSyncHandler, data, functionsObject, serverOutput, receiver, resolvedName, transport, handlerName, logLabel, shouldLogDev, shouldLogStream, buildSyncError, resolvePreferredLocale, sourceUserId, }: ProcessClientSyncForRecipientArgs<TError>) => Promise<void>;
|
|
39
38
|
export {};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export 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'];
|
|
1
|
+
export declare const SYNC_ERROR_CODES: readonly ['sync.invalidName', 'sync.invalidVersion', 'sync.missingReceiver', 'sync.ioUnavailable', 'sync.failedRequest', 'sync.invalidServerResponse', 'sync.invalidRequestFormat', 'sync.requestTimeout', 'sync.disconnected', '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
2
|
/** Union of every framework-emitted `sync.*` error code. */
|
|
3
3
|
export type SyncErrorCode = (typeof SYNC_ERROR_CODES)[number];
|
|
@@ -4,6 +4,14 @@
|
|
|
4
4
|
* than the visible prefix.
|
|
5
5
|
*/
|
|
6
6
|
export declare const redactToken: (token: string | null) => string | null;
|
|
7
|
+
/**
|
|
8
|
+
* Redact a sync `receiver` for the error-tracker context when it is a session
|
|
9
|
+
* token room. A token room's NAME is the bearer token, so a raw `receiver` there
|
|
10
|
+
* leaks the credential exactly like a raw `targetToken` would. Ordinary room
|
|
11
|
+
* codes pass through unchanged so tracker events stay debuggable. `knownTokens`
|
|
12
|
+
* are the tokens the call site can compare against (requester and/or recipient).
|
|
13
|
+
*/
|
|
14
|
+
export declare const redactTokenRoom: (receiver: string, knownTokens: readonly (string | null | undefined)[]) => string;
|
|
7
15
|
/**
|
|
8
16
|
* Redact a list of tokens (e.g. the `streamTo` recipient list) for logging.
|
|
9
17
|
*/
|
|
@@ -19,8 +19,12 @@ export interface SyncStreamEmitters {
|
|
|
19
19
|
flushPressure: FlushPressure;
|
|
20
20
|
}
|
|
21
21
|
interface BuildSyncStreamEmittersArgs {
|
|
22
|
-
cb: string | undefined;
|
|
23
22
|
receiver: string;
|
|
23
|
+
/**
|
|
24
|
+
* Session token of the request originator (or null when anonymous). Its own
|
|
25
|
+
* token room is joined raw, so `broadcastStream` must not format it.
|
|
26
|
+
*/
|
|
27
|
+
token: string | null;
|
|
24
28
|
/**
|
|
25
29
|
* Session user id of the request originator (or null when anonymous). Threaded
|
|
26
30
|
* through so `broadcastStream` / `flushPressure` can route the receiver room
|
|
@@ -47,5 +51,5 @@ interface BuildSyncStreamEmittersArgs {
|
|
|
47
51
|
*/
|
|
48
52
|
originatorSocket?: Socket;
|
|
49
53
|
}
|
|
50
|
-
export declare const buildSyncStreamEmitters: ({
|
|
54
|
+
export declare const buildSyncStreamEmitters: ({ receiver, token, userId, resolvedName, emitOriginatorChunk, logLabel, signal, originatorSocket, }: BuildSyncStreamEmittersArgs) => SyncStreamEmitters;
|
|
51
55
|
export {};
|
|
@@ -9,6 +9,7 @@ var SYNC_ERROR_CODES = [
|
|
|
9
9
|
"sync.invalidServerResponse",
|
|
10
10
|
"sync.invalidRequestFormat",
|
|
11
11
|
"sync.requestTimeout",
|
|
12
|
+
"sync.disconnected",
|
|
12
13
|
//? `handleSyncRequest` / `handleHttpSyncRequest` (both transports)
|
|
13
14
|
"sync.invalidRequest",
|
|
14
15
|
"sync.invalidCallback",
|
|
@@ -32,4 +33,4 @@ var SYNC_ERROR_CODES = [
|
|
|
32
33
|
export {
|
|
33
34
|
SYNC_ERROR_CODES
|
|
34
35
|
};
|
|
35
|
-
//# sourceMappingURL=chunk-
|
|
36
|
+
//# sourceMappingURL=chunk-IFVFF47D.js.map
|
|
@@ -1 +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":[]}
|
|
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 'sync.disconnected',\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,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.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SYNC_ERROR_CODES
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-IFVFF47D.js";
|
|
4
4
|
|
|
5
5
|
// src/syncRequest.ts
|
|
6
6
|
import {
|
|
@@ -377,6 +377,7 @@ var syncRequestInternal = (params) => {
|
|
|
377
377
|
clearResponseTimeout();
|
|
378
378
|
cleanupProgressListener?.();
|
|
379
379
|
cleanupProgressListener = null;
|
|
380
|
+
cleanupResponseListener?.();
|
|
380
381
|
cleanupResponseListener = null;
|
|
381
382
|
cleanupExternalAbort?.();
|
|
382
383
|
cleanupExternalAbort = null;
|
|
@@ -415,8 +416,23 @@ var syncRequestInternal = (params) => {
|
|
|
415
416
|
});
|
|
416
417
|
};
|
|
417
418
|
socketInstance.once(responseEventName, responseListener);
|
|
419
|
+
const disconnectHandler = () => {
|
|
420
|
+
clearResponseTimeout();
|
|
421
|
+
cleanupProgressListener?.();
|
|
422
|
+
cleanupProgressListener = null;
|
|
423
|
+
cleanupResponseListener?.();
|
|
424
|
+
cleanupResponseListener = null;
|
|
425
|
+
cleanupExternalAbort?.();
|
|
426
|
+
cleanupExternalAbort = null;
|
|
427
|
+
resolve(normalizeSyncError({
|
|
428
|
+
response: { status: "error", errorCode: "sync.disconnected" },
|
|
429
|
+
fallbackErrorCode: "sync.disconnected"
|
|
430
|
+
}));
|
|
431
|
+
};
|
|
432
|
+
socketInstance.once(socketEventNames.disconnect, disconnectHandler);
|
|
418
433
|
cleanupResponseListener = () => {
|
|
419
434
|
socketInstance.off(responseEventName, responseListener);
|
|
435
|
+
socketInstance.off(socketEventNames.disconnect, disconnectHandler);
|
|
420
436
|
};
|
|
421
437
|
};
|
|
422
438
|
runRequest(activeSocket);
|
|
@@ -726,7 +742,7 @@ var initSyncRequest = async ({
|
|
|
726
742
|
if (activeLifecycleHandlers) {
|
|
727
743
|
socket.off(socketEventNames.connect, activeLifecycleHandlers.connect);
|
|
728
744
|
socket.off(socketEventNames.disconnect, activeLifecycleHandlers.disconnect);
|
|
729
|
-
socket.off(socketEventNames.reconnectAttempt, activeLifecycleHandlers.reconnectAttempt);
|
|
745
|
+
socket.io.off(socketEventNames.reconnectAttempt, activeLifecycleHandlers.reconnectAttempt);
|
|
730
746
|
socket.off(socketEventNames.userAfk, activeLifecycleHandlers.userAfk);
|
|
731
747
|
socket.off(socketEventNames.userBack, activeLifecycleHandlers.userBack);
|
|
732
748
|
socket.off(socketEventNames.connectError, activeLifecycleHandlers.connectError);
|
|
@@ -747,7 +763,7 @@ var initSyncRequest = async ({
|
|
|
747
763
|
};
|
|
748
764
|
socket.on(socketEventNames.connect, connect);
|
|
749
765
|
socket.on(socketEventNames.disconnect, disconnect);
|
|
750
|
-
socket.on(socketEventNames.reconnectAttempt, reconnectAttempt);
|
|
766
|
+
socket.io.on(socketEventNames.reconnectAttempt, reconnectAttempt);
|
|
751
767
|
socket.on(socketEventNames.userAfk, userAfk);
|
|
752
768
|
socket.on(socketEventNames.userBack, userBack);
|
|
753
769
|
socket.on(socketEventNames.connectError, connectError);
|
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 //? Call (not just null) so the disconnect watcher layered on top is\n //? removed on a normal acknowledgement.\n cleanupResponseListener?.();\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\n //? Mirrors apiRequest's CORE-O13 watcher: a disconnect between emit and\n //? acknowledgement means no ack will ever arrive on this socket. Settle\n //? now instead of waiting out `sync.requestTimeoutMs` (or forever, with\n //? the timeout disabled, leaking the progress and response listeners).\n const disconnectHandler = () => {\n clearResponseTimeout();\n cleanupProgressListener?.();\n cleanupProgressListener = null;\n cleanupResponseListener?.();\n cleanupResponseListener = null;\n cleanupExternalAbort?.();\n cleanupExternalAbort = null;\n resolve(normalizeSyncError({\n response: { status: 'error', errorCode: 'sync.disconnected' },\n fallbackErrorCode: 'sync.disconnected',\n }));\n };\n socketInstance.once(socketEventNames.disconnect, disconnectHandler);\n cleanupResponseListener = () => {\n socketInstance.off(responseEventName, responseListener);\n socketInstance.off(socketEventNames.disconnect, disconnectHandler);\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.io.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.io-client v4 emits `reconnect_attempt` on the Manager only; a\n //? listener on the Socket never fires, so RECONNECTING was never shown.\n socket.io.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,6 +1,12 @@
|
|
|
1
1
|
import type { SyncStreamPayload } from './_shared/syncTypes.js';
|
|
2
2
|
interface HttpSyncRequestParams {
|
|
3
3
|
name: string;
|
|
4
|
+
/**
|
|
5
|
+
* Accepted for wire compatibility with the socket message shape and otherwise
|
|
6
|
+
* ignored. Recipients are always addressed by the server-resolved route: a
|
|
7
|
+
* client-chosen callback name reaching other sockets let a room member fire
|
|
8
|
+
* another route's callbacks (cross-route callback spoofing).
|
|
9
|
+
*/
|
|
4
10
|
cb?: string;
|
|
5
11
|
data: Record<string, unknown>;
|
|
6
12
|
receiver: string;
|