@trpc/server 11.0.0-alpha-tmp-app-router-example.388 → 11.0.0-alpha-tmp-issues-5851-take-two.448
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/@trpc/server/http.d.ts +1 -2
- package/dist/@trpc/server/http.d.ts.map +1 -1
- package/dist/@trpc/server/index.d.ts +1 -1
- package/dist/@trpc/server/index.d.ts.map +1 -1
- package/dist/@trpc/server/rpc.d.ts +1 -1
- package/dist/@trpc/server/rpc.d.ts.map +1 -1
- package/dist/adapters/aws-lambda/getPlanner.d.ts.map +1 -1
- package/dist/adapters/aws-lambda/getPlanner.js +19 -2
- package/dist/adapters/aws-lambda/getPlanner.mjs +19 -2
- package/dist/adapters/next-app-dir/nextAppDirCaller.d.ts.map +1 -1
- package/dist/adapters/next-app-dir/nextAppDirCaller.js +1 -1
- package/dist/adapters/next-app-dir/nextAppDirCaller.mjs +1 -1
- package/dist/adapters/next-app-dir/redirect.d.ts.map +1 -1
- package/dist/adapters/next.js +1 -1
- package/dist/adapters/next.mjs +1 -1
- package/dist/adapters/node-http/incomingMessageToRequest.d.ts +0 -1
- package/dist/adapters/node-http/incomingMessageToRequest.d.ts.map +1 -1
- package/dist/adapters/node-http/incomingMessageToRequest.js +3 -1
- package/dist/adapters/node-http/incomingMessageToRequest.mjs +3 -1
- package/dist/adapters/node-http/nodeHTTPRequestHandler.d.ts.map +1 -1
- package/dist/adapters/node-http/nodeHTTPRequestHandler.js +30 -7
- package/dist/adapters/node-http/nodeHTTPRequestHandler.mjs +30 -7
- package/dist/adapters/node-http/types.d.ts +0 -1
- package/dist/adapters/node-http/types.d.ts.map +1 -1
- package/dist/adapters/standalone.d.ts +0 -1
- package/dist/adapters/standalone.d.ts.map +1 -1
- package/dist/adapters/ws.d.ts +3 -4
- package/dist/adapters/ws.d.ts.map +1 -1
- package/dist/adapters/ws.js +172 -114
- package/dist/adapters/ws.mjs +172 -114
- package/dist/bundle-analysis.json +236 -155
- package/dist/http.js +3 -0
- package/dist/http.mjs +1 -0
- package/dist/index.js +7 -5
- package/dist/index.mjs +3 -2
- package/dist/observable/observable.d.ts +1 -0
- package/dist/observable/observable.d.ts.map +1 -1
- package/dist/observable/observable.js +55 -0
- package/dist/observable/observable.mjs +55 -1
- package/dist/unstable-core-do-not-import/createProxy.d.ts +3 -3
- package/dist/unstable-core-do-not-import/createProxy.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/createProxy.js +15 -6
- package/dist/unstable-core-do-not-import/createProxy.mjs +15 -6
- package/dist/unstable-core-do-not-import/http/contentType.d.ts +7 -4
- package/dist/unstable-core-do-not-import/http/contentType.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/http/contentType.js +60 -17
- package/dist/unstable-core-do-not-import/http/contentType.mjs +61 -18
- package/dist/unstable-core-do-not-import/http/formDataToObject.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/http/formDataToObject.js +40 -0
- package/dist/unstable-core-do-not-import/http/formDataToObject.mjs +38 -0
- package/dist/unstable-core-do-not-import/http/getHTTPStatusCode.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/http/getHTTPStatusCode.js +4 -4
- package/dist/unstable-core-do-not-import/http/getHTTPStatusCode.mjs +4 -4
- package/dist/unstable-core-do-not-import/http/parseConnectionParams.d.ts +4 -0
- package/dist/unstable-core-do-not-import/http/parseConnectionParams.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/http/parseConnectionParams.js +42 -0
- package/dist/unstable-core-do-not-import/http/parseConnectionParams.mjs +39 -0
- package/dist/unstable-core-do-not-import/http/resolveResponse.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/http/resolveResponse.js +302 -149
- package/dist/unstable-core-do-not-import/http/resolveResponse.mjs +301 -148
- package/dist/unstable-core-do-not-import/http/types.d.ts +26 -2
- package/dist/unstable-core-do-not-import/http/types.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/initTRPC.d.ts +12 -12
- package/dist/unstable-core-do-not-import/initTRPC.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/middleware.d.ts +3 -3
- package/dist/unstable-core-do-not-import/middleware.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/procedureBuilder.d.ts +3 -1
- package/dist/unstable-core-do-not-import/procedureBuilder.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/rootConfig.d.ts +12 -0
- package/dist/unstable-core-do-not-import/rootConfig.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/router.d.ts +2 -2
- package/dist/unstable-core-do-not-import/router.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/router.js +7 -2
- package/dist/unstable-core-do-not-import/router.mjs +7 -2
- package/dist/unstable-core-do-not-import/rpc/envelopes.d.ts +7 -0
- package/dist/unstable-core-do-not-import/rpc/envelopes.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/rpc/index.d.ts +1 -1
- package/dist/unstable-core-do-not-import/rpc/index.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/stream/{stream.d.ts → jsonl.d.ts} +5 -5
- package/dist/unstable-core-do-not-import/stream/jsonl.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/stream/{stream.js → jsonl.js} +148 -111
- package/dist/unstable-core-do-not-import/stream/{stream.mjs → jsonl.mjs} +147 -110
- package/dist/unstable-core-do-not-import/stream/sse.d.ts +86 -0
- package/dist/unstable-core-do-not-import/stream/sse.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/stream/sse.js +178 -0
- package/dist/unstable-core-do-not-import/stream/sse.mjs +172 -0
- package/dist/unstable-core-do-not-import/stream/utils/createDeferred.d.ts +18 -0
- package/dist/unstable-core-do-not-import/stream/utils/createDeferred.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/stream/utils/createDeferred.js +46 -0
- package/dist/unstable-core-do-not-import/stream/utils/createDeferred.mjs +43 -0
- package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.d.ts +10 -0
- package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.js +31 -0
- package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.mjs +29 -0
- package/dist/unstable-core-do-not-import/stream/utils/createServer.d.ts +7 -0
- package/dist/unstable-core-do-not-import/stream/utils/createServer.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/transformer.d.ts +5 -5
- package/dist/unstable-core-do-not-import/utils.d.ts +4 -0
- package/dist/unstable-core-do-not-import/utils.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/utils.js +4 -0
- package/dist/unstable-core-do-not-import/utils.mjs +4 -1
- package/dist/unstable-core-do-not-import.d.ts +5 -2
- package/dist/unstable-core-do-not-import.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import.js +19 -7
- package/dist/unstable-core-do-not-import.mjs +6 -3
- package/package.json +6 -6
- package/src/@trpc/server/http.ts +7 -2
- package/src/@trpc/server/index.ts +1 -0
- package/src/@trpc/server/rpc.ts +1 -0
- package/src/adapters/aws-lambda/getPlanner.ts +21 -2
- package/src/adapters/next-app-dir/nextAppDirCaller.ts +2 -1
- package/src/adapters/node-http/incomingMessageToRequest.ts +3 -2
- package/src/adapters/node-http/nodeHTTPRequestHandler.ts +32 -7
- package/src/adapters/ws.ts +193 -107
- package/src/observable/observable.ts +63 -0
- package/src/unstable-core-do-not-import/createProxy.ts +23 -8
- package/src/unstable-core-do-not-import/http/contentType.ts +83 -21
- package/src/{adapters/next-app-dir → unstable-core-do-not-import/http}/formDataToObject.ts +18 -10
- package/src/unstable-core-do-not-import/http/getHTTPStatusCode.ts +4 -7
- package/src/unstable-core-do-not-import/http/parseConnectionParams.ts +49 -0
- package/src/unstable-core-do-not-import/http/resolveResponse.ts +333 -164
- package/src/unstable-core-do-not-import/http/types.ts +31 -2
- package/src/unstable-core-do-not-import/procedureBuilder.ts +8 -1
- package/src/unstable-core-do-not-import/rootConfig.ts +12 -0
- package/src/unstable-core-do-not-import/router.ts +47 -35
- package/src/unstable-core-do-not-import/rpc/envelopes.ts +9 -0
- package/src/unstable-core-do-not-import/rpc/index.ts +1 -0
- package/src/unstable-core-do-not-import/stream/{stream.ts → jsonl.ts} +163 -110
- package/src/unstable-core-do-not-import/stream/sse.ts +288 -0
- package/src/unstable-core-do-not-import/stream/utils/createDeferred.ts +48 -0
- package/src/unstable-core-do-not-import/stream/utils/createReadableStream.ts +31 -0
- package/src/unstable-core-do-not-import/stream/utils/createServer.ts +44 -0
- package/src/unstable-core-do-not-import/utils.ts +5 -0
- package/src/unstable-core-do-not-import.ts +5 -2
- package/dist/adapters/next-app-dir/formDataToObject.d.ts.map +0 -1
- package/dist/adapters/next-app-dir/formDataToObject.js +0 -34
- package/dist/adapters/next-app-dir/formDataToObject.mjs +0 -32
- package/dist/unstable-core-do-not-import/stream/stream.d.ts.map +0 -1
- /package/dist/{adapters/next-app-dir → unstable-core-do-not-import/http}/formDataToObject.d.ts +0 -0
package/src/adapters/ws.ts
CHANGED
|
@@ -12,19 +12,26 @@ import {
|
|
|
12
12
|
transformTRPCResponse,
|
|
13
13
|
TRPCError,
|
|
14
14
|
} from '../@trpc/server';
|
|
15
|
-
import type {
|
|
15
|
+
import type { TRPCRequestInfo } from '../@trpc/server/http';
|
|
16
|
+
import { toURL, type BaseHandlerOptions } from '../@trpc/server/http';
|
|
16
17
|
import { parseTRPCMessage } from '../@trpc/server/rpc';
|
|
17
18
|
// @trpc/server/rpc
|
|
18
19
|
import type {
|
|
19
|
-
JSONRPC2,
|
|
20
20
|
TRPCClientOutgoingMessage,
|
|
21
|
+
TRPCConnectionParamsMessage,
|
|
21
22
|
TRPCReconnectNotification,
|
|
22
23
|
TRPCResponseMessage,
|
|
23
24
|
} from '../@trpc/server/rpc';
|
|
25
|
+
import { parseConnectionParamsFromUnknown } from '../http';
|
|
24
26
|
import { isObservable } from '../observable';
|
|
25
|
-
import
|
|
27
|
+
import { observableToAsyncIterable } from '../observable/observable';
|
|
26
28
|
// eslint-disable-next-line no-restricted-imports
|
|
27
|
-
import
|
|
29
|
+
import {
|
|
30
|
+
isAsyncIterable,
|
|
31
|
+
isObject,
|
|
32
|
+
run,
|
|
33
|
+
type MaybePromise,
|
|
34
|
+
} from '../unstable-core-do-not-import';
|
|
28
35
|
import type { NodeHTTPCreateContextFnOptions } from './node-http';
|
|
29
36
|
|
|
30
37
|
/**
|
|
@@ -36,9 +43,9 @@ const WEBSOCKET_OPEN = 1; /* ws.WebSocket.OPEN */
|
|
|
36
43
|
/**
|
|
37
44
|
* @public
|
|
38
45
|
*/
|
|
39
|
-
export type CreateWSSContextFnOptions =
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
export type CreateWSSContextFnOptions = NodeHTTPCreateContextFnOptions<
|
|
47
|
+
IncomingMessage,
|
|
48
|
+
ws.WebSocket
|
|
42
49
|
>;
|
|
43
50
|
|
|
44
51
|
/**
|
|
@@ -81,6 +88,7 @@ export type WSSHandlerOptions<TRouter extends AnyRouter> =
|
|
|
81
88
|
};
|
|
82
89
|
};
|
|
83
90
|
|
|
91
|
+
const unsetContextSymbol = Symbol('unsetContext');
|
|
84
92
|
export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
85
93
|
opts: WSConnectionHandlerOptions<TRouter>,
|
|
86
94
|
) {
|
|
@@ -88,7 +96,7 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
|
88
96
|
const { transformer } = router._def._config;
|
|
89
97
|
|
|
90
98
|
return async (client: ws.WebSocket, req: IncomingMessage) => {
|
|
91
|
-
const clientSubscriptions = new Map<number | string,
|
|
99
|
+
const clientSubscriptions = new Map<number | string, AbortController>();
|
|
92
100
|
|
|
93
101
|
function respond(untransformedJSON: TRPCResponseMessage) {
|
|
94
102
|
client.send(
|
|
@@ -98,22 +106,65 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
|
98
106
|
);
|
|
99
107
|
}
|
|
100
108
|
|
|
101
|
-
function
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
109
|
+
function createCtxPromise(
|
|
110
|
+
getConnectionParams: () => TRPCRequestInfo['connectionParams'],
|
|
111
|
+
): Promise<inferRouterContext<TRouter>> {
|
|
112
|
+
return run(async () => {
|
|
113
|
+
ctx = await createContext?.({
|
|
114
|
+
req,
|
|
115
|
+
res: client,
|
|
116
|
+
info: {
|
|
117
|
+
connectionParams: getConnectionParams(),
|
|
118
|
+
calls: [],
|
|
119
|
+
isBatchCall: false,
|
|
120
|
+
accept: null,
|
|
121
|
+
type: 'unknown',
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
return ctx;
|
|
126
|
+
}).catch((cause) => {
|
|
127
|
+
const error = getTRPCErrorFromUnknown(cause);
|
|
128
|
+
opts.onError?.({
|
|
129
|
+
error,
|
|
130
|
+
path: undefined,
|
|
131
|
+
type: 'unknown',
|
|
132
|
+
ctx,
|
|
133
|
+
req,
|
|
134
|
+
input: undefined,
|
|
135
|
+
});
|
|
136
|
+
respond({
|
|
137
|
+
id: null,
|
|
138
|
+
error: getErrorShape({
|
|
139
|
+
config: router._def._config,
|
|
140
|
+
error,
|
|
141
|
+
type: 'unknown',
|
|
142
|
+
path: undefined,
|
|
143
|
+
input: undefined,
|
|
144
|
+
ctx,
|
|
145
|
+
}),
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// close in next tick
|
|
149
|
+
(global.setImmediate ?? global.setTimeout)(() => {
|
|
150
|
+
client.close();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
throw error;
|
|
113
154
|
});
|
|
114
155
|
}
|
|
115
156
|
|
|
116
|
-
|
|
157
|
+
/**
|
|
158
|
+
* promise for initializing the context
|
|
159
|
+
*
|
|
160
|
+
* - the context promise will be created immediately on connection if no connectionParams are expected
|
|
161
|
+
* - if connection params are expected, they will be created once received
|
|
162
|
+
*/
|
|
163
|
+
let ctxPromise =
|
|
164
|
+
toURL(req.url ?? '').searchParams.get('connectionParams') === '1'
|
|
165
|
+
? unsetContextSymbol
|
|
166
|
+
: createCtxPromise(() => null);
|
|
167
|
+
|
|
117
168
|
let ctx: inferRouterContext<TRouter> | undefined = undefined;
|
|
118
169
|
|
|
119
170
|
async function handleRequest(msg: TRPCClientOutgoingMessage) {
|
|
@@ -126,11 +177,7 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
|
126
177
|
});
|
|
127
178
|
}
|
|
128
179
|
if (msg.method === 'subscription.stop') {
|
|
129
|
-
|
|
130
|
-
if (sub) {
|
|
131
|
-
stopSubscription(sub, { id, jsonrpc });
|
|
132
|
-
}
|
|
133
|
-
clientSubscriptions.delete(id);
|
|
180
|
+
clientSubscriptions.get(id)?.abort();
|
|
134
181
|
return;
|
|
135
182
|
}
|
|
136
183
|
const { path, input } = msg.params;
|
|
@@ -146,14 +193,7 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
|
146
193
|
type,
|
|
147
194
|
});
|
|
148
195
|
|
|
149
|
-
if (type
|
|
150
|
-
if (!isObservable(result)) {
|
|
151
|
-
throw new TRPCError({
|
|
152
|
-
message: `Subscription ${path} did not return an observable`,
|
|
153
|
-
code: 'INTERNAL_SERVER_ERROR',
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
} else {
|
|
196
|
+
if (type !== 'subscription') {
|
|
157
197
|
// send the value as data if the method is not a subscription
|
|
158
198
|
respond({
|
|
159
199
|
id,
|
|
@@ -166,62 +206,112 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
|
166
206
|
return;
|
|
167
207
|
}
|
|
168
208
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
type: 'data',
|
|
177
|
-
data,
|
|
178
|
-
},
|
|
179
|
-
});
|
|
180
|
-
},
|
|
181
|
-
error(err) {
|
|
182
|
-
const error = getTRPCErrorFromUnknown(err);
|
|
183
|
-
opts.onError?.({ error, path, type, ctx, req, input });
|
|
184
|
-
respond({
|
|
185
|
-
id,
|
|
186
|
-
jsonrpc,
|
|
187
|
-
error: getErrorShape({
|
|
188
|
-
config: router._def._config,
|
|
189
|
-
error,
|
|
190
|
-
type,
|
|
191
|
-
path,
|
|
192
|
-
input,
|
|
193
|
-
ctx,
|
|
194
|
-
}),
|
|
195
|
-
});
|
|
196
|
-
},
|
|
197
|
-
complete() {
|
|
198
|
-
respond({
|
|
199
|
-
id,
|
|
200
|
-
jsonrpc,
|
|
201
|
-
result: {
|
|
202
|
-
type: 'stopped',
|
|
203
|
-
},
|
|
204
|
-
});
|
|
205
|
-
},
|
|
206
|
-
});
|
|
209
|
+
if (!isObservable(result) && !isAsyncIterable(result)) {
|
|
210
|
+
throw new TRPCError({
|
|
211
|
+
message: `Subscription ${path} did not return an observable or a AsyncGenerator`,
|
|
212
|
+
code: 'INTERNAL_SERVER_ERROR',
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
207
216
|
/* istanbul ignore next -- @preserve */
|
|
208
217
|
if (client.readyState !== WEBSOCKET_OPEN) {
|
|
209
218
|
// if the client got disconnected whilst initializing the subscription
|
|
210
219
|
// no need to send stopped message if the client is disconnected
|
|
211
|
-
|
|
220
|
+
|
|
212
221
|
return;
|
|
213
222
|
}
|
|
214
223
|
|
|
215
224
|
/* istanbul ignore next -- @preserve */
|
|
216
225
|
if (clientSubscriptions.has(id)) {
|
|
217
226
|
// duplicate request ids for client
|
|
218
|
-
|
|
227
|
+
|
|
219
228
|
throw new TRPCError({
|
|
220
229
|
message: `Duplicate id ${id}`,
|
|
221
230
|
code: 'BAD_REQUEST',
|
|
222
231
|
});
|
|
223
232
|
}
|
|
224
|
-
|
|
233
|
+
|
|
234
|
+
const iterable = isObservable(result)
|
|
235
|
+
? observableToAsyncIterable(result)
|
|
236
|
+
: result;
|
|
237
|
+
|
|
238
|
+
const iterator: AsyncIterator<unknown> =
|
|
239
|
+
iterable[Symbol.asyncIterator]();
|
|
240
|
+
const abortController = new AbortController();
|
|
241
|
+
|
|
242
|
+
const abortPromise = new Promise<'abort'>((resolve) => {
|
|
243
|
+
abortController.signal.onabort = () => resolve('abort');
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
run(async () => {
|
|
247
|
+
while (true) {
|
|
248
|
+
const next = await Promise.race([
|
|
249
|
+
iterator.next().catch(getTRPCErrorFromUnknown),
|
|
250
|
+
abortPromise,
|
|
251
|
+
]);
|
|
252
|
+
|
|
253
|
+
if (next === 'abort') {
|
|
254
|
+
await iterator.return?.();
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
if (next instanceof Error) {
|
|
258
|
+
const error = getTRPCErrorFromUnknown(next);
|
|
259
|
+
opts.onError?.({ error, path, type, ctx, req, input });
|
|
260
|
+
respond({
|
|
261
|
+
id,
|
|
262
|
+
jsonrpc,
|
|
263
|
+
error: getErrorShape({
|
|
264
|
+
config: router._def._config,
|
|
265
|
+
error,
|
|
266
|
+
type,
|
|
267
|
+
path,
|
|
268
|
+
input,
|
|
269
|
+
ctx,
|
|
270
|
+
}),
|
|
271
|
+
});
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
if (next.done) {
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
respond({
|
|
279
|
+
id,
|
|
280
|
+
jsonrpc,
|
|
281
|
+
result: {
|
|
282
|
+
type: 'data',
|
|
283
|
+
data: next.value,
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
await iterator.return?.();
|
|
289
|
+
respond({
|
|
290
|
+
id,
|
|
291
|
+
jsonrpc,
|
|
292
|
+
result: {
|
|
293
|
+
type: 'stopped',
|
|
294
|
+
},
|
|
295
|
+
});
|
|
296
|
+
clientSubscriptions.delete(id);
|
|
297
|
+
}).catch((cause) => {
|
|
298
|
+
const error = getTRPCErrorFromUnknown(cause);
|
|
299
|
+
opts.onError?.({ error, path, type, ctx, req, input });
|
|
300
|
+
respond({
|
|
301
|
+
id,
|
|
302
|
+
jsonrpc,
|
|
303
|
+
error: getErrorShape({
|
|
304
|
+
config: router._def._config,
|
|
305
|
+
error,
|
|
306
|
+
type,
|
|
307
|
+
path,
|
|
308
|
+
input,
|
|
309
|
+
ctx,
|
|
310
|
+
}),
|
|
311
|
+
});
|
|
312
|
+
abortController.abort();
|
|
313
|
+
});
|
|
314
|
+
clientSubscriptions.set(id, abortController);
|
|
225
315
|
|
|
226
316
|
respond({
|
|
227
317
|
id,
|
|
@@ -249,8 +339,31 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
|
249
339
|
}
|
|
250
340
|
}
|
|
251
341
|
client.on('message', async (message) => {
|
|
342
|
+
if (ctxPromise === unsetContextSymbol) {
|
|
343
|
+
// If the ctxPromise wasn't created immediately, we're expecting the first message to be a TRPCConnectionParamsMessage
|
|
344
|
+
ctxPromise = createCtxPromise(() => {
|
|
345
|
+
let msg;
|
|
346
|
+
try {
|
|
347
|
+
msg = JSON.parse(message.toString()) as TRPCConnectionParamsMessage;
|
|
348
|
+
|
|
349
|
+
if (!isObject(msg)) {
|
|
350
|
+
throw new Error('Message was not an object');
|
|
351
|
+
}
|
|
352
|
+
} catch (cause) {
|
|
353
|
+
throw new TRPCError({
|
|
354
|
+
code: 'PARSE_ERROR',
|
|
355
|
+
message: `Malformed TRPCConnectionParamsMessage`,
|
|
356
|
+
cause,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const connectionParams = parseConnectionParamsFromUnknown(msg.data);
|
|
361
|
+
|
|
362
|
+
return connectionParams;
|
|
363
|
+
});
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
252
366
|
try {
|
|
253
|
-
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
254
367
|
const msgJSON: unknown = JSON.parse(message.toString());
|
|
255
368
|
const msgs: unknown[] = Array.isArray(msgJSON) ? msgJSON : [msgJSON];
|
|
256
369
|
const promises = msgs
|
|
@@ -294,42 +407,15 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
|
|
|
294
407
|
|
|
295
408
|
client.once('close', () => {
|
|
296
409
|
for (const sub of clientSubscriptions.values()) {
|
|
297
|
-
sub.
|
|
410
|
+
sub.abort();
|
|
298
411
|
}
|
|
299
412
|
clientSubscriptions.clear();
|
|
300
413
|
});
|
|
301
|
-
async function createContextAsync() {
|
|
302
|
-
try {
|
|
303
|
-
ctx = await ctxPromise;
|
|
304
|
-
} catch (cause) {
|
|
305
|
-
const error = getTRPCErrorFromUnknown(cause);
|
|
306
|
-
opts.onError?.({
|
|
307
|
-
error,
|
|
308
|
-
path: undefined,
|
|
309
|
-
type: 'unknown',
|
|
310
|
-
ctx,
|
|
311
|
-
req,
|
|
312
|
-
input: undefined,
|
|
313
|
-
});
|
|
314
|
-
respond({
|
|
315
|
-
id: null,
|
|
316
|
-
error: getErrorShape({
|
|
317
|
-
config: router._def._config,
|
|
318
|
-
error,
|
|
319
|
-
type: 'unknown',
|
|
320
|
-
path: undefined,
|
|
321
|
-
input: undefined,
|
|
322
|
-
ctx,
|
|
323
|
-
}),
|
|
324
|
-
});
|
|
325
414
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
});
|
|
330
|
-
}
|
|
415
|
+
if (ctxPromise !== unsetContextSymbol) {
|
|
416
|
+
// prevent unhandled promise rejection errors
|
|
417
|
+
await ctxPromise.catch(() => null);
|
|
331
418
|
}
|
|
332
|
-
await createContextAsync();
|
|
333
419
|
};
|
|
334
420
|
}
|
|
335
421
|
|
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
OperatorFunction,
|
|
5
5
|
TeardownLogic,
|
|
6
6
|
UnaryFunction,
|
|
7
|
+
Unsubscribable,
|
|
7
8
|
} from './types';
|
|
8
9
|
|
|
9
10
|
/** @public */
|
|
@@ -136,3 +137,65 @@ export function observableToPromise<TValue>(
|
|
|
136
137
|
abort: abort!,
|
|
137
138
|
};
|
|
138
139
|
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* @internal
|
|
143
|
+
*/
|
|
144
|
+
function observableToReadableStream<TValue>(
|
|
145
|
+
observable: Observable<TValue, unknown>,
|
|
146
|
+
): ReadableStream<TValue> {
|
|
147
|
+
let unsub: Unsubscribable | null = null;
|
|
148
|
+
return new ReadableStream<TValue>({
|
|
149
|
+
start(controller) {
|
|
150
|
+
unsub = observable.subscribe({
|
|
151
|
+
next(data) {
|
|
152
|
+
controller.enqueue(data);
|
|
153
|
+
},
|
|
154
|
+
error(err) {
|
|
155
|
+
controller.error(err);
|
|
156
|
+
},
|
|
157
|
+
complete() {
|
|
158
|
+
controller.close();
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
},
|
|
162
|
+
cancel() {
|
|
163
|
+
unsub?.unsubscribe();
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function observableToAsyncIterable<TValue>(
|
|
169
|
+
observable: Observable<TValue, unknown>,
|
|
170
|
+
): AsyncIterable<TValue> {
|
|
171
|
+
const stream = observableToReadableStream(observable);
|
|
172
|
+
|
|
173
|
+
const reader = stream.getReader();
|
|
174
|
+
const iterator: AsyncIterator<TValue> = {
|
|
175
|
+
async next() {
|
|
176
|
+
const value = await reader.read();
|
|
177
|
+
if (value.done) {
|
|
178
|
+
return {
|
|
179
|
+
value: undefined,
|
|
180
|
+
done: true,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
value: value.value,
|
|
185
|
+
done: false,
|
|
186
|
+
};
|
|
187
|
+
},
|
|
188
|
+
async return() {
|
|
189
|
+
await reader.cancel();
|
|
190
|
+
return {
|
|
191
|
+
value: undefined,
|
|
192
|
+
done: true,
|
|
193
|
+
};
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
return {
|
|
197
|
+
[Symbol.asyncIterator]() {
|
|
198
|
+
return iterator;
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
interface ProxyCallbackOptions {
|
|
2
|
-
path: string[];
|
|
3
|
-
args: unknown[];
|
|
2
|
+
path: readonly string[];
|
|
3
|
+
args: readonly unknown[];
|
|
4
4
|
}
|
|
5
5
|
type ProxyCallback = (opts: ProxyCallbackOptions) => unknown;
|
|
6
6
|
|
|
@@ -8,15 +8,27 @@ const noop = () => {
|
|
|
8
8
|
// noop
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
const freezeIfAvailable = (obj: object) => {
|
|
12
|
+
if (Object.freeze) {
|
|
13
|
+
Object.freeze(obj);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function createInnerProxy(
|
|
18
|
+
callback: ProxyCallback,
|
|
19
|
+
path: readonly string[],
|
|
20
|
+
memo: Record<string, unknown>,
|
|
21
|
+
) {
|
|
22
|
+
const cacheKey = path.join('.');
|
|
23
|
+
|
|
24
|
+
memo[cacheKey] ??= new Proxy(noop, {
|
|
13
25
|
get(_obj, key) {
|
|
14
26
|
if (typeof key !== 'string' || key === 'then') {
|
|
15
27
|
// special case for if the proxy is accidentally treated
|
|
16
28
|
// like a PromiseLike (like in `Promise.resolve(proxy)`)
|
|
17
29
|
return undefined;
|
|
18
30
|
}
|
|
19
|
-
return createInnerProxy(callback, [...path, key]);
|
|
31
|
+
return createInnerProxy(callback, [...path, key], memo);
|
|
20
32
|
},
|
|
21
33
|
apply(_1, _2, args) {
|
|
22
34
|
const lastOfPath = path[path.length - 1];
|
|
@@ -34,11 +46,13 @@ function createInnerProxy(callback: ProxyCallback, path: string[]) {
|
|
|
34
46
|
path: path.slice(0, -1),
|
|
35
47
|
};
|
|
36
48
|
}
|
|
49
|
+
freezeIfAvailable(opts.args);
|
|
50
|
+
freezeIfAvailable(opts.path);
|
|
37
51
|
return callback(opts);
|
|
38
52
|
},
|
|
39
53
|
});
|
|
40
54
|
|
|
41
|
-
return
|
|
55
|
+
return memo[cacheKey];
|
|
42
56
|
}
|
|
43
57
|
|
|
44
58
|
/**
|
|
@@ -46,8 +60,9 @@ function createInnerProxy(callback: ProxyCallback, path: string[]) {
|
|
|
46
60
|
*
|
|
47
61
|
* @internal
|
|
48
62
|
*/
|
|
49
|
-
export const createRecursiveProxy =
|
|
50
|
-
|
|
63
|
+
export const createRecursiveProxy = <TFaux = unknown>(
|
|
64
|
+
callback: ProxyCallback,
|
|
65
|
+
): TFaux => createInnerProxy(callback, [], Object.create(null)) as TFaux;
|
|
51
66
|
|
|
52
67
|
/**
|
|
53
68
|
* Used in place of `new Proxy` where each handler will map 1 level deep to another value.
|