@trpc/server 11.0.0-rc.630 → 11.0.0-rc.633
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 -1
- package/dist/@trpc/server/http.d.ts.map +1 -1
- package/dist/adapters/aws-lambda/index.js +1 -0
- package/dist/adapters/aws-lambda/index.mjs +1 -0
- package/dist/adapters/express.js +1 -0
- package/dist/adapters/express.mjs +1 -0
- package/dist/adapters/fastify/fastifyRequestHandler.js +2 -1
- package/dist/adapters/fastify/fastifyRequestHandler.mjs +2 -1
- package/dist/adapters/fetch/fetchRequestHandler.js +1 -0
- package/dist/adapters/fetch/fetchRequestHandler.mjs +1 -0
- package/dist/adapters/next-app-dir/nextAppDirCaller.js +1 -0
- package/dist/adapters/next-app-dir/nextAppDirCaller.mjs +1 -0
- package/dist/adapters/next-app-dir/notFound.js +1 -0
- package/dist/adapters/next-app-dir/notFound.mjs +1 -0
- package/dist/adapters/next-app-dir/redirect.js +1 -0
- package/dist/adapters/next-app-dir/redirect.mjs +1 -0
- package/dist/adapters/next.js +1 -0
- package/dist/adapters/next.mjs +1 -0
- package/dist/adapters/node-http/incomingMessageToRequest.d.ts +1 -1
- package/dist/adapters/node-http/incomingMessageToRequest.d.ts.map +1 -1
- package/dist/adapters/node-http/incomingMessageToRequest.js +7 -5
- package/dist/adapters/node-http/incomingMessageToRequest.mjs +7 -5
- package/dist/adapters/node-http/nodeHTTPRequestHandler.d.ts.map +1 -1
- package/dist/adapters/node-http/nodeHTTPRequestHandler.js +9 -42
- package/dist/adapters/node-http/nodeHTTPRequestHandler.mjs +9 -42
- package/dist/adapters/node-http/writeResponse.d.ts +18 -0
- package/dist/adapters/node-http/writeResponse.d.ts.map +1 -0
- package/dist/adapters/node-http/writeResponse.js +80 -0
- package/dist/adapters/node-http/writeResponse.mjs +77 -0
- package/dist/adapters/standalone.js +1 -0
- package/dist/adapters/standalone.mjs +1 -0
- package/dist/adapters/ws.js +1 -0
- package/dist/adapters/ws.mjs +1 -0
- package/dist/bundle-analysis.json +195 -168
- package/dist/http.js +1 -2
- package/dist/http.mjs +1 -1
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/dist/rpc.js +1 -0
- package/dist/rpc.mjs +1 -0
- package/dist/shared.js +1 -0
- package/dist/shared.mjs +1 -0
- package/dist/unstable-core-do-not-import/http/isAbortError.d.ts +4 -0
- package/dist/unstable-core-do-not-import/http/isAbortError.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/http/isAbortError.js +9 -0
- package/dist/unstable-core-do-not-import/http/isAbortError.mjs +7 -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 +3 -3
- package/dist/unstable-core-do-not-import/http/resolveResponse.mjs +3 -3
- package/dist/unstable-core-do-not-import/initTRPC.js +2 -2
- package/dist/unstable-core-do-not-import/initTRPC.mjs +2 -2
- package/dist/unstable-core-do-not-import/rootConfig.d.ts +14 -14
- package/dist/unstable-core-do-not-import/rootConfig.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/rpc/envelopes.d.ts +7 -10
- package/dist/unstable-core-do-not-import/rpc/envelopes.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/stream/jsonl.d.ts +6 -9
- package/dist/unstable-core-do-not-import/stream/jsonl.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/stream/jsonl.js +75 -124
- package/dist/unstable-core-do-not-import/stream/jsonl.mjs +76 -125
- package/dist/unstable-core-do-not-import/stream/sse.d.ts +11 -1
- package/dist/unstable-core-do-not-import/stream/sse.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/stream/sse.js +154 -86
- package/dist/unstable-core-do-not-import/stream/sse.mjs +155 -87
- package/dist/unstable-core-do-not-import/stream/utils/asyncIterable.d.ts +10 -10
- package/dist/unstable-core-do-not-import/stream/utils/asyncIterable.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/stream/utils/asyncIterable.js +47 -34
- package/dist/unstable-core-do-not-import/stream/utils/asyncIterable.mjs +47 -34
- package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.d.ts +0 -4
- package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.js +0 -11
- package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.mjs +1 -11
- package/dist/unstable-core-do-not-import/stream/utils/disposablePromiseTimer.d.ts +6 -0
- package/dist/unstable-core-do-not-import/stream/utils/disposablePromiseTimer.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/stream/utils/disposablePromiseTimer.js +28 -0
- package/dist/unstable-core-do-not-import/stream/utils/disposablePromiseTimer.mjs +25 -0
- package/dist/unstable-core-do-not-import/stream/utils/withPing.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/stream/utils/withPing.js +17 -17
- package/dist/unstable-core-do-not-import/stream/utils/withPing.mjs +17 -17
- package/dist/unstable-core-do-not-import/stream/utils/withRefCount.d.ts +17 -0
- package/dist/unstable-core-do-not-import/stream/utils/withRefCount.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/stream/utils/withRefCount.js +59 -0
- package/dist/unstable-core-do-not-import/stream/utils/withRefCount.mjs +57 -0
- package/dist/unstable-core-do-not-import/transformer.d.ts +1 -4
- package/dist/unstable-core-do-not-import/transformer.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import.d.ts +2 -2
- package/dist/unstable-core-do-not-import.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import.js +2 -2
- package/dist/unstable-core-do-not-import.mjs +1 -1
- package/package.json +3 -3
- package/src/@trpc/server/http.ts +0 -1
- package/src/adapters/fastify/fastifyRequestHandler.ts +1 -1
- package/src/adapters/node-http/incomingMessageToRequest.ts +8 -4
- package/src/adapters/node-http/nodeHTTPRequestHandler.ts +8 -46
- package/src/adapters/node-http/writeResponse.ts +91 -0
- package/src/unstable-core-do-not-import/http/isAbortError.ts +7 -0
- package/src/unstable-core-do-not-import/http/resolveResponse.ts +3 -4
- package/src/unstable-core-do-not-import/initTRPC.ts +1 -1
- package/src/unstable-core-do-not-import/rootConfig.ts +17 -17
- package/src/unstable-core-do-not-import/rpc/envelopes.ts +7 -12
- package/src/unstable-core-do-not-import/stream/jsonl.ts +85 -154
- package/src/unstable-core-do-not-import/stream/sse.ts +179 -92
- package/src/unstable-core-do-not-import/stream/utils/asyncIterable.ts +58 -37
- package/src/unstable-core-do-not-import/stream/utils/createReadableStream.ts +0 -13
- package/src/unstable-core-do-not-import/stream/utils/disposablePromiseTimer.ts +27 -0
- package/src/unstable-core-do-not-import/stream/utils/withPing.ts +31 -19
- package/src/unstable-core-do-not-import/stream/utils/withRefCount.ts +93 -0
- package/src/unstable-core-do-not-import.ts +2 -2
- package/dist/unstable-core-do-not-import/http/batchStreamFormatter.d.ts +0 -24
- package/dist/unstable-core-do-not-import/http/batchStreamFormatter.d.ts.map +0 -1
- package/dist/unstable-core-do-not-import/http/batchStreamFormatter.js +0 -32
- package/dist/unstable-core-do-not-import/http/batchStreamFormatter.mjs +0 -30
- package/dist/unstable-core-do-not-import/stream/utils/promiseTimer.d.ts +0 -8
- package/dist/unstable-core-do-not-import/stream/utils/promiseTimer.d.ts.map +0 -1
- package/dist/unstable-core-do-not-import/stream/utils/promiseTimer.js +0 -38
- package/dist/unstable-core-do-not-import/stream/utils/promiseTimer.mjs +0 -36
- package/src/unstable-core-do-not-import/http/batchStreamFormatter.ts +0 -29
- package/src/unstable-core-do-not-import/stream/utils/promiseTimer.ts +0 -40
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var unpromise = require('../../vendor/unpromise/unpromise.js');
|
|
3
4
|
var TRPCError = require('../error/TRPCError.js');
|
|
5
|
+
var isAbortError = require('../http/isAbortError.js');
|
|
4
6
|
var utils = require('../utils.js');
|
|
5
7
|
var tracked = require('./tracked.js');
|
|
6
8
|
var asyncIterable = require('./utils/asyncIterable.js');
|
|
7
9
|
var createReadableStream = require('./utils/createReadableStream.js');
|
|
8
|
-
var promiseTimer = require('./utils/promiseTimer.js');
|
|
9
10
|
var withPing = require('./utils/withPing.js');
|
|
10
11
|
|
|
12
|
+
const PING_EVENT = 'ping';
|
|
11
13
|
const SERIALIZED_ERROR_EVENT = 'serialized-error';
|
|
12
14
|
/**
|
|
13
15
|
*
|
|
@@ -24,18 +26,18 @@ const SERIALIZED_ERROR_EVENT = 'serialized-error';
|
|
|
24
26
|
};
|
|
25
27
|
utils.run(async ()=>{
|
|
26
28
|
let iterable = opts.data;
|
|
27
|
-
iterable = asyncIterable.withCancel(iterable, stream.cancelledPromise);
|
|
28
29
|
if (opts.emitAndEndImmediately) {
|
|
29
30
|
iterable = asyncIterable.takeWithGrace(iterable, {
|
|
30
31
|
count: 1,
|
|
31
32
|
gracePeriodMs: 1,
|
|
32
|
-
|
|
33
|
+
abortCtrl: opts.abortCtrl
|
|
33
34
|
});
|
|
34
35
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
if (opts.maxDurationMs && opts.maxDurationMs > 0 && opts.maxDurationMs !== Infinity) {
|
|
37
|
+
iterable = asyncIterable.withMaxDuration(iterable, {
|
|
38
|
+
maxDurationMs: opts.maxDurationMs,
|
|
39
|
+
abortCtrl: opts.abortCtrl
|
|
40
|
+
});
|
|
39
41
|
}
|
|
40
42
|
if (ping.enabled && ping.intervalMs !== Infinity && ping.intervalMs > 0) {
|
|
41
43
|
iterable = withPing.withPing(iterable, ping.intervalMs);
|
|
@@ -48,7 +50,8 @@ const SERIALIZED_ERROR_EVENT = 'serialized-error';
|
|
|
48
50
|
for await (value of iterable){
|
|
49
51
|
if (value === withPing.PING_SYM) {
|
|
50
52
|
stream.controller.enqueue({
|
|
51
|
-
|
|
53
|
+
event: PING_EVENT,
|
|
54
|
+
data: ''
|
|
52
55
|
});
|
|
53
56
|
continue;
|
|
54
57
|
}
|
|
@@ -67,22 +70,26 @@ const SERIALIZED_ERROR_EVENT = 'serialized-error';
|
|
|
67
70
|
chunk = null;
|
|
68
71
|
}
|
|
69
72
|
} catch (err) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// So, a user error in any case.
|
|
74
|
-
const error = TRPCError.getTRPCErrorFromUnknown(err);
|
|
75
|
-
const data = opts.formatError?.({
|
|
76
|
-
error
|
|
77
|
-
}) ?? null;
|
|
78
|
-
stream.controller.enqueue({
|
|
79
|
-
event: SERIALIZED_ERROR_EVENT,
|
|
80
|
-
data: JSON.stringify(serialize(data))
|
|
81
|
-
});
|
|
73
|
+
if (isAbortError.isAbortError(err)) {
|
|
74
|
+
// ignore abort errors, send any other errors
|
|
75
|
+
return;
|
|
82
76
|
}
|
|
77
|
+
// `err` must be caused by `opts.data`, `JSON.stringify` or `serialize`.
|
|
78
|
+
// So, a user error in any case.
|
|
79
|
+
const error = TRPCError.getTRPCErrorFromUnknown(err);
|
|
80
|
+
const data = opts.formatError?.({
|
|
81
|
+
error
|
|
82
|
+
}) ?? null;
|
|
83
|
+
stream.controller.enqueue({
|
|
84
|
+
event: SERIALIZED_ERROR_EVENT,
|
|
85
|
+
data: JSON.stringify(serialize(data))
|
|
86
|
+
});
|
|
83
87
|
} finally{
|
|
84
|
-
|
|
85
|
-
|
|
88
|
+
try {
|
|
89
|
+
stream.controller.close();
|
|
90
|
+
} catch {
|
|
91
|
+
// ignore
|
|
92
|
+
}
|
|
86
93
|
}
|
|
87
94
|
}).catch((err)=>{
|
|
88
95
|
// should not be reached; just in case...
|
|
@@ -106,97 +113,158 @@ const SERIALIZED_ERROR_EVENT = 'serialized-error';
|
|
|
106
113
|
}
|
|
107
114
|
}));
|
|
108
115
|
}
|
|
116
|
+
async function withTimeout(opts) {
|
|
117
|
+
let timeoutId;
|
|
118
|
+
const timeoutPromise = new Promise((resolve)=>{
|
|
119
|
+
timeoutId = setTimeout(()=>{
|
|
120
|
+
resolve(null);
|
|
121
|
+
}, opts.timeoutMs);
|
|
122
|
+
});
|
|
123
|
+
let res;
|
|
124
|
+
try {
|
|
125
|
+
res = await unpromise.Unpromise.race([
|
|
126
|
+
opts.promise,
|
|
127
|
+
timeoutPromise
|
|
128
|
+
]);
|
|
129
|
+
} finally{
|
|
130
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
131
|
+
clearTimeout(timeoutId);
|
|
132
|
+
}
|
|
133
|
+
if (res === null) {
|
|
134
|
+
return await opts.onTimeout();
|
|
135
|
+
}
|
|
136
|
+
return res;
|
|
137
|
+
}
|
|
109
138
|
/**
|
|
110
139
|
* @see https://html.spec.whatwg.org/multipage/server-sent-events.html
|
|
111
140
|
*/ function sseStreamConsumer(opts) {
|
|
112
141
|
const { deserialize = (v)=>v } = opts;
|
|
113
142
|
const signal = opts.signal;
|
|
114
143
|
let _es = null;
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
controller.enqueue({
|
|
123
|
-
type: 'connecting',
|
|
124
|
-
eventSource: _es,
|
|
125
|
-
event: null
|
|
126
|
-
});
|
|
127
|
-
eventSource.addEventListener('open', ()=>{
|
|
144
|
+
const createStream = ()=>new ReadableStream({
|
|
145
|
+
async start (controller) {
|
|
146
|
+
const [url, init] = await Promise.all([
|
|
147
|
+
opts.url(),
|
|
148
|
+
opts.init()
|
|
149
|
+
]);
|
|
150
|
+
const eventSource = _es = new opts.EventSource(url, init);
|
|
128
151
|
controller.enqueue({
|
|
129
|
-
type: '
|
|
130
|
-
eventSource
|
|
152
|
+
type: 'connecting',
|
|
153
|
+
eventSource: _es,
|
|
154
|
+
event: null
|
|
131
155
|
});
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
error: deserialize(JSON.parse(msg.data)),
|
|
138
|
-
eventSource
|
|
156
|
+
eventSource.addEventListener('open', ()=>{
|
|
157
|
+
controller.enqueue({
|
|
158
|
+
type: 'opened',
|
|
159
|
+
eventSource
|
|
160
|
+
});
|
|
139
161
|
});
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (eventSource.readyState === EventSource.CLOSED) {
|
|
143
|
-
controller.error(event);
|
|
144
|
-
} else {
|
|
162
|
+
eventSource.addEventListener(SERIALIZED_ERROR_EVENT, (_msg)=>{
|
|
163
|
+
const msg = _msg;
|
|
145
164
|
controller.enqueue({
|
|
146
|
-
type: '
|
|
147
|
-
|
|
148
|
-
|
|
165
|
+
type: 'serialized-error',
|
|
166
|
+
error: deserialize(JSON.parse(msg.data)),
|
|
167
|
+
eventSource
|
|
149
168
|
});
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
169
|
+
});
|
|
170
|
+
eventSource.addEventListener(PING_EVENT, ()=>{
|
|
171
|
+
controller.enqueue({
|
|
172
|
+
type: 'ping',
|
|
173
|
+
eventSource
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
eventSource.addEventListener('error', (event)=>{
|
|
177
|
+
if (eventSource.readyState === EventSource.CLOSED) {
|
|
178
|
+
controller.error(event);
|
|
179
|
+
} else {
|
|
180
|
+
controller.enqueue({
|
|
181
|
+
type: 'connecting',
|
|
182
|
+
eventSource,
|
|
183
|
+
event
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
eventSource.addEventListener('message', (_msg)=>{
|
|
188
|
+
const msg = _msg;
|
|
189
|
+
const chunk = deserialize(JSON.parse(msg.data));
|
|
190
|
+
const def = {
|
|
191
|
+
data: chunk
|
|
192
|
+
};
|
|
193
|
+
if (msg.lastEventId) {
|
|
194
|
+
def.id = msg.lastEventId;
|
|
195
|
+
}
|
|
196
|
+
controller.enqueue({
|
|
197
|
+
type: 'data',
|
|
198
|
+
data: def,
|
|
199
|
+
eventSource
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
const onAbort = ()=>{
|
|
203
|
+
controller.close();
|
|
204
|
+
eventSource.close();
|
|
157
205
|
};
|
|
158
|
-
if (
|
|
159
|
-
|
|
206
|
+
if (signal.aborted) {
|
|
207
|
+
onAbort();
|
|
208
|
+
} else {
|
|
209
|
+
signal.addEventListener('abort', onAbort);
|
|
160
210
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
eventSource
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
const onAbort = ()=>{
|
|
168
|
-
controller.close();
|
|
169
|
-
eventSource.close();
|
|
170
|
-
};
|
|
171
|
-
if (signal.aborted) {
|
|
172
|
-
onAbort();
|
|
173
|
-
} else {
|
|
174
|
-
signal.addEventListener('abort', onAbort);
|
|
211
|
+
},
|
|
212
|
+
cancel () {
|
|
213
|
+
_es?.close();
|
|
175
214
|
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
215
|
+
});
|
|
216
|
+
const getNewStreamAndReader = ()=>{
|
|
217
|
+
const stream = createStream();
|
|
218
|
+
const reader = stream.getReader();
|
|
219
|
+
return {
|
|
220
|
+
reader,
|
|
221
|
+
cancel: ()=>{
|
|
222
|
+
reader.releaseLock();
|
|
223
|
+
return stream.cancel();
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
};
|
|
181
227
|
return {
|
|
182
228
|
[Symbol.asyncIterator] () {
|
|
183
|
-
|
|
229
|
+
let stream = getNewStreamAndReader();
|
|
184
230
|
const iterator = {
|
|
185
231
|
async next () {
|
|
186
|
-
|
|
187
|
-
if (
|
|
232
|
+
let promise = stream.reader.read();
|
|
233
|
+
if (opts.reconnectAfterInactivityMs) {
|
|
234
|
+
promise = withTimeout({
|
|
235
|
+
promise,
|
|
236
|
+
timeoutMs: opts.reconnectAfterInactivityMs,
|
|
237
|
+
onTimeout: async ()=>{
|
|
238
|
+
// Close and release old reader
|
|
239
|
+
await stream.cancel();
|
|
240
|
+
// Create new reader
|
|
241
|
+
stream = getNewStreamAndReader();
|
|
242
|
+
return {
|
|
243
|
+
value: {
|
|
244
|
+
type: 'timeout',
|
|
245
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
246
|
+
eventSource: _es
|
|
247
|
+
},
|
|
248
|
+
done: false
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
const result = await promise;
|
|
254
|
+
// console.debug('result', result, 'done', result.done);
|
|
255
|
+
if (result.done) {
|
|
188
256
|
return {
|
|
189
|
-
value:
|
|
257
|
+
value: result.value,
|
|
190
258
|
done: true
|
|
191
259
|
};
|
|
192
260
|
}
|
|
193
261
|
return {
|
|
194
|
-
value:
|
|
262
|
+
value: result.value,
|
|
195
263
|
done: false
|
|
196
264
|
};
|
|
197
265
|
},
|
|
198
266
|
async return () {
|
|
199
|
-
|
|
267
|
+
await stream.cancel();
|
|
200
268
|
return {
|
|
201
269
|
value: undefined,
|
|
202
270
|
done: true
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import { Unpromise } from '../../vendor/unpromise/unpromise.mjs';
|
|
1
2
|
import { getTRPCErrorFromUnknown } from '../error/TRPCError.mjs';
|
|
3
|
+
import { isAbortError } from '../http/isAbortError.mjs';
|
|
2
4
|
import { run, identity } from '../utils.mjs';
|
|
3
5
|
import { isTrackedEnvelope } from './tracked.mjs';
|
|
4
|
-
import {
|
|
6
|
+
import { takeWithGrace, withMaxDuration } from './utils/asyncIterable.mjs';
|
|
5
7
|
import { createReadableStream } from './utils/createReadableStream.mjs';
|
|
6
|
-
import { createPromiseTimer } from './utils/promiseTimer.mjs';
|
|
7
8
|
import { withPing, PING_SYM } from './utils/withPing.mjs';
|
|
8
9
|
|
|
10
|
+
const PING_EVENT = 'ping';
|
|
9
11
|
const SERIALIZED_ERROR_EVENT = 'serialized-error';
|
|
10
12
|
/**
|
|
11
13
|
*
|
|
@@ -22,18 +24,18 @@ const SERIALIZED_ERROR_EVENT = 'serialized-error';
|
|
|
22
24
|
};
|
|
23
25
|
run(async ()=>{
|
|
24
26
|
let iterable = opts.data;
|
|
25
|
-
iterable = withCancel(iterable, stream.cancelledPromise);
|
|
26
27
|
if (opts.emitAndEndImmediately) {
|
|
27
28
|
iterable = takeWithGrace(iterable, {
|
|
28
29
|
count: 1,
|
|
29
30
|
gracePeriodMs: 1,
|
|
30
|
-
|
|
31
|
+
abortCtrl: opts.abortCtrl
|
|
31
32
|
});
|
|
32
33
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
if (opts.maxDurationMs && opts.maxDurationMs > 0 && opts.maxDurationMs !== Infinity) {
|
|
35
|
+
iterable = withMaxDuration(iterable, {
|
|
36
|
+
maxDurationMs: opts.maxDurationMs,
|
|
37
|
+
abortCtrl: opts.abortCtrl
|
|
38
|
+
});
|
|
37
39
|
}
|
|
38
40
|
if (ping.enabled && ping.intervalMs !== Infinity && ping.intervalMs > 0) {
|
|
39
41
|
iterable = withPing(iterable, ping.intervalMs);
|
|
@@ -46,7 +48,8 @@ const SERIALIZED_ERROR_EVENT = 'serialized-error';
|
|
|
46
48
|
for await (value of iterable){
|
|
47
49
|
if (value === PING_SYM) {
|
|
48
50
|
stream.controller.enqueue({
|
|
49
|
-
|
|
51
|
+
event: PING_EVENT,
|
|
52
|
+
data: ''
|
|
50
53
|
});
|
|
51
54
|
continue;
|
|
52
55
|
}
|
|
@@ -65,22 +68,26 @@ const SERIALIZED_ERROR_EVENT = 'serialized-error';
|
|
|
65
68
|
chunk = null;
|
|
66
69
|
}
|
|
67
70
|
} catch (err) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
// So, a user error in any case.
|
|
72
|
-
const error = getTRPCErrorFromUnknown(err);
|
|
73
|
-
const data = opts.formatError?.({
|
|
74
|
-
error
|
|
75
|
-
}) ?? null;
|
|
76
|
-
stream.controller.enqueue({
|
|
77
|
-
event: SERIALIZED_ERROR_EVENT,
|
|
78
|
-
data: JSON.stringify(serialize(data))
|
|
79
|
-
});
|
|
71
|
+
if (isAbortError(err)) {
|
|
72
|
+
// ignore abort errors, send any other errors
|
|
73
|
+
return;
|
|
80
74
|
}
|
|
75
|
+
// `err` must be caused by `opts.data`, `JSON.stringify` or `serialize`.
|
|
76
|
+
// So, a user error in any case.
|
|
77
|
+
const error = getTRPCErrorFromUnknown(err);
|
|
78
|
+
const data = opts.formatError?.({
|
|
79
|
+
error
|
|
80
|
+
}) ?? null;
|
|
81
|
+
stream.controller.enqueue({
|
|
82
|
+
event: SERIALIZED_ERROR_EVENT,
|
|
83
|
+
data: JSON.stringify(serialize(data))
|
|
84
|
+
});
|
|
81
85
|
} finally{
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
try {
|
|
87
|
+
stream.controller.close();
|
|
88
|
+
} catch {
|
|
89
|
+
// ignore
|
|
90
|
+
}
|
|
84
91
|
}
|
|
85
92
|
}).catch((err)=>{
|
|
86
93
|
// should not be reached; just in case...
|
|
@@ -104,97 +111,158 @@ const SERIALIZED_ERROR_EVENT = 'serialized-error';
|
|
|
104
111
|
}
|
|
105
112
|
}));
|
|
106
113
|
}
|
|
114
|
+
async function withTimeout(opts) {
|
|
115
|
+
let timeoutId;
|
|
116
|
+
const timeoutPromise = new Promise((resolve)=>{
|
|
117
|
+
timeoutId = setTimeout(()=>{
|
|
118
|
+
resolve(null);
|
|
119
|
+
}, opts.timeoutMs);
|
|
120
|
+
});
|
|
121
|
+
let res;
|
|
122
|
+
try {
|
|
123
|
+
res = await Unpromise.race([
|
|
124
|
+
opts.promise,
|
|
125
|
+
timeoutPromise
|
|
126
|
+
]);
|
|
127
|
+
} finally{
|
|
128
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
129
|
+
clearTimeout(timeoutId);
|
|
130
|
+
}
|
|
131
|
+
if (res === null) {
|
|
132
|
+
return await opts.onTimeout();
|
|
133
|
+
}
|
|
134
|
+
return res;
|
|
135
|
+
}
|
|
107
136
|
/**
|
|
108
137
|
* @see https://html.spec.whatwg.org/multipage/server-sent-events.html
|
|
109
138
|
*/ function sseStreamConsumer(opts) {
|
|
110
139
|
const { deserialize = (v)=>v } = opts;
|
|
111
140
|
const signal = opts.signal;
|
|
112
141
|
let _es = null;
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
controller.enqueue({
|
|
121
|
-
type: 'connecting',
|
|
122
|
-
eventSource: _es,
|
|
123
|
-
event: null
|
|
124
|
-
});
|
|
125
|
-
eventSource.addEventListener('open', ()=>{
|
|
142
|
+
const createStream = ()=>new ReadableStream({
|
|
143
|
+
async start (controller) {
|
|
144
|
+
const [url, init] = await Promise.all([
|
|
145
|
+
opts.url(),
|
|
146
|
+
opts.init()
|
|
147
|
+
]);
|
|
148
|
+
const eventSource = _es = new opts.EventSource(url, init);
|
|
126
149
|
controller.enqueue({
|
|
127
|
-
type: '
|
|
128
|
-
eventSource
|
|
150
|
+
type: 'connecting',
|
|
151
|
+
eventSource: _es,
|
|
152
|
+
event: null
|
|
129
153
|
});
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
error: deserialize(JSON.parse(msg.data)),
|
|
136
|
-
eventSource
|
|
154
|
+
eventSource.addEventListener('open', ()=>{
|
|
155
|
+
controller.enqueue({
|
|
156
|
+
type: 'opened',
|
|
157
|
+
eventSource
|
|
158
|
+
});
|
|
137
159
|
});
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (eventSource.readyState === EventSource.CLOSED) {
|
|
141
|
-
controller.error(event);
|
|
142
|
-
} else {
|
|
160
|
+
eventSource.addEventListener(SERIALIZED_ERROR_EVENT, (_msg)=>{
|
|
161
|
+
const msg = _msg;
|
|
143
162
|
controller.enqueue({
|
|
144
|
-
type: '
|
|
145
|
-
|
|
146
|
-
|
|
163
|
+
type: 'serialized-error',
|
|
164
|
+
error: deserialize(JSON.parse(msg.data)),
|
|
165
|
+
eventSource
|
|
147
166
|
});
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
167
|
+
});
|
|
168
|
+
eventSource.addEventListener(PING_EVENT, ()=>{
|
|
169
|
+
controller.enqueue({
|
|
170
|
+
type: 'ping',
|
|
171
|
+
eventSource
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
eventSource.addEventListener('error', (event)=>{
|
|
175
|
+
if (eventSource.readyState === EventSource.CLOSED) {
|
|
176
|
+
controller.error(event);
|
|
177
|
+
} else {
|
|
178
|
+
controller.enqueue({
|
|
179
|
+
type: 'connecting',
|
|
180
|
+
eventSource,
|
|
181
|
+
event
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
eventSource.addEventListener('message', (_msg)=>{
|
|
186
|
+
const msg = _msg;
|
|
187
|
+
const chunk = deserialize(JSON.parse(msg.data));
|
|
188
|
+
const def = {
|
|
189
|
+
data: chunk
|
|
190
|
+
};
|
|
191
|
+
if (msg.lastEventId) {
|
|
192
|
+
def.id = msg.lastEventId;
|
|
193
|
+
}
|
|
194
|
+
controller.enqueue({
|
|
195
|
+
type: 'data',
|
|
196
|
+
data: def,
|
|
197
|
+
eventSource
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
const onAbort = ()=>{
|
|
201
|
+
controller.close();
|
|
202
|
+
eventSource.close();
|
|
155
203
|
};
|
|
156
|
-
if (
|
|
157
|
-
|
|
204
|
+
if (signal.aborted) {
|
|
205
|
+
onAbort();
|
|
206
|
+
} else {
|
|
207
|
+
signal.addEventListener('abort', onAbort);
|
|
158
208
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
eventSource
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
const onAbort = ()=>{
|
|
166
|
-
controller.close();
|
|
167
|
-
eventSource.close();
|
|
168
|
-
};
|
|
169
|
-
if (signal.aborted) {
|
|
170
|
-
onAbort();
|
|
171
|
-
} else {
|
|
172
|
-
signal.addEventListener('abort', onAbort);
|
|
209
|
+
},
|
|
210
|
+
cancel () {
|
|
211
|
+
_es?.close();
|
|
173
212
|
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
213
|
+
});
|
|
214
|
+
const getNewStreamAndReader = ()=>{
|
|
215
|
+
const stream = createStream();
|
|
216
|
+
const reader = stream.getReader();
|
|
217
|
+
return {
|
|
218
|
+
reader,
|
|
219
|
+
cancel: ()=>{
|
|
220
|
+
reader.releaseLock();
|
|
221
|
+
return stream.cancel();
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
};
|
|
179
225
|
return {
|
|
180
226
|
[Symbol.asyncIterator] () {
|
|
181
|
-
|
|
227
|
+
let stream = getNewStreamAndReader();
|
|
182
228
|
const iterator = {
|
|
183
229
|
async next () {
|
|
184
|
-
|
|
185
|
-
if (
|
|
230
|
+
let promise = stream.reader.read();
|
|
231
|
+
if (opts.reconnectAfterInactivityMs) {
|
|
232
|
+
promise = withTimeout({
|
|
233
|
+
promise,
|
|
234
|
+
timeoutMs: opts.reconnectAfterInactivityMs,
|
|
235
|
+
onTimeout: async ()=>{
|
|
236
|
+
// Close and release old reader
|
|
237
|
+
await stream.cancel();
|
|
238
|
+
// Create new reader
|
|
239
|
+
stream = getNewStreamAndReader();
|
|
240
|
+
return {
|
|
241
|
+
value: {
|
|
242
|
+
type: 'timeout',
|
|
243
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
244
|
+
eventSource: _es
|
|
245
|
+
},
|
|
246
|
+
done: false
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
const result = await promise;
|
|
252
|
+
// console.debug('result', result, 'done', result.done);
|
|
253
|
+
if (result.done) {
|
|
186
254
|
return {
|
|
187
|
-
value:
|
|
255
|
+
value: result.value,
|
|
188
256
|
done: true
|
|
189
257
|
};
|
|
190
258
|
}
|
|
191
259
|
return {
|
|
192
|
-
value:
|
|
260
|
+
value: result.value,
|
|
193
261
|
done: false
|
|
194
262
|
};
|
|
195
263
|
},
|
|
196
264
|
async return () {
|
|
197
|
-
|
|
265
|
+
await stream.cancel();
|
|
198
266
|
return {
|
|
199
267
|
value: undefined,
|
|
200
268
|
done: true
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Derives a new {@link AsyncGenerator} based
|
|
3
|
-
* passed {@link cancel} promise.
|
|
2
|
+
* Derives a new {@link AsyncGenerator} based on {@link iterable}, that automatically stops after the specified duration.
|
|
4
3
|
*/
|
|
5
|
-
export declare function
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
onCancel: () => void;
|
|
10
|
-
}
|
|
4
|
+
export declare function withMaxDuration<T>(iterable: AsyncIterable<T>, opts: {
|
|
5
|
+
maxDurationMs: number;
|
|
6
|
+
abortCtrl: AbortController;
|
|
7
|
+
}): AsyncGenerator<T>;
|
|
11
8
|
/**
|
|
12
9
|
* Derives a new {@link AsyncGenerator} based of {@link iterable}, that yields its first
|
|
13
10
|
* {@link count} values. Then, a grace period of {@link gracePeriodMs} is started in which further
|
|
14
11
|
* values may still come through. After this period, the generator stops.
|
|
15
12
|
*/
|
|
16
|
-
export declare function takeWithGrace<T>(iterable: AsyncIterable<T>,
|
|
17
|
-
|
|
13
|
+
export declare function takeWithGrace<T>(iterable: AsyncIterable<T>, opts: {
|
|
14
|
+
count: number;
|
|
15
|
+
gracePeriodMs: number;
|
|
16
|
+
abortCtrl: AbortController;
|
|
17
|
+
}): AsyncGenerator<T>;
|
|
18
18
|
//# sourceMappingURL=asyncIterable.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asyncIterable.d.ts","sourceRoot":"","sources":["../../../../src/unstable-core-do-not-import/stream/utils/asyncIterable.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"asyncIterable.d.ts","sourceRoot":"","sources":["../../../../src/unstable-core-do-not-import/stream/utils/asyncIterable.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,wBAAuB,eAAe,CAAC,CAAC,EACtC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,EAC1B,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,eAAe,CAAA;CAAE,GAC1D,cAAc,CAAC,CAAC,CAAC,CA8BnB;AAED;;;;GAIG;AACH,wBAAuB,aAAa,CAAC,CAAC,EACpC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,EAC1B,IAAI,EAAE;IACJ,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,eAAe,CAAC;CAC5B,GACA,cAAc,CAAC,CAAC,CAAC,CAoCnB"}
|