@trpc/server 11.0.5-canary.2 → 11.1.1-canary.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/fastify/fastifyTRPCPlugin.js +2 -2
- package/dist/adapters/fastify/fastifyTRPCPlugin.mjs +2 -2
- package/dist/adapters/ws.d.ts +1 -1
- package/dist/adapters/ws.d.ts.map +1 -1
- package/dist/adapters/ws.js +102 -84
- package/dist/adapters/ws.mjs +102 -84
- package/dist/bundle-analysis.json +46 -46
- package/package.json +2 -2
- package/src/adapters/fastify/fastifyTRPCPlugin.ts +2 -2
- package/src/adapters/ws.ts +115 -91
|
@@ -42,8 +42,8 @@ function fastifyTRPCPlugin(fastify, opts, done) {
|
|
|
42
42
|
});
|
|
43
43
|
fastify.get(prefix ?? '/', {
|
|
44
44
|
websocket: true
|
|
45
|
-
},
|
|
46
|
-
|
|
45
|
+
}, (socket, req)=>{
|
|
46
|
+
onConnection(socket, req.raw);
|
|
47
47
|
if (trpcOptions?.keepAlive?.enabled) {
|
|
48
48
|
const { pingMs, pongWaitMs } = trpcOptions.keepAlive;
|
|
49
49
|
ws.handleKeepAlive(socket, pingMs, pongWaitMs);
|
|
@@ -40,8 +40,8 @@ function fastifyTRPCPlugin(fastify, opts, done) {
|
|
|
40
40
|
});
|
|
41
41
|
fastify.get(prefix ?? '/', {
|
|
42
42
|
websocket: true
|
|
43
|
-
},
|
|
44
|
-
|
|
43
|
+
}, (socket, req)=>{
|
|
44
|
+
onConnection(socket, req.raw);
|
|
45
45
|
if (trpcOptions?.keepAlive?.enabled) {
|
|
46
46
|
const { pingMs, pongWaitMs } = trpcOptions.keepAlive;
|
|
47
47
|
handleKeepAlive(socket, pingMs, pongWaitMs);
|
package/dist/adapters/ws.d.ts
CHANGED
|
@@ -43,7 +43,7 @@ export type WSSHandlerOptions<TRouter extends AnyRouter> = WSConnectionHandlerOp
|
|
|
43
43
|
*/
|
|
44
44
|
dangerouslyDisablePong?: boolean;
|
|
45
45
|
};
|
|
46
|
-
export declare function getWSConnectionHandler<TRouter extends AnyRouter>(opts: WSSHandlerOptions<TRouter>): (client: ws.WebSocket, req: IncomingMessage) =>
|
|
46
|
+
export declare function getWSConnectionHandler<TRouter extends AnyRouter>(opts: WSSHandlerOptions<TRouter>): (client: ws.WebSocket, req: IncomingMessage) => void;
|
|
47
47
|
/**
|
|
48
48
|
* Handle WebSocket keep-alive messages
|
|
49
49
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../../src/adapters/ws.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,MAAM,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,EACV,SAAS,EACT,qBAAqB,EACrB,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AASzB,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAa/D,OAAO,EAKL,KAAK,YAAY,EAClB,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../../src/adapters/ws.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,MAAM,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,EACV,SAAS,EACT,qBAAqB,EACrB,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AASzB,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAa/D,OAAO,EAKL,KAAK,YAAY,EAClB,MAAM,gCAAgC,CAAC;AAMxC,OAAO,EAAa,KAAK,8BAA8B,EAAE,MAAM,aAAa,CAAC;AAQ7E;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,8BAA8B,CACpE,eAAe,EACf,EAAE,CAAC,SAAS,CACb,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,kBAAkB,CAAC,OAAO,SAAS,SAAS,IAAI,CAC1D,IAAI,EAAE,yBAAyB,KAC5B,YAAY,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC;AAE/C,MAAM,MAAM,0BAA0B,CAAC,OAAO,SAAS,SAAS,IAC9D,kBAAkB,CAAC,OAAO,EAAE,eAAe,CAAC,GAC1C,qBAAqB,CACnB,kBAAkB,CAAC,OAAO,CAAC,EAC3B,kBAAkB,CAAC,OAAO,CAAC,CAC5B,CAAC;AAEN;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,OAAO,SAAS,SAAS,IACrD,0BAA0B,CAAC,OAAO,CAAC,GAAG;IACpC,GAAG,EAAE,EAAE,CAAC,eAAe,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE;QACV;;;WAGG;QACH,OAAO,EAAE,OAAO,CAAC;QACjB;;;WAGG;QACH,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB;;;WAGG;QACH,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC,CAAC;AAEJ,wBAAgB,sBAAsB,CAAC,OAAO,SAAS,SAAS,EAC9D,IAAI,EAAE,iBAAiB,CAAC,OAAO,CAAC,IAKxB,QAAQ,EAAE,CAAC,SAAS,EAAE,KAAK,eAAe,UAyanD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,EAAE,CAAC,SAAS,EACpB,MAAM,SAAS,EACf,UAAU,SAAQ,QAiCnB;AAED,wBAAgB,eAAe,CAAC,OAAO,SAAS,SAAS,EACvD,IAAI,EAAE,iBAAiB,CAAC,OAAO,CAAC;;EAyBjC"}
|
package/dist/adapters/ws.js
CHANGED
|
@@ -84,11 +84,10 @@ function _ts_dispose_resources(env) {
|
|
|
84
84
|
* Importing ws causes a build error
|
|
85
85
|
* @see https://github.com/trpc/trpc/pull/5279
|
|
86
86
|
*/ const WEBSOCKET_OPEN = 1; /* ws.WebSocket.OPEN */
|
|
87
|
-
const unsetContextPromiseSymbol = Symbol('unsetContextPromise');
|
|
88
87
|
function getWSConnectionHandler(opts) {
|
|
89
88
|
const { createContext, router: router$1 } = opts;
|
|
90
89
|
const { transformer: transformer$1 } = router$1._def._config;
|
|
91
|
-
return
|
|
90
|
+
return (client, req)=>{
|
|
92
91
|
const clientSubscriptions = new Map();
|
|
93
92
|
const abortController = new AbortController();
|
|
94
93
|
if (opts.keepAlive?.enabled) {
|
|
@@ -98,23 +97,28 @@ function getWSConnectionHandler(opts) {
|
|
|
98
97
|
function respond(untransformedJSON) {
|
|
99
98
|
client.send(JSON.stringify(transformer.transformTRPCResponse(router$1._def._config, untransformedJSON)));
|
|
100
99
|
}
|
|
101
|
-
function createCtxPromise(getConnectionParams) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
100
|
+
async function createCtxPromise(getConnectionParams) {
|
|
101
|
+
try {
|
|
102
|
+
return await utils.run(async ()=>{
|
|
103
|
+
ctx = await createContext?.({
|
|
104
|
+
req,
|
|
105
|
+
res: client,
|
|
106
|
+
info: {
|
|
107
|
+
connectionParams: getConnectionParams(),
|
|
108
|
+
calls: [],
|
|
109
|
+
isBatchCall: false,
|
|
110
|
+
accept: null,
|
|
111
|
+
type: 'unknown',
|
|
112
|
+
signal: abortController.signal,
|
|
113
|
+
url: null
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
return {
|
|
117
|
+
ok: true,
|
|
118
|
+
value: ctx
|
|
119
|
+
};
|
|
115
120
|
});
|
|
116
|
-
|
|
117
|
-
}).catch((cause)=>{
|
|
121
|
+
} catch (cause) {
|
|
118
122
|
const error = TRPCError.getTRPCErrorFromUnknown(cause);
|
|
119
123
|
opts.onError?.({
|
|
120
124
|
error,
|
|
@@ -139,8 +143,11 @@ function getWSConnectionHandler(opts) {
|
|
|
139
143
|
(globalThis.setImmediate ?? globalThis.setTimeout)(()=>{
|
|
140
144
|
client.close();
|
|
141
145
|
});
|
|
142
|
-
|
|
143
|
-
|
|
146
|
+
return {
|
|
147
|
+
ok: false,
|
|
148
|
+
error
|
|
149
|
+
};
|
|
150
|
+
}
|
|
144
151
|
}
|
|
145
152
|
let ctx = undefined;
|
|
146
153
|
/**
|
|
@@ -148,14 +155,35 @@ function getWSConnectionHandler(opts) {
|
|
|
148
155
|
*
|
|
149
156
|
* - the context promise will be created immediately on connection if no connectionParams are expected
|
|
150
157
|
* - if connection params are expected, they will be created once received
|
|
151
|
-
*/ let ctxPromise = incomingMessageToRequest.createURL(req).searchParams.get('connectionParams') === '1' ?
|
|
152
|
-
|
|
158
|
+
*/ let ctxPromise = incomingMessageToRequest.createURL(req).searchParams.get('connectionParams') === '1' ? null : createCtxPromise(()=>null);
|
|
159
|
+
function handleRequest(msg) {
|
|
153
160
|
const { id, jsonrpc } = msg;
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
code: '
|
|
161
|
+
if (id === null) {
|
|
162
|
+
const error = TRPCError.getTRPCErrorFromUnknown(new TRPCError.TRPCError({
|
|
163
|
+
code: 'PARSE_ERROR',
|
|
157
164
|
message: '`id` is required'
|
|
165
|
+
}));
|
|
166
|
+
opts.onError?.({
|
|
167
|
+
error,
|
|
168
|
+
path: undefined,
|
|
169
|
+
type: 'unknown',
|
|
170
|
+
ctx,
|
|
171
|
+
req,
|
|
172
|
+
input: undefined
|
|
158
173
|
});
|
|
174
|
+
respond({
|
|
175
|
+
id,
|
|
176
|
+
jsonrpc,
|
|
177
|
+
error: getErrorShape.getErrorShape({
|
|
178
|
+
config: router$1._def._config,
|
|
179
|
+
error,
|
|
180
|
+
type: 'unknown',
|
|
181
|
+
path: undefined,
|
|
182
|
+
input: undefined,
|
|
183
|
+
ctx
|
|
184
|
+
})
|
|
185
|
+
});
|
|
186
|
+
return;
|
|
159
187
|
}
|
|
160
188
|
if (msg.method === 'subscription.stop') {
|
|
161
189
|
clientSubscriptions.get(id)?.abort();
|
|
@@ -164,20 +192,24 @@ function getWSConnectionHandler(opts) {
|
|
|
164
192
|
const { path, lastEventId } = msg.params;
|
|
165
193
|
let { input } = msg.params;
|
|
166
194
|
const type = msg.method;
|
|
167
|
-
|
|
168
|
-
if (
|
|
169
|
-
|
|
170
|
-
input
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
195
|
+
if (lastEventId !== undefined) {
|
|
196
|
+
if (utils.isObject(input)) {
|
|
197
|
+
input = {
|
|
198
|
+
...input,
|
|
199
|
+
lastEventId: lastEventId
|
|
200
|
+
};
|
|
201
|
+
} else {
|
|
202
|
+
input ?? (input = {
|
|
203
|
+
lastEventId: lastEventId
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
utils.run(async ()=>{
|
|
208
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
209
|
+
const res = await ctxPromise; // asserts context has been set
|
|
210
|
+
if (!res.ok) {
|
|
211
|
+
throw res.error;
|
|
179
212
|
}
|
|
180
|
-
await ctxPromise; // asserts context has been set
|
|
181
213
|
const abortController = new AbortController();
|
|
182
214
|
const result = await router.callProcedure({
|
|
183
215
|
router: router$1,
|
|
@@ -345,7 +377,7 @@ function getWSConnectionHandler(opts) {
|
|
|
345
377
|
type: 'started'
|
|
346
378
|
}
|
|
347
379
|
});
|
|
348
|
-
}
|
|
380
|
+
}).catch((cause)=>{
|
|
349
381
|
// procedure threw an error
|
|
350
382
|
const error = TRPCError.getTRPCErrorFromUnknown(cause);
|
|
351
383
|
opts.onError?.({
|
|
@@ -368,9 +400,9 @@ function getWSConnectionHandler(opts) {
|
|
|
368
400
|
ctx
|
|
369
401
|
})
|
|
370
402
|
});
|
|
371
|
-
}
|
|
403
|
+
});
|
|
372
404
|
}
|
|
373
|
-
client.on('message',
|
|
405
|
+
client.on('message', (rawData)=>{
|
|
374
406
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
375
407
|
const msgStr = rawData.toString();
|
|
376
408
|
if (msgStr === 'PONG') {
|
|
@@ -382,7 +414,7 @@ function getWSConnectionHandler(opts) {
|
|
|
382
414
|
}
|
|
383
415
|
return;
|
|
384
416
|
}
|
|
385
|
-
if (ctxPromise
|
|
417
|
+
if (!ctxPromise) {
|
|
386
418
|
// If the ctxPromise wasn't created immediately, we're expecting the first message to be a TRPCConnectionParamsMessage
|
|
387
419
|
ctxPromise = createCtxPromise(()=>{
|
|
388
420
|
let msg;
|
|
@@ -403,30 +435,33 @@ function getWSConnectionHandler(opts) {
|
|
|
403
435
|
});
|
|
404
436
|
return;
|
|
405
437
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
msgJSON
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
438
|
+
const parsedMsgs = utils.run(()=>{
|
|
439
|
+
try {
|
|
440
|
+
const msgJSON = JSON.parse(msgStr);
|
|
441
|
+
const msgs = Array.isArray(msgJSON) ? msgJSON : [
|
|
442
|
+
msgJSON
|
|
443
|
+
];
|
|
444
|
+
return msgs.map((raw)=>parseTRPCMessage.parseTRPCMessage(raw, transformer$1));
|
|
445
|
+
} catch (cause) {
|
|
446
|
+
const error = new TRPCError.TRPCError({
|
|
447
|
+
code: 'PARSE_ERROR',
|
|
448
|
+
cause
|
|
449
|
+
});
|
|
450
|
+
respond({
|
|
451
|
+
id: null,
|
|
452
|
+
error: getErrorShape.getErrorShape({
|
|
453
|
+
config: router$1._def._config,
|
|
454
|
+
error,
|
|
455
|
+
type: 'unknown',
|
|
456
|
+
path: undefined,
|
|
457
|
+
input: undefined,
|
|
458
|
+
ctx
|
|
459
|
+
})
|
|
460
|
+
});
|
|
461
|
+
return [];
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
parsedMsgs.map(handleRequest);
|
|
430
465
|
});
|
|
431
466
|
// WebSocket errors should be handled, as otherwise unhandled exceptions will crash Node.js.
|
|
432
467
|
// This line was introduced after the following error brought down production systems:
|
|
@@ -449,9 +484,6 @@ function getWSConnectionHandler(opts) {
|
|
|
449
484
|
clientSubscriptions.clear();
|
|
450
485
|
abortController.abort();
|
|
451
486
|
});
|
|
452
|
-
if (ctxPromise !== unsetContextPromiseSymbol) {
|
|
453
|
-
await ctxPromise;
|
|
454
|
-
}
|
|
455
487
|
};
|
|
456
488
|
}
|
|
457
489
|
/**
|
|
@@ -488,21 +520,7 @@ function applyWSSHandler(opts) {
|
|
|
488
520
|
if (opts.prefix && !req.url?.startsWith(opts.prefix)) {
|
|
489
521
|
return;
|
|
490
522
|
}
|
|
491
|
-
onConnection(client, req)
|
|
492
|
-
opts.onError?.({
|
|
493
|
-
error: new TRPCError.TRPCError({
|
|
494
|
-
code: 'INTERNAL_SERVER_ERROR',
|
|
495
|
-
cause,
|
|
496
|
-
message: 'Failed to handle WebSocket connection'
|
|
497
|
-
}),
|
|
498
|
-
req: req,
|
|
499
|
-
path: undefined,
|
|
500
|
-
type: 'unknown',
|
|
501
|
-
ctx: undefined,
|
|
502
|
-
input: undefined
|
|
503
|
-
});
|
|
504
|
-
client.close();
|
|
505
|
-
});
|
|
523
|
+
onConnection(client, req);
|
|
506
524
|
});
|
|
507
525
|
return {
|
|
508
526
|
broadcastReconnectNotification: ()=>{
|
package/dist/adapters/ws.mjs
CHANGED
|
@@ -82,11 +82,10 @@ function _ts_dispose_resources(env) {
|
|
|
82
82
|
* Importing ws causes a build error
|
|
83
83
|
* @see https://github.com/trpc/trpc/pull/5279
|
|
84
84
|
*/ const WEBSOCKET_OPEN = 1; /* ws.WebSocket.OPEN */
|
|
85
|
-
const unsetContextPromiseSymbol = Symbol('unsetContextPromise');
|
|
86
85
|
function getWSConnectionHandler(opts) {
|
|
87
86
|
const { createContext, router } = opts;
|
|
88
87
|
const { transformer } = router._def._config;
|
|
89
|
-
return
|
|
88
|
+
return (client, req)=>{
|
|
90
89
|
const clientSubscriptions = new Map();
|
|
91
90
|
const abortController = new AbortController();
|
|
92
91
|
if (opts.keepAlive?.enabled) {
|
|
@@ -96,23 +95,28 @@ function getWSConnectionHandler(opts) {
|
|
|
96
95
|
function respond(untransformedJSON) {
|
|
97
96
|
client.send(JSON.stringify(transformTRPCResponse(router._def._config, untransformedJSON)));
|
|
98
97
|
}
|
|
99
|
-
function createCtxPromise(getConnectionParams) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
98
|
+
async function createCtxPromise(getConnectionParams) {
|
|
99
|
+
try {
|
|
100
|
+
return await run(async ()=>{
|
|
101
|
+
ctx = await createContext?.({
|
|
102
|
+
req,
|
|
103
|
+
res: client,
|
|
104
|
+
info: {
|
|
105
|
+
connectionParams: getConnectionParams(),
|
|
106
|
+
calls: [],
|
|
107
|
+
isBatchCall: false,
|
|
108
|
+
accept: null,
|
|
109
|
+
type: 'unknown',
|
|
110
|
+
signal: abortController.signal,
|
|
111
|
+
url: null
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
return {
|
|
115
|
+
ok: true,
|
|
116
|
+
value: ctx
|
|
117
|
+
};
|
|
113
118
|
});
|
|
114
|
-
|
|
115
|
-
}).catch((cause)=>{
|
|
119
|
+
} catch (cause) {
|
|
116
120
|
const error = getTRPCErrorFromUnknown(cause);
|
|
117
121
|
opts.onError?.({
|
|
118
122
|
error,
|
|
@@ -137,8 +141,11 @@ function getWSConnectionHandler(opts) {
|
|
|
137
141
|
(globalThis.setImmediate ?? globalThis.setTimeout)(()=>{
|
|
138
142
|
client.close();
|
|
139
143
|
});
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
return {
|
|
145
|
+
ok: false,
|
|
146
|
+
error
|
|
147
|
+
};
|
|
148
|
+
}
|
|
142
149
|
}
|
|
143
150
|
let ctx = undefined;
|
|
144
151
|
/**
|
|
@@ -146,14 +153,35 @@ function getWSConnectionHandler(opts) {
|
|
|
146
153
|
*
|
|
147
154
|
* - the context promise will be created immediately on connection if no connectionParams are expected
|
|
148
155
|
* - if connection params are expected, they will be created once received
|
|
149
|
-
*/ let ctxPromise = createURL(req).searchParams.get('connectionParams') === '1' ?
|
|
150
|
-
|
|
156
|
+
*/ let ctxPromise = createURL(req).searchParams.get('connectionParams') === '1' ? null : createCtxPromise(()=>null);
|
|
157
|
+
function handleRequest(msg) {
|
|
151
158
|
const { id, jsonrpc } = msg;
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
code: '
|
|
159
|
+
if (id === null) {
|
|
160
|
+
const error = getTRPCErrorFromUnknown(new TRPCError({
|
|
161
|
+
code: 'PARSE_ERROR',
|
|
155
162
|
message: '`id` is required'
|
|
163
|
+
}));
|
|
164
|
+
opts.onError?.({
|
|
165
|
+
error,
|
|
166
|
+
path: undefined,
|
|
167
|
+
type: 'unknown',
|
|
168
|
+
ctx,
|
|
169
|
+
req,
|
|
170
|
+
input: undefined
|
|
156
171
|
});
|
|
172
|
+
respond({
|
|
173
|
+
id,
|
|
174
|
+
jsonrpc,
|
|
175
|
+
error: getErrorShape({
|
|
176
|
+
config: router._def._config,
|
|
177
|
+
error,
|
|
178
|
+
type: 'unknown',
|
|
179
|
+
path: undefined,
|
|
180
|
+
input: undefined,
|
|
181
|
+
ctx
|
|
182
|
+
})
|
|
183
|
+
});
|
|
184
|
+
return;
|
|
157
185
|
}
|
|
158
186
|
if (msg.method === 'subscription.stop') {
|
|
159
187
|
clientSubscriptions.get(id)?.abort();
|
|
@@ -162,20 +190,24 @@ function getWSConnectionHandler(opts) {
|
|
|
162
190
|
const { path, lastEventId } = msg.params;
|
|
163
191
|
let { input } = msg.params;
|
|
164
192
|
const type = msg.method;
|
|
165
|
-
|
|
166
|
-
if (
|
|
167
|
-
|
|
168
|
-
input
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
193
|
+
if (lastEventId !== undefined) {
|
|
194
|
+
if (isObject(input)) {
|
|
195
|
+
input = {
|
|
196
|
+
...input,
|
|
197
|
+
lastEventId: lastEventId
|
|
198
|
+
};
|
|
199
|
+
} else {
|
|
200
|
+
input ?? (input = {
|
|
201
|
+
lastEventId: lastEventId
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
run(async ()=>{
|
|
206
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
207
|
+
const res = await ctxPromise; // asserts context has been set
|
|
208
|
+
if (!res.ok) {
|
|
209
|
+
throw res.error;
|
|
177
210
|
}
|
|
178
|
-
await ctxPromise; // asserts context has been set
|
|
179
211
|
const abortController = new AbortController();
|
|
180
212
|
const result = await callProcedure({
|
|
181
213
|
router,
|
|
@@ -343,7 +375,7 @@ function getWSConnectionHandler(opts) {
|
|
|
343
375
|
type: 'started'
|
|
344
376
|
}
|
|
345
377
|
});
|
|
346
|
-
}
|
|
378
|
+
}).catch((cause)=>{
|
|
347
379
|
// procedure threw an error
|
|
348
380
|
const error = getTRPCErrorFromUnknown(cause);
|
|
349
381
|
opts.onError?.({
|
|
@@ -366,9 +398,9 @@ function getWSConnectionHandler(opts) {
|
|
|
366
398
|
ctx
|
|
367
399
|
})
|
|
368
400
|
});
|
|
369
|
-
}
|
|
401
|
+
});
|
|
370
402
|
}
|
|
371
|
-
client.on('message',
|
|
403
|
+
client.on('message', (rawData)=>{
|
|
372
404
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
373
405
|
const msgStr = rawData.toString();
|
|
374
406
|
if (msgStr === 'PONG') {
|
|
@@ -380,7 +412,7 @@ function getWSConnectionHandler(opts) {
|
|
|
380
412
|
}
|
|
381
413
|
return;
|
|
382
414
|
}
|
|
383
|
-
if (ctxPromise
|
|
415
|
+
if (!ctxPromise) {
|
|
384
416
|
// If the ctxPromise wasn't created immediately, we're expecting the first message to be a TRPCConnectionParamsMessage
|
|
385
417
|
ctxPromise = createCtxPromise(()=>{
|
|
386
418
|
let msg;
|
|
@@ -401,30 +433,33 @@ function getWSConnectionHandler(opts) {
|
|
|
401
433
|
});
|
|
402
434
|
return;
|
|
403
435
|
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
msgJSON
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
436
|
+
const parsedMsgs = run(()=>{
|
|
437
|
+
try {
|
|
438
|
+
const msgJSON = JSON.parse(msgStr);
|
|
439
|
+
const msgs = Array.isArray(msgJSON) ? msgJSON : [
|
|
440
|
+
msgJSON
|
|
441
|
+
];
|
|
442
|
+
return msgs.map((raw)=>parseTRPCMessage(raw, transformer));
|
|
443
|
+
} catch (cause) {
|
|
444
|
+
const error = new TRPCError({
|
|
445
|
+
code: 'PARSE_ERROR',
|
|
446
|
+
cause
|
|
447
|
+
});
|
|
448
|
+
respond({
|
|
449
|
+
id: null,
|
|
450
|
+
error: getErrorShape({
|
|
451
|
+
config: router._def._config,
|
|
452
|
+
error,
|
|
453
|
+
type: 'unknown',
|
|
454
|
+
path: undefined,
|
|
455
|
+
input: undefined,
|
|
456
|
+
ctx
|
|
457
|
+
})
|
|
458
|
+
});
|
|
459
|
+
return [];
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
parsedMsgs.map(handleRequest);
|
|
428
463
|
});
|
|
429
464
|
// WebSocket errors should be handled, as otherwise unhandled exceptions will crash Node.js.
|
|
430
465
|
// This line was introduced after the following error brought down production systems:
|
|
@@ -447,9 +482,6 @@ function getWSConnectionHandler(opts) {
|
|
|
447
482
|
clientSubscriptions.clear();
|
|
448
483
|
abortController.abort();
|
|
449
484
|
});
|
|
450
|
-
if (ctxPromise !== unsetContextPromiseSymbol) {
|
|
451
|
-
await ctxPromise;
|
|
452
|
-
}
|
|
453
485
|
};
|
|
454
486
|
}
|
|
455
487
|
/**
|
|
@@ -486,21 +518,7 @@ function applyWSSHandler(opts) {
|
|
|
486
518
|
if (opts.prefix && !req.url?.startsWith(opts.prefix)) {
|
|
487
519
|
return;
|
|
488
520
|
}
|
|
489
|
-
onConnection(client, req)
|
|
490
|
-
opts.onError?.({
|
|
491
|
-
error: new TRPCError({
|
|
492
|
-
code: 'INTERNAL_SERVER_ERROR',
|
|
493
|
-
cause,
|
|
494
|
-
message: 'Failed to handle WebSocket connection'
|
|
495
|
-
}),
|
|
496
|
-
req: req,
|
|
497
|
-
path: undefined,
|
|
498
|
-
type: 'unknown',
|
|
499
|
-
ctx: undefined,
|
|
500
|
-
input: undefined
|
|
501
|
-
});
|
|
502
|
-
client.close();
|
|
503
|
-
});
|
|
521
|
+
onConnection(client, req);
|
|
504
522
|
});
|
|
505
523
|
return {
|
|
506
524
|
broadcastReconnectNotification: ()=>{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"bundleSize":
|
|
3
|
-
"bundleOrigSize":
|
|
4
|
-
"bundleReduction": 13.
|
|
2
|
+
"bundleSize": 202625,
|
|
3
|
+
"bundleOrigSize": 235222,
|
|
4
|
+
"bundleReduction": 13.86,
|
|
5
5
|
"modules": [
|
|
6
6
|
{
|
|
7
7
|
"id": "/src/unstable-core-do-not-import/http/resolveResponse.ts",
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
"dependents": [
|
|
15
15
|
"/src/unstable-core-do-not-import.ts"
|
|
16
16
|
],
|
|
17
|
-
"percent": 10.
|
|
17
|
+
"percent": 10.41,
|
|
18
18
|
"reduction": 0
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
"id": "/src/adapters/ws.ts",
|
|
22
|
-
"size":
|
|
23
|
-
"origSize":
|
|
22
|
+
"size": 20656,
|
|
23
|
+
"origSize": 16339,
|
|
24
24
|
"renderedExports": [
|
|
25
25
|
"getWSConnectionHandler",
|
|
26
26
|
"handleKeepAlive",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"dependents": [
|
|
31
31
|
"/src/adapters/fastify/fastifyTRPCPlugin.ts"
|
|
32
32
|
],
|
|
33
|
-
"percent":
|
|
33
|
+
"percent": 10.19,
|
|
34
34
|
"reduction": 0
|
|
35
35
|
},
|
|
36
36
|
{
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"/src/unstable-core-do-not-import.ts",
|
|
48
48
|
"/src/unstable-core-do-not-import/http/resolveResponse.ts"
|
|
49
49
|
],
|
|
50
|
-
"percent": 9.
|
|
50
|
+
"percent": 9.84,
|
|
51
51
|
"reduction": 0
|
|
52
52
|
},
|
|
53
53
|
{
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"/src/unstable-core-do-not-import.ts",
|
|
65
65
|
"/src/unstable-core-do-not-import/http/resolveResponse.ts"
|
|
66
66
|
],
|
|
67
|
-
"percent": 6.
|
|
67
|
+
"percent": 6.39,
|
|
68
68
|
"reduction": 0
|
|
69
69
|
},
|
|
70
70
|
{
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
],
|
|
78
78
|
"removedExports": [],
|
|
79
79
|
"dependents": [],
|
|
80
|
-
"percent": 6
|
|
80
|
+
"percent": 6,
|
|
81
81
|
"reduction": 11.62
|
|
82
82
|
},
|
|
83
83
|
{
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"/src/unstable-core-do-not-import/initTRPC.ts",
|
|
99
99
|
"/src/unstable-core-do-not-import/http/contentType.ts"
|
|
100
100
|
],
|
|
101
|
-
"percent": 5.
|
|
101
|
+
"percent": 5.01,
|
|
102
102
|
"reduction": 29.54
|
|
103
103
|
},
|
|
104
104
|
{
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
"dependents": [
|
|
113
113
|
"/src/unstable-core-do-not-import/stream/jsonl.ts"
|
|
114
114
|
],
|
|
115
|
-
"percent": 4.
|
|
115
|
+
"percent": 4.01,
|
|
116
116
|
"reduction": 0
|
|
117
117
|
},
|
|
118
118
|
{
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
"/src/unstable-core-do-not-import.ts",
|
|
128
128
|
"/src/unstable-core-do-not-import/http/resolveResponse.ts"
|
|
129
129
|
],
|
|
130
|
-
"percent": 3.
|
|
130
|
+
"percent": 3.89,
|
|
131
131
|
"reduction": 0.83
|
|
132
132
|
},
|
|
133
133
|
{
|
|
@@ -142,7 +142,7 @@
|
|
|
142
142
|
"/src/unstable-core-do-not-import.ts",
|
|
143
143
|
"/src/unstable-core-do-not-import/initTRPC.ts"
|
|
144
144
|
],
|
|
145
|
-
"percent": 2.
|
|
145
|
+
"percent": 2.92,
|
|
146
146
|
"reduction": 66.3
|
|
147
147
|
},
|
|
148
148
|
{
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
"/src/unstable-core-do-not-import/stream/sse.ts",
|
|
163
163
|
"/src/unstable-core-do-not-import/stream/utils/withPing.ts"
|
|
164
164
|
],
|
|
165
|
-
"percent": 2.
|
|
165
|
+
"percent": 2.82,
|
|
166
166
|
"reduction": 0
|
|
167
167
|
},
|
|
168
168
|
{
|
|
@@ -176,7 +176,7 @@
|
|
|
176
176
|
"dependents": [
|
|
177
177
|
"/src/adapters/aws-lambda/index.ts"
|
|
178
178
|
],
|
|
179
|
-
"percent": 2.
|
|
179
|
+
"percent": 2.67,
|
|
180
180
|
"reduction": 12.47
|
|
181
181
|
},
|
|
182
182
|
{
|
|
@@ -212,7 +212,7 @@
|
|
|
212
212
|
"/src/unstable-core-do-not-import/stream/jsonl.ts",
|
|
213
213
|
"/src/unstable-core-do-not-import/stream/sse.ts"
|
|
214
214
|
],
|
|
215
|
-
"percent": 2.
|
|
215
|
+
"percent": 2.19,
|
|
216
216
|
"reduction": 0
|
|
217
217
|
},
|
|
218
218
|
{
|
|
@@ -289,7 +289,7 @@
|
|
|
289
289
|
"dependents": [
|
|
290
290
|
"/src/adapters/node-http/index.ts"
|
|
291
291
|
],
|
|
292
|
-
"percent": 1.
|
|
292
|
+
"percent": 1.35,
|
|
293
293
|
"reduction": 16.3
|
|
294
294
|
},
|
|
295
295
|
{
|
|
@@ -309,7 +309,7 @@
|
|
|
309
309
|
"/src/unstable-core-do-not-import/router.ts",
|
|
310
310
|
"/src/unstable-core-do-not-import/initTRPC.ts"
|
|
311
311
|
],
|
|
312
|
-
"percent": 1.
|
|
312
|
+
"percent": 1.35,
|
|
313
313
|
"reduction": 45.98
|
|
314
314
|
},
|
|
315
315
|
{
|
|
@@ -323,7 +323,7 @@
|
|
|
323
323
|
"dependents": [
|
|
324
324
|
"/src/unstable-core-do-not-import.ts"
|
|
325
325
|
],
|
|
326
|
-
"percent": 1.
|
|
326
|
+
"percent": 1.31,
|
|
327
327
|
"reduction": 40.81
|
|
328
328
|
},
|
|
329
329
|
{
|
|
@@ -381,7 +381,7 @@
|
|
|
381
381
|
"/src/unstable-core-do-not-import/stream/jsonl.ts",
|
|
382
382
|
"/src/unstable-core-do-not-import/stream/sse.ts"
|
|
383
383
|
],
|
|
384
|
-
"percent": 1.
|
|
384
|
+
"percent": 1.21,
|
|
385
385
|
"reduction": 17.51
|
|
386
386
|
},
|
|
387
387
|
{
|
|
@@ -505,8 +505,8 @@
|
|
|
505
505
|
},
|
|
506
506
|
{
|
|
507
507
|
"id": "/src/adapters/fastify/fastifyTRPCPlugin.ts",
|
|
508
|
-
"size":
|
|
509
|
-
"origSize":
|
|
508
|
+
"size": 1765,
|
|
509
|
+
"origSize": 2534,
|
|
510
510
|
"renderedExports": [
|
|
511
511
|
"fastifyTRPCPlugin"
|
|
512
512
|
],
|
|
@@ -514,8 +514,8 @@
|
|
|
514
514
|
"dependents": [
|
|
515
515
|
"/src/adapters/fastify/index.ts"
|
|
516
516
|
],
|
|
517
|
-
"percent": 0.
|
|
518
|
-
"reduction": 30.
|
|
517
|
+
"percent": 0.87,
|
|
518
|
+
"reduction": 30.35
|
|
519
519
|
},
|
|
520
520
|
{
|
|
521
521
|
"id": "/src/unstable-core-do-not-import/stream/utils/disposable.ts",
|
|
@@ -571,7 +571,7 @@
|
|
|
571
571
|
],
|
|
572
572
|
"removedExports": [],
|
|
573
573
|
"dependents": [],
|
|
574
|
-
"percent": 0.
|
|
574
|
+
"percent": 0.65,
|
|
575
575
|
"reduction": 35.1
|
|
576
576
|
},
|
|
577
577
|
{
|
|
@@ -588,7 +588,7 @@
|
|
|
588
588
|
"/src/adapters/next-app-dir/nextAppDirCaller.ts",
|
|
589
589
|
"/src/adapters/next-app-dir/rethrowNextErrors.ts"
|
|
590
590
|
],
|
|
591
|
-
"percent": 0.
|
|
591
|
+
"percent": 0.65,
|
|
592
592
|
"reduction": 0
|
|
593
593
|
},
|
|
594
594
|
{
|
|
@@ -619,7 +619,7 @@
|
|
|
619
619
|
"/src/unstable-core-do-not-import.ts",
|
|
620
620
|
"/src/unstable-core-do-not-import/http/contentType.ts"
|
|
621
621
|
],
|
|
622
|
-
"percent": 0.
|
|
622
|
+
"percent": 0.54,
|
|
623
623
|
"reduction": 15.08
|
|
624
624
|
},
|
|
625
625
|
{
|
|
@@ -690,7 +690,7 @@
|
|
|
690
690
|
"/src/unstable-core-do-not-import.ts",
|
|
691
691
|
"/src/unstable-core-do-not-import/stream/sse.ts"
|
|
692
692
|
],
|
|
693
|
-
"percent": 0.
|
|
693
|
+
"percent": 0.38,
|
|
694
694
|
"reduction": 44.13
|
|
695
695
|
},
|
|
696
696
|
{
|
|
@@ -702,7 +702,7 @@
|
|
|
702
702
|
],
|
|
703
703
|
"removedExports": [],
|
|
704
704
|
"dependents": [],
|
|
705
|
-
"percent": 0.
|
|
705
|
+
"percent": 0.37,
|
|
706
706
|
"reduction": 66.61
|
|
707
707
|
},
|
|
708
708
|
{
|
|
@@ -896,6 +896,16 @@
|
|
|
896
896
|
"percent": 0,
|
|
897
897
|
"reduction": 100
|
|
898
898
|
},
|
|
899
|
+
{
|
|
900
|
+
"id": "/src/shared.ts",
|
|
901
|
+
"size": 0,
|
|
902
|
+
"origSize": 653,
|
|
903
|
+
"renderedExports": [],
|
|
904
|
+
"removedExports": [],
|
|
905
|
+
"dependents": [],
|
|
906
|
+
"percent": 0,
|
|
907
|
+
"reduction": 100
|
|
908
|
+
},
|
|
899
909
|
{
|
|
900
910
|
"id": "/src/rpc.ts",
|
|
901
911
|
"size": 0,
|
|
@@ -915,8 +925,8 @@
|
|
|
915
925
|
"dependents": [
|
|
916
926
|
"/src/adapters/express.ts",
|
|
917
927
|
"/src/adapters/next.ts",
|
|
918
|
-
"/src/adapters/ws.ts",
|
|
919
928
|
"/src/adapters/standalone.ts",
|
|
929
|
+
"/src/adapters/ws.ts",
|
|
920
930
|
"/src/adapters/node-http/nodeHTTPRequestHandler.ts",
|
|
921
931
|
"/src/adapters/next-app-dir/nextAppDirCaller.ts",
|
|
922
932
|
"/src/adapters/node-http/writeResponse.ts"
|
|
@@ -924,16 +934,6 @@
|
|
|
924
934
|
"percent": 0,
|
|
925
935
|
"reduction": 100
|
|
926
936
|
},
|
|
927
|
-
{
|
|
928
|
-
"id": "/src/shared.ts",
|
|
929
|
-
"size": 0,
|
|
930
|
-
"origSize": 653,
|
|
931
|
-
"renderedExports": [],
|
|
932
|
-
"removedExports": [],
|
|
933
|
-
"dependents": [],
|
|
934
|
-
"percent": 0,
|
|
935
|
-
"reduction": 100
|
|
936
|
-
},
|
|
937
937
|
{
|
|
938
938
|
"id": "/src/adapters/next-app-dir.ts",
|
|
939
939
|
"size": 0,
|
|
@@ -957,9 +957,9 @@
|
|
|
957
957
|
"reduction": 100
|
|
958
958
|
},
|
|
959
959
|
{
|
|
960
|
-
"id": "/src/adapters/
|
|
960
|
+
"id": "/src/adapters/fastify/index.ts",
|
|
961
961
|
"size": 0,
|
|
962
|
-
"origSize":
|
|
962
|
+
"origSize": 78,
|
|
963
963
|
"renderedExports": [],
|
|
964
964
|
"removedExports": [],
|
|
965
965
|
"dependents": [],
|
|
@@ -967,9 +967,9 @@
|
|
|
967
967
|
"reduction": 100
|
|
968
968
|
},
|
|
969
969
|
{
|
|
970
|
-
"id": "/src/adapters/
|
|
970
|
+
"id": "/src/adapters/fetch/index.ts",
|
|
971
971
|
"size": 0,
|
|
972
|
-
"origSize":
|
|
972
|
+
"origSize": 64,
|
|
973
973
|
"renderedExports": [],
|
|
974
974
|
"removedExports": [],
|
|
975
975
|
"dependents": [],
|
|
@@ -985,8 +985,8 @@
|
|
|
985
985
|
"dependents": [
|
|
986
986
|
"/src/adapters/express.ts",
|
|
987
987
|
"/src/adapters/next.ts",
|
|
988
|
-
"/src/adapters/ws.ts",
|
|
989
988
|
"/src/adapters/standalone.ts",
|
|
989
|
+
"/src/adapters/ws.ts",
|
|
990
990
|
"/src/adapters/fastify/fastifyRequestHandler.ts"
|
|
991
991
|
],
|
|
992
992
|
"percent": 0,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trpc/server",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.1.1-canary.8+9beb26c63",
|
|
4
4
|
"description": "The tRPC server library",
|
|
5
5
|
"author": "KATT",
|
|
6
6
|
"license": "MIT",
|
|
@@ -152,5 +152,5 @@
|
|
|
152
152
|
"peerDependencies": {
|
|
153
153
|
"typescript": ">=5.7.2"
|
|
154
154
|
},
|
|
155
|
-
"gitHead": "
|
|
155
|
+
"gitHead": "9beb26c636d44852e0f407f3d7a82ad54df65b4d"
|
|
156
156
|
}
|
|
@@ -68,8 +68,8 @@ export function fastifyTRPCPlugin<TRouter extends AnyRouter>(
|
|
|
68
68
|
...trpcOptions,
|
|
69
69
|
});
|
|
70
70
|
|
|
71
|
-
fastify.get(prefix ?? '/', { websocket: true },
|
|
72
|
-
|
|
71
|
+
fastify.get(prefix ?? '/', { websocket: true }, (socket, req) => {
|
|
72
|
+
onConnection(socket, req.raw);
|
|
73
73
|
if (trpcOptions?.keepAlive?.enabled) {
|
|
74
74
|
const { pingMs, pongWaitMs } = trpcOptions.keepAlive;
|
|
75
75
|
handleKeepAlive(socket, pingMs, pongWaitMs);
|
package/src/adapters/ws.ts
CHANGED
|
@@ -34,6 +34,8 @@ import {
|
|
|
34
34
|
type MaybePromise,
|
|
35
35
|
} from '../unstable-core-do-not-import';
|
|
36
36
|
// eslint-disable-next-line no-restricted-imports
|
|
37
|
+
import type { Result } from '../unstable-core-do-not-import';
|
|
38
|
+
// eslint-disable-next-line no-restricted-imports
|
|
37
39
|
import { iteratorResource } from '../unstable-core-do-not-import/stream/utils/asyncIterable';
|
|
38
40
|
import { Unpromise } from '../vendor/unpromise';
|
|
39
41
|
import { createURL, type NodeHTTPCreateContextFnOptions } from './node-http';
|
|
@@ -98,14 +100,16 @@ export type WSSHandlerOptions<TRouter extends AnyRouter> =
|
|
|
98
100
|
dangerouslyDisablePong?: boolean;
|
|
99
101
|
};
|
|
100
102
|
|
|
101
|
-
const unsetContextPromiseSymbol = Symbol('unsetContextPromise');
|
|
102
103
|
export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
103
104
|
opts: WSSHandlerOptions<TRouter>,
|
|
104
105
|
) {
|
|
105
106
|
const { createContext, router } = opts;
|
|
106
107
|
const { transformer } = router._def._config;
|
|
107
108
|
|
|
108
|
-
return
|
|
109
|
+
return (client: ws.WebSocket, req: IncomingMessage) => {
|
|
110
|
+
type Context = inferRouterContext<TRouter>;
|
|
111
|
+
type ContextResult = Result<Context>;
|
|
112
|
+
|
|
109
113
|
const clientSubscriptions = new Map<number | string, AbortController>();
|
|
110
114
|
const abortController = new AbortController();
|
|
111
115
|
|
|
@@ -122,26 +126,31 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
|
122
126
|
);
|
|
123
127
|
}
|
|
124
128
|
|
|
125
|
-
function createCtxPromise(
|
|
129
|
+
async function createCtxPromise(
|
|
126
130
|
getConnectionParams: () => TRPCRequestInfo['connectionParams'],
|
|
127
|
-
): Promise<
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
131
|
+
): Promise<ContextResult> {
|
|
132
|
+
try {
|
|
133
|
+
return await run(async (): Promise<ContextResult> => {
|
|
134
|
+
ctx = await createContext?.({
|
|
135
|
+
req,
|
|
136
|
+
res: client,
|
|
137
|
+
info: {
|
|
138
|
+
connectionParams: getConnectionParams(),
|
|
139
|
+
calls: [],
|
|
140
|
+
isBatchCall: false,
|
|
141
|
+
accept: null,
|
|
142
|
+
type: 'unknown',
|
|
143
|
+
signal: abortController.signal,
|
|
144
|
+
url: null,
|
|
145
|
+
},
|
|
146
|
+
});
|
|
142
147
|
|
|
143
|
-
|
|
144
|
-
|
|
148
|
+
return {
|
|
149
|
+
ok: true,
|
|
150
|
+
value: ctx,
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
} catch (cause) {
|
|
145
154
|
const error = getTRPCErrorFromUnknown(cause);
|
|
146
155
|
opts.onError?.({
|
|
147
156
|
error,
|
|
@@ -167,12 +176,14 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
|
167
176
|
(globalThis.setImmediate ?? globalThis.setTimeout)(() => {
|
|
168
177
|
client.close();
|
|
169
178
|
});
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
179
|
+
return {
|
|
180
|
+
ok: false,
|
|
181
|
+
error,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
173
184
|
}
|
|
174
185
|
|
|
175
|
-
let ctx:
|
|
186
|
+
let ctx: Context | undefined = undefined;
|
|
176
187
|
|
|
177
188
|
/**
|
|
178
189
|
* promise for initializing the context
|
|
@@ -182,18 +193,40 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
|
182
193
|
*/
|
|
183
194
|
let ctxPromise =
|
|
184
195
|
createURL(req).searchParams.get('connectionParams') === '1'
|
|
185
|
-
?
|
|
196
|
+
? null
|
|
186
197
|
: createCtxPromise(() => null);
|
|
187
198
|
|
|
188
|
-
|
|
199
|
+
function handleRequest(msg: TRPCClientOutgoingMessage) {
|
|
189
200
|
const { id, jsonrpc } = msg;
|
|
190
201
|
|
|
191
|
-
/* istanbul ignore next -- @preserve */
|
|
192
202
|
if (id === null) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
203
|
+
const error = getTRPCErrorFromUnknown(
|
|
204
|
+
new TRPCError({
|
|
205
|
+
code: 'PARSE_ERROR',
|
|
206
|
+
message: '`id` is required',
|
|
207
|
+
}),
|
|
208
|
+
);
|
|
209
|
+
opts.onError?.({
|
|
210
|
+
error,
|
|
211
|
+
path: undefined,
|
|
212
|
+
type: 'unknown',
|
|
213
|
+
ctx,
|
|
214
|
+
req,
|
|
215
|
+
input: undefined,
|
|
196
216
|
});
|
|
217
|
+
respond({
|
|
218
|
+
id,
|
|
219
|
+
jsonrpc,
|
|
220
|
+
error: getErrorShape({
|
|
221
|
+
config: router._def._config,
|
|
222
|
+
error,
|
|
223
|
+
type: 'unknown',
|
|
224
|
+
path: undefined,
|
|
225
|
+
input: undefined,
|
|
226
|
+
ctx,
|
|
227
|
+
}),
|
|
228
|
+
});
|
|
229
|
+
return;
|
|
197
230
|
}
|
|
198
231
|
if (msg.method === 'subscription.stop') {
|
|
199
232
|
clientSubscriptions.get(id)?.abort();
|
|
@@ -202,20 +235,25 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
|
202
235
|
const { path, lastEventId } = msg.params;
|
|
203
236
|
let { input } = msg.params;
|
|
204
237
|
const type = msg.method;
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
238
|
+
|
|
239
|
+
if (lastEventId !== undefined) {
|
|
240
|
+
if (isObject(input)) {
|
|
241
|
+
input = {
|
|
242
|
+
...input,
|
|
243
|
+
lastEventId: lastEventId,
|
|
244
|
+
};
|
|
245
|
+
} else {
|
|
246
|
+
input ??= {
|
|
247
|
+
lastEventId: lastEventId,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
run(async () => {
|
|
252
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
253
|
+
const res = await ctxPromise!; // asserts context has been set
|
|
254
|
+
if (!res.ok) {
|
|
255
|
+
throw res.error;
|
|
217
256
|
}
|
|
218
|
-
await ctxPromise; // asserts context has been set
|
|
219
257
|
|
|
220
258
|
const abortController = new AbortController();
|
|
221
259
|
const result = await callTRPCProcedure({
|
|
@@ -384,7 +422,7 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
|
384
422
|
type: 'started',
|
|
385
423
|
},
|
|
386
424
|
});
|
|
387
|
-
}
|
|
425
|
+
}).catch((cause) => {
|
|
388
426
|
// procedure threw an error
|
|
389
427
|
const error = getTRPCErrorFromUnknown(cause);
|
|
390
428
|
opts.onError?.({ error, path, type, ctx, req, input });
|
|
@@ -400,9 +438,9 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
|
400
438
|
ctx,
|
|
401
439
|
}),
|
|
402
440
|
});
|
|
403
|
-
}
|
|
441
|
+
});
|
|
404
442
|
}
|
|
405
|
-
client.on('message',
|
|
443
|
+
client.on('message', (rawData) => {
|
|
406
444
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
407
445
|
const msgStr = rawData.toString();
|
|
408
446
|
if (msgStr === 'PONG') {
|
|
@@ -414,7 +452,7 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
|
414
452
|
}
|
|
415
453
|
return;
|
|
416
454
|
}
|
|
417
|
-
if (ctxPromise
|
|
455
|
+
if (!ctxPromise) {
|
|
418
456
|
// If the ctxPromise wasn't created immediately, we're expecting the first message to be a TRPCConnectionParamsMessage
|
|
419
457
|
ctxPromise = createCtxPromise(() => {
|
|
420
458
|
let msg;
|
|
@@ -438,31 +476,36 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
|
438
476
|
});
|
|
439
477
|
return;
|
|
440
478
|
}
|
|
441
|
-
try {
|
|
442
|
-
const msgJSON: unknown = JSON.parse(msgStr);
|
|
443
|
-
const msgs: unknown[] = Array.isArray(msgJSON) ? msgJSON : [msgJSON];
|
|
444
|
-
const promises = msgs
|
|
445
|
-
.map((raw) => parseTRPCMessage(raw, transformer))
|
|
446
|
-
.map(handleRequest);
|
|
447
|
-
await Promise.all(promises);
|
|
448
|
-
} catch (cause) {
|
|
449
|
-
const error = new TRPCError({
|
|
450
|
-
code: 'PARSE_ERROR',
|
|
451
|
-
cause,
|
|
452
|
-
});
|
|
453
479
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
480
|
+
const parsedMsgs = run(() => {
|
|
481
|
+
try {
|
|
482
|
+
const msgJSON: unknown = JSON.parse(msgStr);
|
|
483
|
+
const msgs: unknown[] = Array.isArray(msgJSON) ? msgJSON : [msgJSON];
|
|
484
|
+
|
|
485
|
+
return msgs.map((raw) => parseTRPCMessage(raw, transformer));
|
|
486
|
+
} catch (cause) {
|
|
487
|
+
const error = new TRPCError({
|
|
488
|
+
code: 'PARSE_ERROR',
|
|
489
|
+
cause,
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
respond({
|
|
493
|
+
id: null,
|
|
494
|
+
error: getErrorShape({
|
|
495
|
+
config: router._def._config,
|
|
496
|
+
error,
|
|
497
|
+
type: 'unknown',
|
|
498
|
+
path: undefined,
|
|
499
|
+
input: undefined,
|
|
500
|
+
ctx,
|
|
501
|
+
}),
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
return [];
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
parsedMsgs.map(handleRequest);
|
|
466
509
|
});
|
|
467
510
|
|
|
468
511
|
// WebSocket errors should be handled, as otherwise unhandled exceptions will crash Node.js.
|
|
@@ -487,10 +530,6 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
|
487
530
|
clientSubscriptions.clear();
|
|
488
531
|
abortController.abort();
|
|
489
532
|
});
|
|
490
|
-
|
|
491
|
-
if (ctxPromise !== unsetContextPromiseSymbol) {
|
|
492
|
-
await ctxPromise;
|
|
493
|
-
}
|
|
494
533
|
};
|
|
495
534
|
}
|
|
496
535
|
|
|
@@ -544,22 +583,7 @@ export function applyWSSHandler<TRouter extends AnyRouter>(
|
|
|
544
583
|
return;
|
|
545
584
|
}
|
|
546
585
|
|
|
547
|
-
onConnection(client, req)
|
|
548
|
-
opts.onError?.({
|
|
549
|
-
error: new TRPCError({
|
|
550
|
-
code: 'INTERNAL_SERVER_ERROR',
|
|
551
|
-
cause,
|
|
552
|
-
message: 'Failed to handle WebSocket connection',
|
|
553
|
-
}),
|
|
554
|
-
req: req,
|
|
555
|
-
path: undefined,
|
|
556
|
-
type: 'unknown',
|
|
557
|
-
ctx: undefined,
|
|
558
|
-
input: undefined,
|
|
559
|
-
});
|
|
560
|
-
|
|
561
|
-
client.close();
|
|
562
|
-
});
|
|
586
|
+
onConnection(client, req);
|
|
563
587
|
});
|
|
564
588
|
|
|
565
589
|
return {
|