stitchkit 0.52.0 → 0.53.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/README.md +1 -1
- package/dist/browser/http.d.ts +7 -0
- package/dist/browser/http.d.ts.map +1 -1
- package/dist/browser/socket-io.d.ts +38 -2
- package/dist/browser/socket-io.d.ts.map +1 -1
- package/dist/{index-d6jj3cp5.js → index-6jngw7hw.js} +42 -2
- package/dist/index.js +23 -8
- package/dist/node.d.ts +1 -1
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +1 -1
- package/dist/realtime/socket.d.ts +8 -1
- package/dist/realtime/socket.d.ts.map +1 -1
- package/dist/server/bun.d.ts +19 -0
- package/dist/server/bun.d.ts.map +1 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +81 -16
- package/dist/server/realtime.d.ts +14 -10
- package/dist/server/realtime.d.ts.map +1 -1
- package/dist/server/socket-io-config.d.ts +45 -2
- package/dist/server/socket-io-config.d.ts.map +1 -1
- package/dist/server/socket-io-node.d.ts +5 -5
- package/dist/server/socket-io-node.d.ts.map +1 -1
- package/dist/server/socket-io.d.ts +5 -5
- package/dist/server/socket-io.d.ts.map +1 -1
- package/llms-full.txt +184 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -221,7 +221,7 @@ const socket = await createSocketIOServer<ServerToClientEvents, ClientToServerEv
|
|
|
221
221
|
cors: { origin: 'https://app.example.com' },
|
|
222
222
|
})
|
|
223
223
|
|
|
224
|
-
socket.io.on('connection', (s) => { /* rooms
|
|
224
|
+
socket.io.on('connection', (s) => { /* rooms — your domain logic; typed handshake auth via `handshake` */ })
|
|
225
225
|
|
|
226
226
|
createServer({
|
|
227
227
|
services: [service],
|
package/dist/browser/http.d.ts
CHANGED
|
@@ -61,6 +61,13 @@ export interface HttpClientConfig {
|
|
|
61
61
|
* Default `false`.
|
|
62
62
|
*/
|
|
63
63
|
trace?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Dial a unix domain socket instead of TCP (Bun runtime only — other
|
|
66
|
+
* runtimes ignore the option and dial `baseUrl` over TCP). `baseUrl` stays
|
|
67
|
+
* required as the path/prefix source; its host is ignored by the socket
|
|
68
|
+
* transport, so `baseUrl: 'http://localhost'` is the idiomatic pairing.
|
|
69
|
+
*/
|
|
70
|
+
unix?: string;
|
|
64
71
|
}
|
|
65
72
|
type ParamValue = string | number | boolean | undefined;
|
|
66
73
|
type ParamArrayValue = Array<string | number>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/browser/http.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAMjD,MAAM,MAAM,QAAQ,GAChB;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEvB,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;AAEzD,sEAAsE;AACtE,MAAM,MAAM,mBAAmB,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;AAEhE,qBAAa,QAAS,SAAQ,KAAK;aAEf,IAAI,EAAE,MAAM;aACZ,MAAM,EAAE,MAAM;aACd,OAAO,CAAC,EAAE,OAAO;aAEjB,IAAI,CAAC,EAAE,MAAM;aACb,OAAO,CAAC,EAAE,MAAM;IANlC,YACkB,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,MAAU,EAClB,OAAO,CAAC,EAAE,OAAO,EACjC,OAAO,CAAC,EAAE,MAAM,EACA,IAAI,CAAC,EAAE,MAAM,YAAA,EACb,OAAO,CAAC,EAAE,MAAM,YAAA,EAIjC;IAED,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE3C;CACF;AAED,2EAA2E;AAC3E,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,CAgB3E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,IAAI,CAU9E;AAED,MAAM,MAAM,cAAc,GACtB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtB,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;AAEtD,4CAA4C;AAC5C,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC;;;;;;OAMG;IACH,KAAK,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACvE,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,aAAa,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IAC9D,sFAAsF;IACtF,uBAAuB,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACzD;;;OAGG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/browser/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -91,6 +91,34 @@ export interface SocketIOClientConfig<TServerEvents extends SocketEventMap = Soc
|
|
|
91
91
|
* cycle. Only the first emitted argument of an event is retained.
|
|
92
92
|
*/
|
|
93
93
|
retain?: Array<keyof TServerEvents & string>;
|
|
94
|
+
/**
|
|
95
|
+
* Observe handshake/connection failures (`connect_error`). `terminal: true`
|
|
96
|
+
* means socket.io will NOT retry on its own — that is how a server-side
|
|
97
|
+
* handshake gate rejection (`io.use` middleware / the stitchkit `handshake`
|
|
98
|
+
* option, `data.code === 'handshake_rejected'`) arrives, unlike a
|
|
99
|
+
* transport-level failure which keeps retrying. On a terminal error the
|
|
100
|
+
* client resets its connection intent, so a later `connect()` starts a fresh
|
|
101
|
+
* attempt and re-reads a function-form `auth` — the recovery path after
|
|
102
|
+
* rotating a rejected token. For transport-level failures (server down) the
|
|
103
|
+
* hook fires once **per retry attempt** — debounce before wiring it to
|
|
104
|
+
* user-facing alerts.
|
|
105
|
+
*/
|
|
106
|
+
onConnectError?: (error: {
|
|
107
|
+
message: string;
|
|
108
|
+
data?: unknown;
|
|
109
|
+
terminal: boolean;
|
|
110
|
+
}) => void;
|
|
111
|
+
/**
|
|
112
|
+
* Observe every emit dropped because the socket was disconnected (the
|
|
113
|
+
* central alternative to guarding each call with `connected`). Receives the
|
|
114
|
+
* **wire** arguments — for a validated `RealtimeClient` that is the
|
|
115
|
+
* Zod-parsed values plus the wrapped ack callback, not the caller's original
|
|
116
|
+
* arguments. The drop itself is also reported by `emit` returning `false`.
|
|
117
|
+
*/
|
|
118
|
+
onDroppedEmit?: (dropped: {
|
|
119
|
+
event: string;
|
|
120
|
+
args: unknown[];
|
|
121
|
+
}) => void;
|
|
94
122
|
}
|
|
95
123
|
export interface SocketIOClient<TServerEvents extends SocketEventMap, TClientEvents extends SocketEventMap> {
|
|
96
124
|
/** Create the socket (if absent) and connect. Idempotent. */
|
|
@@ -105,8 +133,16 @@ export interface SocketIOClient<TServerEvents extends SocketEventMap, TClientEve
|
|
|
105
133
|
* survives a `disconnect()` / `connect()` cycle.
|
|
106
134
|
*/
|
|
107
135
|
on<E extends keyof TServerEvents & string>(event: E, handler: TServerEvents[E]): () => void;
|
|
108
|
-
/**
|
|
109
|
-
|
|
136
|
+
/**
|
|
137
|
+
* Emit a client → server event. Returns `true` when the event was handed to
|
|
138
|
+
* the transport (not a delivery guarantee) and `false` when it was dropped
|
|
139
|
+
* because the socket is disconnected — including the window while the lazy
|
|
140
|
+
* peer is still loading right after `connect()`. A drop also fires the
|
|
141
|
+
* `onDroppedEmit` hook. The default stays a drop (no buffering): after a
|
|
142
|
+
* reconnect the durable subscriptions replay state deterministically instead
|
|
143
|
+
* of an unordered backlog of stale emits.
|
|
144
|
+
*/
|
|
145
|
+
emit<E extends keyof TClientEvents & string>(event: E, ...args: Parameters<TClientEvents[E]>): boolean;
|
|
110
146
|
/**
|
|
111
147
|
* Subscribe to connection up/down changes. Returns an unsubscribe. On a
|
|
112
148
|
* disconnect the listener also receives the Socket.IO **reason** (e.g.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"socket-io.d.ts","sourceRoot":"","sources":["../../src/browser/socket-io.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EACV,gBAAgB,EAChB,qBAAqB,EACrB,yBAAyB,EAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,oBAAoB,CAAC;AA0D5B;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,CAAC;AAEvC,MAAM,WAAW,oBAAoB,CAAC,aAAa,SAAS,cAAc,GAAG,cAAc;IACzF,qDAAqD;IACrD,GAAG,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;OAMG;IACH,IAAI,CAAC,EACD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACvE,kFAAkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IAClD;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,2EAA2E;IAC3E,UAAU,CAAC,EAAE,KAAK,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;IAC5C,iDAAiD;IACjD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,uDAAuD;IACvD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mDAAmD;IACnD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;;;;;OAcG;IACH,2BAA2B,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC7C;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"socket-io.d.ts","sourceRoot":"","sources":["../../src/browser/socket-io.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,7 +27,8 @@ import {
|
|
|
27
27
|
__require,
|
|
28
28
|
isRecord,
|
|
29
29
|
parseTrailingWildcard,
|
|
30
|
-
resolveTraceContext
|
|
30
|
+
resolveTraceContext,
|
|
31
|
+
transportResult
|
|
31
32
|
} from "./index-bmnhqtya.js";
|
|
32
33
|
|
|
33
34
|
// src/server/multipart.ts
|
|
@@ -1913,7 +1914,7 @@ function createValidatedRealtimeSocket({
|
|
|
1913
1914
|
acknowledgement(ack.data);
|
|
1914
1915
|
});
|
|
1915
1916
|
}
|
|
1916
|
-
emitTarget(event, ...wireArgs);
|
|
1917
|
+
return emitTarget(event, ...wireArgs) !== false;
|
|
1917
1918
|
}
|
|
1918
1919
|
};
|
|
1919
1920
|
}
|
|
@@ -2035,6 +2036,43 @@ async function importPeer(load, pkg) {
|
|
|
2035
2036
|
throw err;
|
|
2036
2037
|
}
|
|
2037
2038
|
}
|
|
2039
|
+
function handshakeRejection(message) {
|
|
2040
|
+
const error = new Error(message);
|
|
2041
|
+
error.data = { code: "handshake_rejected" };
|
|
2042
|
+
return error;
|
|
2043
|
+
}
|
|
2044
|
+
function handshakeMiddleware(handshake) {
|
|
2045
|
+
return (socket, next) => {
|
|
2046
|
+
let parsed;
|
|
2047
|
+
try {
|
|
2048
|
+
parsed = handshake.schema.safeParse(socket.handshake.auth);
|
|
2049
|
+
} catch (error) {
|
|
2050
|
+
console.error("[stitchkit] handshake schema threw — use a synchronous schema", error);
|
|
2051
|
+
next(handshakeRejection("handshake auth failed validation"));
|
|
2052
|
+
return;
|
|
2053
|
+
}
|
|
2054
|
+
if (!parsed.success) {
|
|
2055
|
+
next(handshakeRejection("handshake auth failed validation"));
|
|
2056
|
+
return;
|
|
2057
|
+
}
|
|
2058
|
+
const verify = handshake.verify;
|
|
2059
|
+
Promise.resolve().then(() => {
|
|
2060
|
+
if (verify)
|
|
2061
|
+
return verify(parsed.data, { handshake: socket.handshake });
|
|
2062
|
+
return transportResult(parsed.data);
|
|
2063
|
+
}).then((identity) => {
|
|
2064
|
+
if (identity === null || identity === undefined) {
|
|
2065
|
+
next(handshakeRejection("handshake rejected"));
|
|
2066
|
+
return;
|
|
2067
|
+
}
|
|
2068
|
+
socket.data = identity;
|
|
2069
|
+
next();
|
|
2070
|
+
}, (error) => {
|
|
2071
|
+
console.error("[stitchkit] handshake verify rejected", error);
|
|
2072
|
+
next(handshakeRejection("handshake rejected"));
|
|
2073
|
+
});
|
|
2074
|
+
};
|
|
2075
|
+
}
|
|
2038
2076
|
async function createSocketIOServer(config) {
|
|
2039
2077
|
const path = config.path ?? "/socket.io/";
|
|
2040
2078
|
const onBun = "Bun" in globalThis;
|
|
@@ -2084,6 +2122,8 @@ async function createSocketIOServer(config) {
|
|
|
2084
2122
|
pingInterval,
|
|
2085
2123
|
allowRequest
|
|
2086
2124
|
});
|
|
2125
|
+
if (config.handshake)
|
|
2126
|
+
io.use(handshakeMiddleware(config.handshake));
|
|
2087
2127
|
const lifecycle = {
|
|
2088
2128
|
beginShutdown() {
|
|
2089
2129
|
accepting = false;
|
package/dist/index.js
CHANGED
|
@@ -397,19 +397,21 @@ function parseApiErrorBody(body) {
|
|
|
397
397
|
hint: typeof error.hint === "string" ? error.hint : undefined
|
|
398
398
|
};
|
|
399
399
|
}
|
|
400
|
-
function createRetryAwareFetch() {
|
|
400
|
+
function createRetryAwareFetch(unix) {
|
|
401
401
|
const runtimeFetch = globalThis.fetch.bind(globalThis);
|
|
402
402
|
let attempt = 0;
|
|
403
403
|
return (input, init) => {
|
|
404
404
|
attempt += 1;
|
|
405
|
-
if (attempt === 1) {
|
|
405
|
+
if (unix === undefined && attempt === 1) {
|
|
406
406
|
return runtimeFetch(input, init);
|
|
407
407
|
}
|
|
408
|
-
if (!(input instanceof Request))
|
|
409
|
-
return runtimeFetch(input, init);
|
|
408
|
+
if (!(input instanceof Request)) {
|
|
409
|
+
return runtimeFetch(input, unix === undefined ? init : { ...init, unix });
|
|
410
|
+
}
|
|
410
411
|
const streamedBody = input.body ? { body: input.body, duplex: "half" } : {};
|
|
411
412
|
return runtimeFetch(input.url, {
|
|
412
413
|
...init,
|
|
414
|
+
...unix !== undefined && { unix },
|
|
413
415
|
method: input.method,
|
|
414
416
|
headers: input.headers,
|
|
415
417
|
...streamedBody,
|
|
@@ -490,7 +492,7 @@ function createHttpClient(config) {
|
|
|
490
492
|
async function request(method, url, data, options = {}) {
|
|
491
493
|
const cancellation = createRequestCancellation(options.signal, options.timeout ?? config.timeout ?? 30000);
|
|
492
494
|
const kyOptions = {
|
|
493
|
-
fetch: createRetryAwareFetch(),
|
|
495
|
+
fetch: createRetryAwareFetch(config.unix),
|
|
494
496
|
timeout: false,
|
|
495
497
|
signal: cancellation.signal
|
|
496
498
|
};
|
|
@@ -991,7 +993,7 @@ function createValidatedRealtimeSocket({
|
|
|
991
993
|
acknowledgement(ack.data);
|
|
992
994
|
});
|
|
993
995
|
}
|
|
994
|
-
emitTarget(event, ...wireArgs);
|
|
996
|
+
return emitTarget(event, ...wireArgs) !== false;
|
|
995
997
|
}
|
|
996
998
|
};
|
|
997
999
|
}
|
|
@@ -1128,6 +1130,16 @@ function createSocketIOClient(config) {
|
|
|
1128
1130
|
socket.io.on("reconnect_failed", () => {
|
|
1129
1131
|
desiredConnected = false;
|
|
1130
1132
|
});
|
|
1133
|
+
socket.on("connect_error", (error) => {
|
|
1134
|
+
const terminal = socket !== null && !socket.active;
|
|
1135
|
+
if (terminal)
|
|
1136
|
+
desiredConnected = false;
|
|
1137
|
+
config.onConnectError?.({
|
|
1138
|
+
message: error.message,
|
|
1139
|
+
data: Reflect.get(error, "data"),
|
|
1140
|
+
terminal
|
|
1141
|
+
});
|
|
1142
|
+
});
|
|
1131
1143
|
if (retained) {
|
|
1132
1144
|
for (const name of retainNames) {
|
|
1133
1145
|
socket.on(name, (payload) => retained.record(name, payload));
|
|
@@ -1181,10 +1193,13 @@ function createSocketIOClient(config) {
|
|
|
1181
1193
|
};
|
|
1182
1194
|
},
|
|
1183
1195
|
emit(event, ...args) {
|
|
1184
|
-
if (!socket?.connected)
|
|
1185
|
-
return;
|
|
1186
1196
|
const name = event;
|
|
1197
|
+
if (!socket?.connected) {
|
|
1198
|
+
config.onDroppedEmit?.({ event: name, args });
|
|
1199
|
+
return false;
|
|
1200
|
+
}
|
|
1187
1201
|
socket.emit(name, ...args);
|
|
1202
|
+
return true;
|
|
1188
1203
|
},
|
|
1189
1204
|
onConnectionChange(listener) {
|
|
1190
1205
|
connectionListeners.add(listener);
|
package/dist/node.d.ts
CHANGED
|
@@ -12,6 +12,6 @@ export { type NodeRuntimeServer, type NodeServerConfig, type NodeServerHandle, t
|
|
|
12
12
|
export { bindProcessSignals, type ProcessSignalName, type ProcessSignalsBinding, type ProcessSignalsErrorPhase, type ProcessSignalsOptions, type ShutdownTarget, type SignalSource, } from './server/process-signals';
|
|
13
13
|
export { bindRealtimeServer, type RealtimeServer, type RealtimeServerConnection, type RealtimeServerHandle, } from './server/realtime';
|
|
14
14
|
export { type ManagedServerHandle, type ShutdownOptions, ShutdownOptionsSchema, type ShutdownResult, ShutdownResultSchema, type ShutdownState, ShutdownStateSchema, type ShutdownStatus, ShutdownStatusSchema, } from './server/shutdown';
|
|
15
|
-
export { createNodeSocketIOServer as createSocketIOServer, type NodeSocketIOServerHandle as SocketIOServerHandle, type SocketIORequestPolicy, type SocketIOServerConfig, } from './server/socket-io-node';
|
|
15
|
+
export { createNodeSocketIOServer as createSocketIOServer, type NodeSocketIOServerHandle as SocketIOServerHandle, type SocketIOHandshakeConfig, type SocketIORequestPolicy, type SocketIOServerConfig, } from './server/socket-io-node';
|
|
16
16
|
export type { EffectiveScope, FetchComposition, FetchHandler, HandlerConfig, LoggingConfig, LogOutcome, RawRoute, RawRouteContext, ScopeContexts, ScopedHandlers, ServiceDef, } from './server/types';
|
|
17
17
|
//# sourceMappingURL=node.d.ts.map
|
package/dist/node.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,WAAW,EACX,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,6BAA6B,EAC7B,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAC3B,SAAS,EACT,iBAAiB,EACjB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,4BAA4B,EACjC,KAAK,sBAAsB,EAC3B,KAAK,WAAW,GACjB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,SAAS,GACV,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,kBAAkB,EAClB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,YAAY,GAClB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,kBAAkB,EAClB,KAAK,cAAc,EACnB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,GAC1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,qBAAqB,EACrB,KAAK,cAAc,EACnB,oBAAoB,EACpB,KAAK,aAAa,EAClB,mBAAmB,EACnB,KAAK,cAAc,EACnB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,wBAAwB,IAAI,oBAAoB,EAChD,KAAK,wBAAwB,IAAI,oBAAoB,EACrD,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,GAC1B,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,aAAa,EACb,UAAU,EACV,QAAQ,EACR,eAAe,EACf,aAAa,EACb,cAAc,EACd,UAAU,GACX,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,WAAW,EACX,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,6BAA6B,EAC7B,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAC3B,SAAS,EACT,iBAAiB,EACjB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,4BAA4B,EACjC,KAAK,sBAAsB,EAC3B,KAAK,WAAW,GACjB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,SAAS,GACV,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,kBAAkB,EAClB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,YAAY,GAClB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,kBAAkB,EAClB,KAAK,cAAc,EACnB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,GAC1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,qBAAqB,EACrB,KAAK,cAAc,EACnB,oBAAoB,EACpB,KAAK,aAAa,EAClB,mBAAmB,EACnB,KAAK,cAAc,EACnB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,wBAAwB,IAAI,oBAAoB,EAChD,KAAK,wBAAwB,IAAI,oBAAoB,EACrD,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,GAC1B,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,aAAa,EACb,UAAU,EACV,QAAQ,EACR,eAAe,EACf,aAAa,EACb,cAAc,EACd,UAAU,GACX,MAAM,gBAAgB,CAAC"}
|
package/dist/node.js
CHANGED
|
@@ -23,7 +23,14 @@ export declare const REALTIME_TARGET_FORMS: ({
|
|
|
23
23
|
})[];
|
|
24
24
|
export interface ValidatedRealtimeSocket<TInbound extends RealtimeEventRegistry, TOutbound extends RealtimeEventRegistry> {
|
|
25
25
|
on<TEvent extends keyof TInbound & string>(event: TEvent, handler: RealtimeEventHandler<TInbound[TEvent]>): () => void;
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Emit a validated event. Three outcomes, in order: a local contract
|
|
28
|
+
* violation **throws** (validation runs even while disconnected); an emit a
|
|
29
|
+
* disconnected browser transport drops returns `false`; otherwise `true` —
|
|
30
|
+
* accepted by the transport, which is not a delivery guarantee. Server
|
|
31
|
+
* targets always return `true` (an empty room is not a drop).
|
|
32
|
+
*/
|
|
33
|
+
emit<TEvent extends keyof TOutbound & string>(event: TEvent, ...args: RealtimeEmitArguments<TOutbound[TEvent]>): boolean;
|
|
27
34
|
}
|
|
28
35
|
export declare function createValidatedRealtimeSocket<const TInbound extends RealtimeEventRegistry, const TOutbound extends RealtimeEventRegistry>({ target, inbound, outbound, inboundDirection, outboundDirection, onRejected, logger, subscribe, }: ValidatedRealtimeSocketOptions<TInbound, TOutbound>): ValidatedRealtimeSocket<TInbound, TOutbound>;
|
|
29
36
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../src/realtime/socket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EACV,qBAAqB,EAErB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EAEvB,yBAAyB,EAC1B,MAAM,YAAY,CAAC;AAGpB,UAAU,8BAA8B,CACtC,QAAQ,SAAS,qBAAqB,EACtC,SAAS,SAAS,qBAAqB;IAEvC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,QAAQ,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC;IACpB,gBAAgB,EAAE,uBAAuB,CAAC;IAC1C,iBAAiB,EAAE,uBAAuB,CAAC;IAC3C,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;CAClF;AAED,8FAA8F;AAC9F,eAAO,MAAM,qBAAqB;;;;;;;;;IAOhC,CAAC;AAEH,MAAM,WAAW,uBAAuB,CACtC,QAAQ,SAAS,qBAAqB,EACtC,SAAS,SAAS,qBAAqB;IAEvC,EAAE,CAAC,MAAM,SAAS,MAAM,QAAQ,GAAG,MAAM,EACvC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,oBAAoB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAC9C,MAAM,IAAI,CAAC;IACd,IAAI,CAAC,MAAM,SAAS,MAAM,SAAS,GAAG,MAAM,EAC1C,KAAK,EAAE,MAAM,EACb,GAAG,IAAI,EAAE,qBAAqB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,GAChD,
|
|
1
|
+
{"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../src/realtime/socket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EACV,qBAAqB,EAErB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EAEvB,yBAAyB,EAC1B,MAAM,YAAY,CAAC;AAGpB,UAAU,8BAA8B,CACtC,QAAQ,SAAS,qBAAqB,EACtC,SAAS,SAAS,qBAAqB;IAEvC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,QAAQ,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC;IACpB,gBAAgB,EAAE,uBAAuB,CAAC;IAC1C,iBAAiB,EAAE,uBAAuB,CAAC;IAC3C,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;CAClF;AAED,8FAA8F;AAC9F,eAAO,MAAM,qBAAqB;;;;;;;;;IAOhC,CAAC;AAEH,MAAM,WAAW,uBAAuB,CACtC,QAAQ,SAAS,qBAAqB,EACtC,SAAS,SAAS,qBAAqB;IAEvC,EAAE,CAAC,MAAM,SAAS,MAAM,QAAQ,GAAG,MAAM,EACvC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,oBAAoB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAC9C,MAAM,IAAI,CAAC;IACd;;;;;;OAMG;IACH,IAAI,CAAC,MAAM,SAAS,MAAM,SAAS,GAAG,MAAM,EAC1C,KAAK,EAAE,MAAM,EACb,GAAG,IAAI,EAAE,qBAAqB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,GAChD,OAAO,CAAC;CACZ;AA+DD,wBAAgB,6BAA6B,CAC3C,KAAK,CAAC,QAAQ,SAAS,qBAAqB,EAC5C,KAAK,CAAC,SAAS,SAAS,qBAAqB,EAC7C,EACA,MAAM,EACN,OAAO,EACP,QAAQ,EACR,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,MAAM,EACN,SAAS,GACV,EAAE,8BAA8B,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,uBAAuB,CAC9E,QAAQ,EACR,SAAS,CACV,CA+HA"}
|
package/dist/server/bun.d.ts
CHANGED
|
@@ -14,10 +14,29 @@ type BunDevelopmentOptions = BunServeOptions extends {
|
|
|
14
14
|
development?: infer T;
|
|
15
15
|
} ? T : never;
|
|
16
16
|
export type ServerPassthrough = Omit<BunServeOptions, 'fetch' | 'port' | 'hostname' | 'unix' | 'routes' | 'websocket' | 'development'>;
|
|
17
|
+
/**
|
|
18
|
+
* Unix domain socket listener. The plain-string form binds the path as-is;
|
|
19
|
+
* the object form additionally tightens the socket file mode after listen —
|
|
20
|
+
* `mode: 0o600` is the right choice when access to the socket IS the
|
|
21
|
+
* credential (a local daemon whose only auth is filesystem permission).
|
|
22
|
+
*/
|
|
23
|
+
export type UnixListenConfig = string | {
|
|
24
|
+
path: string;
|
|
25
|
+
mode?: number;
|
|
26
|
+
};
|
|
17
27
|
/** Bun-specific server config layered over the Fetch-clean handler config. */
|
|
18
28
|
export interface BunServerConfig extends BunHandlerConfig, BunFetchComposition {
|
|
19
29
|
port?: number;
|
|
20
30
|
hostname?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Listen on a unix domain socket instead of a TCP port. Mutually exclusive
|
|
33
|
+
* with `port`/`hostname`. A stale socket file left by a killed process is
|
|
34
|
+
* reclaimed (probe-then-unlink, best-effort against concurrent starts); a
|
|
35
|
+
* path answered by a live listener — or one this process may not probe —
|
|
36
|
+
* fails loudly. Not compatible with the Socket.IO lifecycle (`socket`):
|
|
37
|
+
* socket.io clients cannot dial a unix socket.
|
|
38
|
+
*/
|
|
39
|
+
unix?: UnixListenConfig;
|
|
21
40
|
websocket?: BunWebSocketHandlers;
|
|
22
41
|
/** Full Stitchkit Socket.IO lifecycle; route and default websocket are mounted automatically. */
|
|
23
42
|
socket?: SocketIOServerLifecycle;
|
package/dist/server/bun.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../../src/server/bun.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../../src/server/bun.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,mBAAmB,EAEzB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,eAAe,EAChB,MAAM,SAAS,CAAC;AAEjB,yEAAyE;AACzE,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;AACrD,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;AAC9C,MAAM,MAAM,kBAAkB,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;AAC5D,MAAM,MAAM,eAAe,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;AACtD,MAAM,MAAM,mBAAmB,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;AAC9D,MAAM,MAAM,gBAAgB,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;AAExD,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,KAAK,oBAAoB,GAAG,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAC1D,KAAK,qBAAqB,GAAG,eAAe,SAAS;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,CAAC,GAAG,KAAK,CAAC;AAE3F,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAClC,eAAe,EACf,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,aAAa,CAChF,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE,8EAA8E;AAC9E,MAAM,WAAW,eAAgB,SAAQ,gBAAgB,EAAE,mBAAmB;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC,iGAAiG;IACjG,MAAM,CAAC,EAAE,uBAAuB,CAAC;IACjC,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC,GAAG,CAAC,EAAE,iBAAiB,CAAC;CACzB;AAED,MAAM,MAAM,eAAe,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;AAyD7D,qDAAqD;AACrD,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,eAAe,CA6LrE"}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { AppError, appError, badRequest, conflict, forbidden, isStitchErrorCode, notFound, rateLimited, STITCH_ERROR_STATUS, type StitchErrorCode, unauthorized, } from '../contract';
|
|
2
2
|
export { errorCode, formatZodError, normalizeError, type ZodIssueSummary, zodIssues, } from '../internal/errors';
|
|
3
3
|
export { isWithinDir } from '../internal/within-dir';
|
|
4
|
-
export { type BunFetchComposition as FetchComposition, type BunFetchHandler as FetchHandler, type BunHandlerConfig as HandlerConfig, type BunRawRoute as RawRoute, type BunRawRouteContext as RawRouteContext, type BunServer, type BunServerConfig, type BunServerHandle, createServer, type ServerPassthrough, } from './bun';
|
|
4
|
+
export { type BunFetchComposition as FetchComposition, type BunFetchHandler as FetchHandler, type BunHandlerConfig as HandlerConfig, type BunRawRoute as RawRoute, type BunRawRouteContext as RawRouteContext, type BunServer, type BunServerConfig, type BunServerHandle, createServer, type ServerPassthrough, type UnixListenConfig, } from './bun';
|
|
5
5
|
export { type CacheOptions, cacheHeaders, createCache } from './cache';
|
|
6
6
|
export { createHandler } from './create';
|
|
7
7
|
export { createErrorHook, type ErrorHookConfig, type ResolvedError, } from './error-hook';
|
|
@@ -21,7 +21,7 @@ export { errorResponse, parseBody, respondJson } from './raw';
|
|
|
21
21
|
export { bindRealtimeServer, type RealtimeServer, type RealtimeServerConnection, type RealtimeServerHandle, } from './realtime';
|
|
22
22
|
export { type ClientIpOptions, extractIp, generateTraceId, getClientInfo, resolveSocketIp, resolveTraceId, } from './request';
|
|
23
23
|
export { type ManagedServerHandle, type ShutdownOptions, ShutdownOptionsSchema, type ShutdownResult, ShutdownResultSchema, type ShutdownState, ShutdownStateSchema, type ShutdownStatus, ShutdownStatusSchema, } from './shutdown';
|
|
24
|
-
export type { SocketIORequestPolicy, SocketIOServerConfig, SocketIOServerHandle, SocketIOServerLifecycle, } from './socket-io';
|
|
24
|
+
export type { SocketIOHandshakeConfig, SocketIORequestPolicy, SocketIOServerConfig, SocketIOServerHandle, SocketIOServerLifecycle, } from './socket-io';
|
|
25
25
|
export { createSocketIOServer, socketIoLane } from './socket-io';
|
|
26
26
|
export { type ParseSSEOptions, parseSSE, streamSSE } from './stream';
|
|
27
27
|
export type { AuthorizationContext, EffectiveScope, EndpointHandlerContext, Handlers, LifecycleHooks, LoggingConfig, LogOutcome, MethodDef, MultipartFileMetadata, MultipartReceiver, MultipartReceiverResult, OperationIdentity, RouteGroup, ScopeContexts, ScopedHandlers, ServiceDef, StitchLogger, StreamingMultipartImplementation, } from './types';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,KAAK,eAAe,EACpB,YAAY,GACb,MAAM,aAAa,CAAC;AAIrB,OAAO,EACL,SAAS,EACT,cAAc,EACd,cAAc,EACd,KAAK,eAAe,EACpB,SAAS,GACV,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EACL,KAAK,mBAAmB,IAAI,gBAAgB,EAC5C,KAAK,eAAe,IAAI,YAAY,EACpC,KAAK,gBAAgB,IAAI,aAAa,EACtC,KAAK,WAAW,IAAI,QAAQ,EAC5B,KAAK,kBAAkB,IAAI,eAAe,EAC1C,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,YAAY,EACZ,KAAK,iBAAiB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,KAAK,eAAe,EACpB,YAAY,GACb,MAAM,aAAa,CAAC;AAIrB,OAAO,EACL,SAAS,EACT,cAAc,EACd,cAAc,EACd,KAAK,eAAe,EACpB,SAAS,GACV,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EACL,KAAK,mBAAmB,IAAI,gBAAgB,EAC5C,KAAK,eAAe,IAAI,YAAY,EACpC,KAAK,gBAAgB,IAAI,aAAa,EACtC,KAAK,WAAW,IAAI,QAAQ,EAC5B,KAAK,kBAAkB,IAAI,eAAe,EAC1C,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,KAAK,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EACL,eAAe,EACf,KAAK,eAAe,EACpB,KAAK,aAAa,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,YAAY,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,KAAK,SAAS,EACd,cAAc,EACd,KAAK,gBAAgB,EACrB,SAAS,EACT,WAAW,EACX,QAAQ,GACT,MAAM,QAAQ,CAAC;AAChB,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,6BAA6B,EAC7B,qBAAqB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAC3B,SAAS,EACT,iBAAiB,EACjB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,4BAA4B,EACjC,KAAK,sBAAsB,EAC3B,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,oBAAoB,EACzB,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,OAAO,EACP,KAAK,gBAAgB,EACrB,SAAS,GACV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,YAAY,EACZ,YAAY,EACZ,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,UAAU,EACf,WAAW,EACX,qBAAqB,EACrB,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,KAAK,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACrF,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EACL,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,kBAAkB,EAClB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,YAAY,GAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAC9D,OAAO,EACL,kBAAkB,EAClB,KAAK,cAAc,EACnB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,GAC1B,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,KAAK,eAAe,EACpB,SAAS,EACT,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,qBAAqB,EACrB,KAAK,cAAc,EACnB,oBAAoB,EACpB,KAAK,aAAa,EAClB,mBAAmB,EACnB,KAAK,cAAc,EACnB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrE,YAAY,EACV,oBAAoB,EACpB,cAAc,EACd,sBAAsB,EACtB,QAAQ,EACR,cAAc,EACd,aAAa,EACb,UAAU,EACV,SAAS,EACT,qBAAqB,EACrB,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,cAAc,EACd,UAAU,EACV,YAAY,EACZ,gCAAgC,GACjC,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,KAAK,YAAY,EACjB,wBAAwB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAClB,aAAa,GACd,MAAM,aAAa,CAAC"}
|
package/dist/server/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
parseMultipart,
|
|
13
13
|
socketIoLane,
|
|
14
14
|
webSocketLane
|
|
15
|
-
} from "../index-
|
|
15
|
+
} from "../index-6jngw7hw.js";
|
|
16
16
|
import {
|
|
17
17
|
createAuthHook,
|
|
18
18
|
createBearerResolver,
|
|
@@ -75,6 +75,39 @@ import {
|
|
|
75
75
|
parseTrailingWildcard
|
|
76
76
|
} from "../index-bmnhqtya.js";
|
|
77
77
|
// src/server/bun.ts
|
|
78
|
+
import { chmodSync, statSync, unlinkSync } from "node:fs";
|
|
79
|
+
function reclaimStaleUnixSocket(path) {
|
|
80
|
+
const stats = statSync(path, { throwIfNoEntry: false });
|
|
81
|
+
if (stats === undefined)
|
|
82
|
+
return;
|
|
83
|
+
if (!stats.isSocket()) {
|
|
84
|
+
throw new Error(`[stitchkit] createServer: "${path}" exists and is not a socket — refusing to remove it`);
|
|
85
|
+
}
|
|
86
|
+
if (typeof process.getuid === "function" && stats.uid !== process.getuid()) {
|
|
87
|
+
throw new Error(`[stitchkit] createServer: unix socket "${path}" is owned by another user — refusing to reclaim it`);
|
|
88
|
+
}
|
|
89
|
+
const standalone = Bun.main.startsWith("/$bunfs/");
|
|
90
|
+
const interpreter = standalone ? Bun.which("bun") : process.execPath;
|
|
91
|
+
if (!interpreter) {
|
|
92
|
+
throw new Error(`[stitchkit] createServer: unix socket "${path}" already exists and no \`bun\` binary is on PATH to probe it from this compiled executable — remove the file manually if the previous process is dead`);
|
|
93
|
+
}
|
|
94
|
+
const probe = Bun.spawnSync({
|
|
95
|
+
cmd: [
|
|
96
|
+
interpreter,
|
|
97
|
+
"-e",
|
|
98
|
+
'try { const socket = await Bun.connect({ unix: Bun.env.STITCHKIT_UNIX_PROBE ?? "", socket: { data() { return undefined; } } }); socket.end(); process.exit(0); } catch (error) { process.exit(error && typeof error === "object" && "code" in error && error.code === "EACCES" ? 2 : 1); }'
|
|
99
|
+
],
|
|
100
|
+
env: { ...process.env, STITCHKIT_UNIX_PROBE: path },
|
|
101
|
+
timeout: 2000
|
|
102
|
+
});
|
|
103
|
+
if (probe.exitedDueToTimeout) {
|
|
104
|
+
throw new Error(`[stitchkit] createServer: liveness probe for unix socket "${path}" timed out — refusing to reclaim; remove the file manually if the previous process is dead`);
|
|
105
|
+
}
|
|
106
|
+
if (probe.exitCode === 0 || probe.exitCode === 2) {
|
|
107
|
+
throw new Error(`[stitchkit] createServer: unix socket "${path}" is already in use${probe.exitCode === 2 ? " (connect permission denied)" : " by a live listener"}`);
|
|
108
|
+
}
|
|
109
|
+
unlinkSync(path);
|
|
110
|
+
}
|
|
78
111
|
function createServer(config) {
|
|
79
112
|
const {
|
|
80
113
|
websocket: configuredWebSocket,
|
|
@@ -84,6 +117,19 @@ function createServer(config) {
|
|
|
84
117
|
port = 3000,
|
|
85
118
|
hostname
|
|
86
119
|
} = config;
|
|
120
|
+
const unixPath = typeof config.unix === "string" ? config.unix : config.unix?.path;
|
|
121
|
+
const unixMode = typeof config.unix === "string" ? undefined : config.unix?.mode;
|
|
122
|
+
if (unixPath !== undefined) {
|
|
123
|
+
if (unixPath.length === 0) {
|
|
124
|
+
throw new Error("[stitchkit] createServer: `unix` must be a non-empty socket path");
|
|
125
|
+
}
|
|
126
|
+
if (config.port !== undefined || config.hostname !== undefined) {
|
|
127
|
+
throw new Error("[stitchkit] createServer: `unix` is mutually exclusive with `port`/`hostname`");
|
|
128
|
+
}
|
|
129
|
+
if (socket) {
|
|
130
|
+
throw new Error("[stitchkit] createServer: the Socket.IO lifecycle cannot listen on a unix socket — socket.io clients dial TCP only");
|
|
131
|
+
}
|
|
132
|
+
}
|
|
87
133
|
const socketRoutePrefix = socket?.route.path.replace(/\*socketPath$/, "");
|
|
88
134
|
const websocket = configuredWebSocket ?? socket?.websocket;
|
|
89
135
|
const openSockets = new Set;
|
|
@@ -176,24 +222,43 @@ function createServer(config) {
|
|
|
176
222
|
}
|
|
177
223
|
return admittedFetch(request, server2);
|
|
178
224
|
};
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
...
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
225
|
+
if (unixPath !== undefined) {
|
|
226
|
+
reclaimStaleUnixSocket(unixPath);
|
|
227
|
+
const { reusePort, ipv6Only, http3, http1, idleTimeout, ...unixExtra } = bunExtra ?? {};
|
|
228
|
+
runtime = trackedWebSocket ? Bun.serve({
|
|
229
|
+
...unixExtra,
|
|
230
|
+
...development && { development },
|
|
231
|
+
unix: unixPath,
|
|
232
|
+
websocket: trackedWebSocket,
|
|
233
|
+
fetch
|
|
234
|
+
}) : Bun.serve({
|
|
235
|
+
...unixExtra,
|
|
236
|
+
...development && { development },
|
|
237
|
+
unix: unixPath,
|
|
238
|
+
fetch
|
|
239
|
+
});
|
|
240
|
+
if (unixMode !== undefined)
|
|
241
|
+
chmodSync(unixPath, unixMode);
|
|
242
|
+
} else {
|
|
243
|
+
runtime = trackedWebSocket ? Bun.serve({
|
|
244
|
+
...bunExtra,
|
|
245
|
+
...development && { development },
|
|
246
|
+
port,
|
|
247
|
+
hostname,
|
|
248
|
+
websocket: trackedWebSocket,
|
|
249
|
+
fetch
|
|
250
|
+
}) : Bun.serve({
|
|
251
|
+
...bunExtra,
|
|
252
|
+
...development && { development },
|
|
253
|
+
port,
|
|
254
|
+
hostname,
|
|
255
|
+
fetch
|
|
256
|
+
});
|
|
257
|
+
}
|
|
193
258
|
const server = runtime;
|
|
194
259
|
return {
|
|
195
260
|
url: server.url.toString().replace(/\/$/, ""),
|
|
196
|
-
port: server.port ?? port,
|
|
261
|
+
port: server.port ?? (unixPath !== undefined ? 0 : port),
|
|
197
262
|
runtime: server,
|
|
198
263
|
get status() {
|
|
199
264
|
return lifecycle.status;
|
|
@@ -1,24 +1,28 @@
|
|
|
1
|
-
import type { Socket, Server as SocketIOServer } from 'socket.io';
|
|
1
|
+
import type { DefaultEventsMap, Socket, Server as SocketIOServer } from 'socket.io';
|
|
2
2
|
import type { SocketEventMap } from '../browser/socket-io';
|
|
3
3
|
import type { StitchLogger } from '../logger';
|
|
4
4
|
import type { RealtimeContract, RealtimeEventRegistry, RealtimeRejectedEventHook } from '../realtime/contract';
|
|
5
5
|
import { type ValidatedRealtimeSocket } from '../realtime/socket';
|
|
6
|
-
export interface RealtimeServerConnection<TServerToClient extends RealtimeEventRegistry, TClientToServer extends RealtimeEventRegistry> {
|
|
7
|
-
/**
|
|
8
|
-
|
|
6
|
+
export interface RealtimeServerConnection<TServerToClient extends RealtimeEventRegistry, TClientToServer extends RealtimeEventRegistry, TData = any> {
|
|
7
|
+
/**
|
|
8
|
+
* Raw Socket.IO socket for rooms and application-owned delivery policy.
|
|
9
|
+
* `raw.data` carries the typed handshake identity when the server was
|
|
10
|
+
* created with a `handshake` gate.
|
|
11
|
+
*/
|
|
12
|
+
raw: Socket<SocketEventMap, SocketEventMap, DefaultEventsMap, TData>;
|
|
9
13
|
events: ValidatedRealtimeSocket<TClientToServer, TServerToClient>;
|
|
10
14
|
to(room: string): Pick<ValidatedRealtimeSocket<RealtimeEventRegistry, TServerToClient>, 'emit'>;
|
|
11
15
|
}
|
|
12
|
-
export interface RealtimeServer<TServerToClient extends RealtimeEventRegistry, TClientToServer extends RealtimeEventRegistry> {
|
|
13
|
-
onConnection(handler: (connection: RealtimeServerConnection<TServerToClient, TClientToServer>) => void | Promise<void>): () => void;
|
|
16
|
+
export interface RealtimeServer<TServerToClient extends RealtimeEventRegistry, TClientToServer extends RealtimeEventRegistry, TData = any> {
|
|
17
|
+
onConnection(handler: (connection: RealtimeServerConnection<TServerToClient, TClientToServer, TData>) => void | Promise<void>): () => void;
|
|
14
18
|
emit: ValidatedRealtimeSocket<RealtimeEventRegistry, TServerToClient>['emit'];
|
|
15
19
|
to(room: string): Pick<ValidatedRealtimeSocket<RealtimeEventRegistry, TServerToClient>, 'emit'>;
|
|
16
20
|
}
|
|
17
|
-
export interface RealtimeServerHandle {
|
|
18
|
-
io: SocketIOServer<SocketEventMap, SocketEventMap>;
|
|
21
|
+
export interface RealtimeServerHandle<TData = any> {
|
|
22
|
+
io: SocketIOServer<SocketEventMap, SocketEventMap, DefaultEventsMap, TData>;
|
|
19
23
|
}
|
|
20
|
-
export declare function bindRealtimeServer<const TServerToClient extends RealtimeEventRegistry, const TClientToServer extends RealtimeEventRegistry>(contract: RealtimeContract<TServerToClient, TClientToServer>, handle: RealtimeServerHandle
|
|
24
|
+
export declare function bindRealtimeServer<const TServerToClient extends RealtimeEventRegistry, const TClientToServer extends RealtimeEventRegistry, TData = any>(contract: RealtimeContract<TServerToClient, TClientToServer>, handle: RealtimeServerHandle<TData>, options?: {
|
|
21
25
|
onRejected?: RealtimeRejectedEventHook;
|
|
22
26
|
logger?: StitchLogger;
|
|
23
|
-
}): RealtimeServer<TServerToClient, TClientToServer>;
|
|
27
|
+
}): RealtimeServer<TServerToClient, TClientToServer, TData>;
|
|
24
28
|
//# sourceMappingURL=realtime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../src/server/realtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,IAAI,cAAc,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../src/server/realtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,IAAI,cAAc,EAAE,MAAM,WAAW,CAAC;AACpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EACV,gBAAgB,EAChB,qBAAqB,EACrB,yBAAyB,EAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,wBAAwB,CACvC,eAAe,SAAS,qBAAqB,EAC7C,eAAe,SAAS,qBAAqB,EAC7C,KAAK,GAAG,GAAG;IAEX;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC;IACrE,MAAM,EAAE,uBAAuB,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;IAClE,EAAE,CACA,IAAI,EAAE,MAAM,GACX,IAAI,CAAC,uBAAuB,CAAC,qBAAqB,EAAE,eAAe,CAAC,EAAE,MAAM,CAAC,CAAC;CAClF;AAED,MAAM,WAAW,cAAc,CAC7B,eAAe,SAAS,qBAAqB,EAC7C,eAAe,SAAS,qBAAqB,EAC7C,KAAK,GAAG,GAAG;IAEX,YAAY,CACV,OAAO,EAAE,CACP,UAAU,EAAE,wBAAwB,CAAC,eAAe,EAAE,eAAe,EAAE,KAAK,CAAC,KAC1E,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GACxB,MAAM,IAAI,CAAC;IACd,IAAI,EAAE,uBAAuB,CAAC,qBAAqB,EAAE,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;IAC9E,EAAE,CACA,IAAI,EAAE,MAAM,GACX,IAAI,CAAC,uBAAuB,CAAC,qBAAqB,EAAE,eAAe,CAAC,EAAE,MAAM,CAAC,CAAC;CAClF;AAED,MAAM,WAAW,oBAAoB,CAAC,KAAK,GAAG,GAAG;IAC/C,EAAE,EAAE,cAAc,CAAC,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC;CAC7E;AAED,wBAAgB,kBAAkB,CAChC,KAAK,CAAC,eAAe,SAAS,qBAAqB,EACnD,KAAK,CAAC,eAAe,SAAS,qBAAqB,EACnD,KAAK,GAAG,GAAG,EAEX,QAAQ,EAAE,gBAAgB,CAAC,eAAe,EAAE,eAAe,CAAC,EAC5D,MAAM,EAAE,oBAAoB,CAAC,KAAK,CAAC,EACnC,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,yBAAyB,CAAC;IAAC,MAAM,CAAC,EAAE,YAAY,CAAA;CAAO,GAC9E,cAAc,CAAC,eAAe,EAAE,eAAe,EAAE,KAAK,CAAC,CAwCzD"}
|
|
@@ -1,8 +1,42 @@
|
|
|
1
1
|
/** Runtime-neutral Socket.IO configuration shared by Bun and Node adapters. */
|
|
2
|
-
import type { ServerOptions } from 'socket.io';
|
|
2
|
+
import type { ServerOptions, Socket } from 'socket.io';
|
|
3
|
+
import type { z } from 'zod';
|
|
3
4
|
/** Runtime-neutral Engine.IO handshake policy, evaluated before shutdown admission. */
|
|
4
5
|
export type SocketIORequestPolicy = (request: Request) => boolean | Promise<boolean>;
|
|
5
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Typed identity gate for the Socket.IO handshake. `schema` validates
|
|
8
|
+
* `socket.handshake.auth` (the structured channel — `query` values are strings
|
|
9
|
+
* on the wire); an optional `verify` turns the parsed payload into the
|
|
10
|
+
* connection identity. Returning `null` or throwing rejects the handshake
|
|
11
|
+
* **before** the connection handler and before any event validation; the
|
|
12
|
+
* accepted identity is written to `socket.data`, typed end-to-end through
|
|
13
|
+
* `createSocketIOServer` and `bindRealtimeServer`.
|
|
14
|
+
*
|
|
15
|
+
* A rejected handshake is terminal for socket.io-client — it does **not**
|
|
16
|
+
* retry (unlike a transport-level denial). The stitchkit client surfaces it
|
|
17
|
+
* via `onConnectError` with `terminal: true`; recovery is an explicit
|
|
18
|
+
* `connect()`, which re-reads a function-form `auth`.
|
|
19
|
+
*/
|
|
20
|
+
export interface SocketIOHandshakeConfig<TParsed, TData = TParsed> {
|
|
21
|
+
/** Zod schema for `socket.handshake.auth`. */
|
|
22
|
+
schema: z.ZodType<TParsed>;
|
|
23
|
+
/**
|
|
24
|
+
* Turn the schema-validated payload into the connection identity (may be
|
|
25
|
+
* async — the wrapper awaits it safely; socket.io itself would leak an
|
|
26
|
+
* unhandled rejection from a raw async middleware). Return `null` or throw
|
|
27
|
+
* to reject; a thrown error is logged server-side and the peer sees only
|
|
28
|
+
* the generic `handshake rejected` — raw error text never crosses to an
|
|
29
|
+
* unauthenticated client. When omitted, the parsed payload itself is the
|
|
30
|
+
* identity (when passing `TData` explicitly with `TData ≠ TParsed`,
|
|
31
|
+
* `verify` is therefore mandatory — without it the runtime stores the
|
|
32
|
+
* schema output). The `schema` must be synchronous (no async
|
|
33
|
+
* refine/transform).
|
|
34
|
+
*/
|
|
35
|
+
verify?: (parsed: TParsed, context: {
|
|
36
|
+
handshake: Socket['handshake'];
|
|
37
|
+
}) => TData | null | Promise<TData | null>;
|
|
38
|
+
}
|
|
39
|
+
export interface SocketIOServerConfig<TParsed = any, TData = TParsed> {
|
|
6
40
|
/** CORS — the browser origin(s) allowed to open a socket. */
|
|
7
41
|
cors: {
|
|
8
42
|
origin: string | string[];
|
|
@@ -18,6 +52,15 @@ export interface SocketIOServerConfig {
|
|
|
18
52
|
pingInterval?: number;
|
|
19
53
|
/** Runtime-neutral policy for accepting a new Engine.IO handshake. */
|
|
20
54
|
allowRequest?: SocketIORequestPolicy;
|
|
55
|
+
/**
|
|
56
|
+
* Typed identity gate — Zod-validate the handshake and put the result into
|
|
57
|
+
* `socket.data`. Registered as the **first** `io.use()` middleware, so app
|
|
58
|
+
* middlewares added later see the typed identity already in place. Type
|
|
59
|
+
* inference works on calls without explicit event generics (the
|
|
60
|
+
* `bindRealtimeServer` lane); with explicit generics, pass the identity
|
|
61
|
+
* types explicitly: `createSocketIOServer<S, C, Parsed, Data>`.
|
|
62
|
+
*/
|
|
63
|
+
handshake?: SocketIOHandshakeConfig<TParsed, TData>;
|
|
21
64
|
/** Typed Socket.IO options not owned by this wrapper. */
|
|
22
65
|
serverOptions?: Omit<Partial<ServerOptions>, 'allowRequest'>;
|
|
23
66
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"socket-io-config.d.ts","sourceRoot":"","sources":["../../src/server/socket-io-config.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"socket-io-config.d.ts","sourceRoot":"","sources":["../../src/server/socket-io-config.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,uFAAuF;AACvF,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAErF;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,uBAAuB,CAAC,OAAO,EAAE,KAAK,GAAG,OAAO;IAC/D,8CAA8C;IAC9C,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,CACP,MAAM,EAAE,OAAO,EACf,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;KAAE,KACxC,KAAK,GAAG,IAAI,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,oBAAoB,CAAC,OAAO,GAAG,GAAG,EAAE,KAAK,GAAG,OAAO;IAClE,6DAA6D;IAC7D,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAAC,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC3D,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,UAAU,CAAC,EAAE,KAAK,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;IAC5C,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sEAAsE;IACtE,YAAY,CAAC,EAAE,qBAAqB,CAAC;IACrC;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,uBAAuB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACpD,yDAAyD;IACzD,aAAa,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,cAAc,CAAC,CAAC;CAC9D"}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/** Node-facing Socket.IO surface without Bun engine declarations. */
|
|
2
2
|
import type { Server as HttpServer } from 'node:http';
|
|
3
|
-
import type { Server as SocketIOServer } from 'socket.io';
|
|
3
|
+
import type { DefaultEventsMap, Server as SocketIOServer } from 'socket.io';
|
|
4
4
|
import type { SocketEventMap } from '../browser/socket-io';
|
|
5
5
|
import type { SocketIOServerConfig } from './socket-io-config';
|
|
6
|
-
export type { SocketIORequestPolicy, SocketIOServerConfig } from './socket-io-config';
|
|
6
|
+
export type { SocketIOHandshakeConfig, SocketIORequestPolicy, SocketIOServerConfig, } from './socket-io-config';
|
|
7
7
|
/** The runtime-neutral part of a Socket.IO handle used by `serveNode`. */
|
|
8
|
-
export interface NodeSocketIOServerHandle<TServerEvents extends SocketEventMap, TClientEvents extends SocketEventMap> {
|
|
9
|
-
io: SocketIOServer<TClientEvents, TServerEvents>;
|
|
8
|
+
export interface NodeSocketIOServerHandle<TServerEvents extends SocketEventMap, TClientEvents extends SocketEventMap, TData = any> {
|
|
9
|
+
io: SocketIOServer<TClientEvents, TServerEvents, DefaultEventsMap, TData>;
|
|
10
10
|
attach(server: HttpServer): void;
|
|
11
11
|
beginShutdown(): void;
|
|
12
12
|
close(): Promise<void>;
|
|
13
13
|
connections(): number;
|
|
14
14
|
}
|
|
15
15
|
/** Create a Socket.IO handle typed only for the Node capabilities it exposes. */
|
|
16
|
-
export declare function createNodeSocketIOServer<TServerEvents extends SocketEventMap, TClientEvents extends SocketEventMap>(config: SocketIOServerConfig): Promise<NodeSocketIOServerHandle<TServerEvents, TClientEvents>>;
|
|
16
|
+
export declare function createNodeSocketIOServer<TServerEvents extends SocketEventMap, TClientEvents extends SocketEventMap, TParsed = any, TData = TParsed>(config: SocketIOServerConfig<TParsed, TData>): Promise<NodeSocketIOServerHandle<TServerEvents, TClientEvents, TData>>;
|
|
17
17
|
//# sourceMappingURL=socket-io-node.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"socket-io-node.d.ts","sourceRoot":"","sources":["../../src/server/socket-io-node.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,IAAI,cAAc,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"socket-io-node.d.ts","sourceRoot":"","sources":["../../src/server/socket-io-node.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,IAAI,cAAc,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE/D,YAAY,EACV,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAE5B,0EAA0E;AAC1E,MAAM,WAAW,wBAAwB,CACvC,aAAa,SAAS,cAAc,EACpC,aAAa,SAAS,cAAc,EACpC,KAAK,GAAG,GAAG;IAEX,EAAE,EAAE,cAAc,CAAC,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC;IAC1E,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IACjC,aAAa,IAAI,IAAI,CAAC;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,WAAW,IAAI,MAAM,CAAC;CACvB;AAED,iFAAiF;AACjF,wBAAsB,wBAAwB,CAC5C,aAAa,SAAS,cAAc,EACpC,aAAa,SAAS,cAAc,EAGpC,OAAO,GAAG,GAAG,EACb,KAAK,GAAG,OAAO,EAEf,MAAM,EAAE,oBAAoB,CAAC,OAAO,EAAE,KAAK,CAAC,GAC3C,OAAO,CAAC,wBAAwB,CAAC,aAAa,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC,CAExE"}
|
|
@@ -17,13 +17,13 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import type { Server as HttpServer } from 'node:http';
|
|
19
19
|
import type { Server as BunEngine } from '@socket.io/bun-engine';
|
|
20
|
-
import type { Server as SocketIOServer } from 'socket.io';
|
|
20
|
+
import type { DefaultEventsMap, Server as SocketIOServer } from 'socket.io';
|
|
21
21
|
import type { SocketEventMap } from '../browser/socket-io';
|
|
22
22
|
import type { BunServer } from './bun';
|
|
23
23
|
import type { SocketIOServerConfig } from './socket-io-config';
|
|
24
24
|
import type { RawRoute } from './types';
|
|
25
25
|
import { type ComposedLane } from './websocket';
|
|
26
|
-
export type { SocketIORequestPolicy, SocketIOServerConfig } from './socket-io-config';
|
|
26
|
+
export type { SocketIOHandshakeConfig, SocketIORequestPolicy, SocketIOServerConfig, } from './socket-io-config';
|
|
27
27
|
export interface SocketIOServerLifecycle {
|
|
28
28
|
/**
|
|
29
29
|
* WebSocket handler for `Bun.serve({ websocket })`. Real on Bun; on Node it is
|
|
@@ -52,11 +52,11 @@ export interface SocketIOServerLifecycle {
|
|
|
52
52
|
/** Current Engine.IO client count, when the engine has been bound. */
|
|
53
53
|
connections(): number;
|
|
54
54
|
}
|
|
55
|
-
export interface SocketIOServerHandle<TServerEvents extends SocketEventMap, TClientEvents extends SocketEventMap> extends SocketIOServerLifecycle {
|
|
55
|
+
export interface SocketIOServerHandle<TServerEvents extends SocketEventMap, TClientEvents extends SocketEventMap, TData = any> extends SocketIOServerLifecycle {
|
|
56
56
|
/** The typed Socket.IO server — attach `io.on('connection', ...)` handlers. */
|
|
57
|
-
io: SocketIOServer<TClientEvents, TServerEvents>;
|
|
57
|
+
io: SocketIOServer<TClientEvents, TServerEvents, DefaultEventsMap, TData>;
|
|
58
58
|
}
|
|
59
|
-
export declare function createSocketIOServer<TServerEvents extends SocketEventMap, TClientEvents extends SocketEventMap>(config: SocketIOServerConfig): Promise<SocketIOServerHandle<TServerEvents, TClientEvents>>;
|
|
59
|
+
export declare function createSocketIOServer<TServerEvents extends SocketEventMap, TClientEvents extends SocketEventMap, TParsed = any, TData = TParsed>(config: SocketIOServerConfig<TParsed, TData>): Promise<SocketIOServerHandle<TServerEvents, TClientEvents, TData>>;
|
|
60
60
|
/**
|
|
61
61
|
* Wrap a Socket.IO handle's `websocket` as a catch-all {@link ComposedLane} for
|
|
62
62
|
* {@link composeWebSocketHandlers} — when a second, raw WebSocket lane shares
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"socket-io.d.ts","sourceRoot":"","sources":["../../src/server/socket-io.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,EACV,MAAM,IAAI,SAAS,EAEpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EACV,MAAM,IAAI,cAAc,
|
|
1
|
+
{"version":3,"file":"socket-io.d.ts","sourceRoot":"","sources":["../../src/server/socket-io.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,EACV,MAAM,IAAI,SAAS,EAEpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EACV,gBAAgB,EAChB,MAAM,IAAI,cAAc,EAGzB,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAA2B,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AACxF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,KAAK,YAAY,EAAiB,MAAM,aAAa,CAAC;AAE/D,YAAY,EACV,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,uBAAuB;IACtC;;;;;OAKG;IACH,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IACzD;;;;;OAKG;IACH,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC3B;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IACjC,6EAA6E;IAC7E,aAAa,IAAI,IAAI,CAAC;IACtB,8EAA8E;IAC9E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,sEAAsE;IACtE,WAAW,IAAI,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB,CACnC,aAAa,SAAS,cAAc,EACpC,aAAa,SAAS,cAAc,EACpC,KAAK,GAAG,GAAG,CACX,SAAQ,uBAAuB;IAC/B,+EAA+E;IAC/E,EAAE,EAAE,cAAc,CAAC,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC;CAC3E;AA8GD,wBAAsB,oBAAoB,CACxC,aAAa,SAAS,cAAc,EACpC,aAAa,SAAS,cAAc,EAKpC,OAAO,GAAG,GAAG,EACb,KAAK,GAAG,OAAO,EAEf,MAAM,EAAE,oBAAoB,CAAC,OAAO,EAAE,KAAK,CAAC,GAC3C,OAAO,CAAC,oBAAoB,CAAC,aAAa,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC,CA6IpE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,oBAAoB,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC,WAAW,CAAC,GAC3E,YAAY,CAMd"}
|
package/llms-full.txt
CHANGED
|
@@ -851,6 +851,7 @@ server. See [Testing & deployment](./testing-and-deployment.md).
|
|
|
851
851
|
| `rawRoutes` | non-contract routes (see below) |
|
|
852
852
|
| `maxJsonBodyBytes` | optional JSON body cap (bytes); per-route value overrides; unset preserves existing behaviour |
|
|
853
853
|
| `port` / `hostname` | listen address — port defaults to `3000` |
|
|
854
|
+
| `unix` | listen on a unix domain socket instead of TCP — `'/run/app.sock'` or `{ path, mode }` (see below) |
|
|
854
855
|
| `cors` | CORS policy — `{ origin, credentials, methods, headers, exposeHeaders }`. `origin` is **required** when `cors` is present: pass an explicit origin (or list), or `'*'` to deliberately allow every origin — an origin-less config is a construction error, never a silent wildcard. Omit `cors` entirely to emit no CORS headers. |
|
|
855
856
|
| `hooks` | lifecycle hooks (see below) |
|
|
856
857
|
| `logging` | `true` for built-in request logs, or a `LoggingConfig` (see below) |
|
|
@@ -864,6 +865,41 @@ Native Bun `routes` are intentionally not accepted: Bun matches them before
|
|
|
864
865
|
`fetch`, so they could bypass shutdown admission. Use `rawRoutes`; they retain
|
|
865
866
|
the Fetch `Request → Response` model and participate in lifecycle tracking.
|
|
866
867
|
|
|
868
|
+
### Local daemon over a unix socket
|
|
869
|
+
|
|
870
|
+
A local daemon whose door is a socket file needs no TCP port at all:
|
|
871
|
+
|
|
872
|
+
```ts
|
|
873
|
+
const server = createServer({
|
|
874
|
+
services,
|
|
875
|
+
unix: { path: '/run/my-daemon.sock', mode: 0o600 },
|
|
876
|
+
})
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
`unix` is mutually exclusive with `port`/`hostname` (construction error). The
|
|
880
|
+
handle stays honest: `server.url` is `unix:///run/my-daemon.sock` — an
|
|
881
|
+
identifier, **not** a fetchable address (dial the path with
|
|
882
|
+
`createHttpClient({ unix })`, [client guide](client.md#unix-domain-sockets)) —
|
|
883
|
+
and `server.port` is `0`.
|
|
884
|
+
|
|
885
|
+
Socket-file hygiene is built in. A stale file left by a killed process is
|
|
886
|
+
reclaimed automatically: the path is probed, and only a socket that is owned by
|
|
887
|
+
the current user **and** answers no live listener is removed before binding
|
|
888
|
+
(best-effort — two processes racing the same path resolve through the loud
|
|
889
|
+
bind error of the loser). A regular file at the path, another user's socket, or
|
|
890
|
+
a live listener each fail with a specific error instead of being unlinked. A
|
|
891
|
+
clean `server.shutdown()` removes the file.
|
|
892
|
+
|
|
893
|
+
`mode` tightens the socket file permissions after listen. Bun creates the file
|
|
894
|
+
`0755` under a normal umask — since `connect(2)` requires *write* permission
|
|
895
|
+
that is already owner-only in practice — but when access to the socket **is**
|
|
896
|
+
the credential, set `mode: 0o600` explicitly and let the filesystem be the
|
|
897
|
+
policy. The Socket.IO lifecycle (`socket`) cannot mount on a unix listener
|
|
898
|
+
(socket.io clients dial TCP only — construction error); Bun's own WebSocket
|
|
899
|
+
client cannot dial a unix path either. Unix listeners are Bun-only: `srvx`
|
|
900
|
+
resolves a numeric port unconditionally, so `stitchkit/node` does not offer
|
|
901
|
+
`unix` (no half-support).
|
|
902
|
+
|
|
867
903
|
### Managed shutdown
|
|
868
904
|
|
|
869
905
|
```ts
|
|
@@ -1678,6 +1714,7 @@ without repeating transport configuration.
|
|
|
1678
1714
|
| `suppressUnauthorizedFor` | `[]` | exact contract-derived operation matchers whose expected 401 does not emit `unauthorized` |
|
|
1679
1715
|
| `parseError` | built-in | map an error body to `{ code, message, details, hint }` |
|
|
1680
1716
|
| `trace` | `false` | emit a W3C `traceparent` header on every request |
|
|
1717
|
+
| `unix` | — | dial a unix domain socket instead of TCP (Bun only, see below) |
|
|
1681
1718
|
|
|
1682
1719
|
`headers` as a function is the hook for runtime tokens — a bearer token or any
|
|
1683
1720
|
short-lived credential — re-evaluated on every request.
|
|
@@ -1691,6 +1728,26 @@ compile the prefix structure without a concrete tenant id. Matching is exact by
|
|
|
1691
1728
|
path segments, including params and trailing wildcards — a shared prefix never
|
|
1692
1729
|
suppresses a neighbouring protected endpoint.
|
|
1693
1730
|
|
|
1731
|
+
### Unix domain sockets
|
|
1732
|
+
|
|
1733
|
+
The same typed client dials a local daemon's socket file
|
|
1734
|
+
([server side](server.md#local-daemon-over-a-unix-socket)):
|
|
1735
|
+
|
|
1736
|
+
```ts
|
|
1737
|
+
const http = createHttpClient({
|
|
1738
|
+
baseUrl: 'http://localhost', // required prefix source; its host is ignored
|
|
1739
|
+
unix: '/run/my-daemon.sock',
|
|
1740
|
+
})
|
|
1741
|
+
const daemon = createClient(daemonContract, http)
|
|
1742
|
+
```
|
|
1743
|
+
|
|
1744
|
+
`baseUrl` stays required — it supplies the path prefix and the `Host` header,
|
|
1745
|
+
while the connection itself goes through the socket file. Bun runtime only:
|
|
1746
|
+
other runtimes ignore the option and dial `baseUrl` over TCP (Node's fetch
|
|
1747
|
+
would need an undici dispatcher — out of scope). A missing socket file
|
|
1748
|
+
surfaces as a normal `ApiError` and is not retried (transport retry stays
|
|
1749
|
+
connection-refused-only).
|
|
1750
|
+
|
|
1694
1751
|
`trace: true` mints a fresh root trace per request. The stitchkit server
|
|
1695
1752
|
[continues an inbound `traceparent`](./observability.md#trace-context), so the
|
|
1696
1753
|
browser call, the HTTP handler and every nested tool call share one trace id
|
|
@@ -3286,8 +3343,11 @@ export function publishExampleNote(realtime: ExampleRealtimePublisher): void {
|
|
|
3286
3343
|
| `beginShutdown()` / `connections()` | lifecycle surface consumed by the managed server |
|
|
3287
3344
|
|
|
3288
3345
|
`SocketIOServerConfig` also takes `path`, `transports`, `pingTimeout`,
|
|
3289
|
-
`pingInterval
|
|
3290
|
-
|
|
3346
|
+
`pingInterval`, a runtime-neutral `allowRequest(Request)` handshake policy and
|
|
3347
|
+
the typed **`handshake`** identity gate (schema + verify →
|
|
3348
|
+
[typed `socket.data`](#handshake-auth--cookie-or-token)). `allowRequest` is the
|
|
3349
|
+
transport gate (composed with managed-shutdown admission on both Bun and Node);
|
|
3350
|
+
`handshake` is the identity gate that runs after it.
|
|
3291
3351
|
For anything else socket.io's `ServerOptions` exposes, use the
|
|
3292
3352
|
typed **`serverOptions`** passthrough — most often `maxHttpBufferSize` to lift the
|
|
3293
3353
|
1 MB default for large emits:
|
|
@@ -3337,7 +3397,40 @@ subscribe once; reconnection is the wrapper's problem, not yours.
|
|
|
3337
3397
|
|
|
3338
3398
|
`SocketIOClientConfig` takes `url`, `path`, `withCredentials` (cookies on the
|
|
3339
3399
|
handshake — default `true`), `auth`, `query`, `extraHeaders`, `transports`,
|
|
3340
|
-
`reconnectionAttempts`, `reconnectionDelay
|
|
3400
|
+
`reconnectionAttempts`, `reconnectionDelay`, `retain` (below), `onConnectError`
|
|
3401
|
+
(handshake/connection failures — see the auth section) and `onDroppedEmit`
|
|
3402
|
+
(observability for emits dropped while disconnected — see below).
|
|
3403
|
+
|
|
3404
|
+
### Honest emit — what happens while disconnected
|
|
3405
|
+
|
|
3406
|
+
`emit` has exactly three outcomes, in order:
|
|
3407
|
+
|
|
3408
|
+
1. **A local contract violation throws** (validated `RealtimeClient` only) —
|
|
3409
|
+
validation runs before the connection guard, even while disconnected.
|
|
3410
|
+
2. **Disconnected → the emit is dropped**: `emit` returns `false` and the
|
|
3411
|
+
`onDroppedEmit` hook fires with the event name and wire arguments. This
|
|
3412
|
+
includes the short window right after `connect()` while the socket.io peer
|
|
3413
|
+
is still loading.
|
|
3414
|
+
3. **Otherwise `emit` returns `true`** — handed to the transport, which is
|
|
3415
|
+
*not* a delivery guarantee.
|
|
3416
|
+
|
|
3417
|
+
The default is deliberately a drop, not a buffer: after a reconnect, durable
|
|
3418
|
+
subscriptions and [sticky events](#sticky-events) replay current state
|
|
3419
|
+
deterministically, instead of the server receiving an unordered backlog of
|
|
3420
|
+
stale emits. What changed is that the drop is now observable — assert it
|
|
3421
|
+
per-call (`if (!client.emit(...)) …`) or centrally:
|
|
3422
|
+
|
|
3423
|
+
```ts
|
|
3424
|
+
const client = createSocketIOClient({
|
|
3425
|
+
url,
|
|
3426
|
+
onDroppedEmit: ({ event }) => metrics.count('realtime.dropped_emit', { event }),
|
|
3427
|
+
})
|
|
3428
|
+
```
|
|
3429
|
+
|
|
3430
|
+
Server-side emits (`realtime.emit`, `to(room).emit`, `connection.events.emit`)
|
|
3431
|
+
always return `true` — a broadcast into an empty room is not a drop, and the
|
|
3432
|
+
server has no disconnected state of this kind. For state that must survive
|
|
3433
|
+
gaps, see [durability](#durability--idempotent--replay).
|
|
3341
3434
|
|
|
3342
3435
|
### Sticky events
|
|
3343
3436
|
|
|
@@ -3392,32 +3485,71 @@ const socket = createRealtimeClient(realtimeContract, {
|
|
|
3392
3485
|
```
|
|
3393
3486
|
|
|
3394
3487
|
```ts
|
|
3395
|
-
// server — the
|
|
3488
|
+
// server — the typed identity gate: Zod-validate handshake.auth, verify,
|
|
3489
|
+
// and the result lands in socket.data — typed all the way to onConnection.
|
|
3396
3490
|
import { verifyJwt } from 'stitchkit/server'
|
|
3397
3491
|
|
|
3398
|
-
socket
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3492
|
+
const socket = await createSocketIOServer({
|
|
3493
|
+
cors: { origin: 'https://app.example.com' },
|
|
3494
|
+
handshake: {
|
|
3495
|
+
schema: z.object({ token: z.string() }),
|
|
3496
|
+
verify: async ({ token }) => ({ user: await verifyJwt(token, secret) }),
|
|
3497
|
+
},
|
|
3498
|
+
})
|
|
3499
|
+
|
|
3500
|
+
const realtime = bindRealtimeServer(realtimeContract, socket)
|
|
3501
|
+
realtime.onConnection(({ raw }) => {
|
|
3502
|
+
raw.data.user // typed — no String(...) coercions, no casts
|
|
3407
3503
|
})
|
|
3408
3504
|
```
|
|
3409
3505
|
|
|
3506
|
+
`verify` may be async (the wrapper runs it inside a settled promise chain —
|
|
3507
|
+
raw async `io.use` middleware would leak an unhandled rejection); throwing or
|
|
3508
|
+
returning `null` rejects the handshake **before** the connection handler and
|
|
3509
|
+
before any event validation. A thrown error's raw message is logged
|
|
3510
|
+
server-side and never reaches the unauthenticated peer — the wire always
|
|
3511
|
+
carries the generic `handshake rejected` (the same never-leak policy as the
|
|
3512
|
+
HTTP error normalizer). The schema itself must be synchronous (no async
|
|
3513
|
+
refine/transform). Omit `verify` and the schema output itself is the
|
|
3514
|
+
identity. The gate registers as the **first** middleware, so `socket.io.use(…)`
|
|
3515
|
+
middlewares you add afterwards see the typed `socket.data` already in place.
|
|
3516
|
+
Raw `io.use` remains available for anything beyond identity.
|
|
3517
|
+
|
|
3518
|
+
Type inference works on calls without explicit event generics (the
|
|
3519
|
+
`bindRealtimeServer` lane above). With explicit generics TypeScript cannot
|
|
3520
|
+
partially infer — pass the identity types too:
|
|
3521
|
+
`createSocketIOServer<S, C, z.infer<typeof schema>, Identity>`.
|
|
3522
|
+
|
|
3410
3523
|
A static object (`auth: { token }`) works too, but only the function form
|
|
3411
3524
|
re-reads on reconnect — prefer it for rotating tokens. `query` adds handshake
|
|
3412
|
-
URL params (`socket.handshake.query`)
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3525
|
+
URL params (`socket.handshake.query`) — note its values are **strings** on the
|
|
3526
|
+
wire, which is why the schema gate reads `auth`; `extraHeaders` adds handshake
|
|
3527
|
+
headers, but in a browser those apply to the **polling** transport only (a
|
|
3528
|
+
WebSocket upgrade cannot set request headers) — for browser WebSocket auth use
|
|
3529
|
+
`auth`.
|
|
3530
|
+
|
|
3531
|
+
**A gate rejection is terminal for the client.** Unlike a transport-level
|
|
3532
|
+
failure (which socket.io retries indefinitely), a middleware/handshake-gate
|
|
3533
|
+
rejection stops the client: socket.io destroys its retry path and will not
|
|
3534
|
+
reconnect on its own. The stitchkit client surfaces this through
|
|
3535
|
+
**`onConnectError`** with `terminal: true` (and `data.code ===
|
|
3536
|
+
'handshake_rejected'` for the built-in gate) and resets its connection intent —
|
|
3537
|
+
so recovery is explicit: rotate the credential, call `connect()`, and the
|
|
3538
|
+
function-form `auth` is re-read:
|
|
3539
|
+
|
|
3540
|
+
```ts
|
|
3541
|
+
const client = createRealtimeClient(realtimeContract, {
|
|
3542
|
+
url: 'https://api.example.com',
|
|
3543
|
+
auth: () => ({ token: getAccessToken() }),
|
|
3544
|
+
onConnectError: ({ terminal }) => {
|
|
3545
|
+
if (terminal) refreshTokenThen(() => client.connect())
|
|
3546
|
+
},
|
|
3547
|
+
})
|
|
3548
|
+
```
|
|
3417
3549
|
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3550
|
+
If an auth producer throws or rejects, the wrapper sends an empty auth object —
|
|
3551
|
+
the server gate then rejects it visibly (via `onConnectError`) instead of
|
|
3552
|
+
leaving the handshake waiting forever.
|
|
3421
3553
|
|
|
3422
3554
|
## Cache bridge
|
|
3423
3555
|
|
|
@@ -5277,6 +5409,28 @@ current one *up to* your target, and apply each snippet.
|
|
|
5277
5409
|
runtime): bootstrap the server, one HTTP request, and any feature you rely on
|
|
5278
5410
|
(Socket.IO connect, an MCP tool call, a multipart upload, …).
|
|
5279
5411
|
|
|
5412
|
+
## Released migration: 0.53.0
|
|
5413
|
+
|
|
5414
|
+
### Realtime `emit` returns `boolean` instead of `void`
|
|
5415
|
+
|
|
5416
|
+
Every **call site** compiles and behaves exactly as before — the return value
|
|
5417
|
+
is new information (`true` = accepted by the transport, `false` = dropped
|
|
5418
|
+
while the browser client was disconnected), not a behavior change. What breaks
|
|
5419
|
+
is **implementing** the interfaces: a test mock or app-side adapter of
|
|
5420
|
+
`SocketIOClient` / `RealtimeClient` / `ValidatedRealtimeSocket` /
|
|
5421
|
+
`RealtimeServer` whose `emit` returns `void` no longer typechecks.
|
|
5422
|
+
|
|
5423
|
+
```ts
|
|
5424
|
+
// before — a void mock satisfied the interface
|
|
5425
|
+
const mock: Pick<RealtimeClient<S, C>, 'emit'> = { emit: () => {} }
|
|
5426
|
+
// after — report acceptance (true is what a live server-side emit reports)
|
|
5427
|
+
const mock: Pick<RealtimeClient<S, C>, 'emit'> = { emit: () => true }
|
|
5428
|
+
```
|
|
5429
|
+
|
|
5430
|
+
While migrating, consider replacing hand-rolled `if (client.connected)` guards
|
|
5431
|
+
with the new honest surface: check `client.emit(...) === false`, or observe
|
|
5432
|
+
drops centrally with `onDroppedEmit`.
|
|
5433
|
+
|
|
5280
5434
|
## Released migration: 0.50.0
|
|
5281
5435
|
|
|
5282
5436
|
### The factory's scope union now covers per-endpoint overrides
|
|
@@ -6208,7 +6362,7 @@ The browser-and-server entrypoint. Re-exports everything from
|
|
|
6208
6362
|
| `ApiError` | class | a non-2xx response, with `code` / `status` / `details` / `hint` and optional readonly `traceId` from `x-request-id` |
|
|
6209
6363
|
| `HttpClient` | _type_ | the transport interface `createClient` builds on |
|
|
6210
6364
|
| `ConfiguredHttpClient` | _type_ | a framework-created `HttpClient` carrying its readonly `baseUrl` for URL builders |
|
|
6211
|
-
| `HttpClientConfig` | _type_ | config for `createHttpClient`; retry `limit` counts retries after the initial attempt (default 2 = at most 3 GET attempts), with `statusCodes: []` by default — [details](../guide/client.md#createhttpclient) |
|
|
6365
|
+
| `HttpClientConfig` | _type_ | config for `createHttpClient`; retry `limit` counts retries after the initial attempt (default 2 = at most 3 GET attempts), with `statusCodes: []` by default; `unix` dials a unix domain socket (Bun only) — [details](../guide/client.md#createhttpclient) |
|
|
6212
6366
|
| `UnauthorizedMatcher` | _type_ | exact `(pathname) => boolean` policy accepted by `suppressUnauthorizedFor` |
|
|
6213
6367
|
| `RequestOptions` | _type_ | per-call options — params, timeout, response type |
|
|
6214
6368
|
| `HeaderProvider` | _type_ | static or per-request headers |
|
|
@@ -6224,8 +6378,8 @@ The browser-and-server entrypoint. Re-exports everything from
|
|
|
6224
6378
|
| `createRealtimeClient` | function | inferred, runtime-validated Socket.IO client — [guide](../guide/realtime.md#client--createrealtimeclient) |
|
|
6225
6379
|
| `createRetainedTopics` | function | retained last-value store for sticky events — [guide](../guide/realtime.md#sticky-events) |
|
|
6226
6380
|
| `parseSSE` | function | parse an SSE `Response` into an async generator — [guide](../guide/client.md#sse) |
|
|
6227
|
-
| `SocketIOClient` | _type_ | the client handle |
|
|
6228
|
-
| `SocketIOClientConfig` | _type_ | config for `createSocketIOClient` (incl. `retain`) |
|
|
6381
|
+
| `SocketIOClient` | _type_ | the client handle; `emit` returns `false` for an emit dropped while disconnected |
|
|
6382
|
+
| `SocketIOClientConfig` | _type_ | config for `createSocketIOClient` (incl. `retain`, `onConnectError`, `onDroppedEmit`) |
|
|
6229
6383
|
| `SocketEventMap` | _type_ | the shape of an event map |
|
|
6230
6384
|
| `RealtimeClient` | _type_ | validated client inferred from a realtime contract |
|
|
6231
6385
|
| `RealtimeClientOptions` | _type_ | transport options and the rejected-event hook for `createRealtimeClient` |
|
|
@@ -6239,7 +6393,7 @@ The browser-and-server entrypoint. Re-exports everything from
|
|
|
6239
6393
|
| `RealtimeRejectDirection` | _type_ | server/client inbound/outbound rejection direction |
|
|
6240
6394
|
| `RealtimeRejectedEvent` | _type_ | structured rejected event with event, direction, phase, reason and fault |
|
|
6241
6395
|
| `RealtimeRejectedEventHook` | _type_ | sync/async observer for structured realtime rejections |
|
|
6242
|
-
| `ValidatedRealtimeSocket` | _type_ | runtime-validating `on`/`emit` surface inferred from registries |
|
|
6396
|
+
| `ValidatedRealtimeSocket` | _type_ | runtime-validating `on`/`emit` surface inferred from registries; `emit` returns "accepted by the transport" (`false` only for a client-side disconnected drop) |
|
|
6243
6397
|
| `RetainedTopics` | _type_ | the `createRetainedTopics` handle |
|
|
6244
6398
|
| `ParseSSEOptions` | _type_ | options for `parseSSE` |
|
|
6245
6399
|
|
|
@@ -6393,7 +6547,8 @@ Also re-exports the error helpers from `stitchkit/contract`.
|
|
|
6393
6547
|
| `ZodIssueSummary` | _type_ | one structured validation issue (`{ path, code, message }`) |
|
|
6394
6548
|
| `parseBody` | function | parse + Zod-validate a JSON body → `data` or `null` (no throw) |
|
|
6395
6549
|
| `HandlerConfig` | _type_ | config for `createHandler`, including optional `maxJsonBodyBytes`; bound to `BunServer` on this entrypoint |
|
|
6396
|
-
| `BunServerConfig` | _type_ | config for `createServer` (Bun) |
|
|
6550
|
+
| `BunServerConfig` | _type_ | config for `createServer` (Bun); `unix` listens on a unix domain socket (mutually exclusive with `port`/`hostname`) — [details](../guide/server.md#local-daemon-over-a-unix-socket) |
|
|
6551
|
+
| `UnixListenConfig` | _type_ | unix listener — a socket path, or `{ path, mode }` to tighten the file mode after listen |
|
|
6397
6552
|
| `BunServerHandle` | _type_ | managed Bun handle (`url`, `port`, `runtime`, `status`, `shutdown`) |
|
|
6398
6553
|
| `ManagedServerHandle` | _type_ | shared lifecycle shape generic over the runtime escape hatch |
|
|
6399
6554
|
| `ShutdownOptionsSchema` / `ShutdownOptions` | schema / _type_ | one graceful budget, bounded forced-completion timeout, retry hint and optional external abort signal |
|
|
@@ -6469,9 +6624,10 @@ Also re-exports the error helpers from `stitchkit/contract`.
|
|
|
6469
6624
|
| `bindRealtimeServer` | function | inferred, runtime-validated connection and broadcast boundary |
|
|
6470
6625
|
| `RealtimeServer` | _type_ | validated broadcast and connection API inferred from a realtime contract |
|
|
6471
6626
|
| `RealtimeServerConnection` | _type_ | one validated connection with raw socket access for auth and rooms |
|
|
6472
|
-
| `RealtimeServerHandle` | _type_ | minimal Socket.IO server handle accepted by `bindRealtimeServer` |
|
|
6627
|
+
| `RealtimeServerHandle` | _type_ | minimal Socket.IO server handle accepted by `bindRealtimeServer`; carries the handshake identity type through to `connection.raw.data` |
|
|
6473
6628
|
| `SocketIORequestPolicy` | _type_ | runtime-neutral async-capable Web `Request` handshake admission policy |
|
|
6474
|
-
| `SocketIOServerConfig` | _type_ | config for `createSocketIOServer` |
|
|
6629
|
+
| `SocketIOServerConfig` | _type_ | config for `createSocketIOServer`; `handshake` is the typed identity gate — [guide](../guide/realtime.md#handshake-auth--cookie-or-token) |
|
|
6630
|
+
| `SocketIOHandshakeConfig` | _type_ | the `handshake` gate — Zod `schema` over `handshake.auth` plus optional async `verify`; the result lands typed in `socket.data` |
|
|
6475
6631
|
| `SocketIOServerHandle` | _type_ | typed Socket.IO server plus Bun mount fields and idempotent lifecycle |
|
|
6476
6632
|
| `SocketIOServerLifecycle` | _type_ | non-generic Bun mount/shutdown portion accepted by `createServer` |
|
|
6477
6633
|
| `composeWebSocketHandlers` | function | compose one Bun `websocket` from N lanes — a raw binary lane beside Socket.IO ([guide](../guide/realtime.md#raw-binary-lane-bun)) |
|
package/package.json
CHANGED