@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.
Files changed (117) hide show
  1. package/dist/@trpc/server/http.d.ts +1 -1
  2. package/dist/@trpc/server/http.d.ts.map +1 -1
  3. package/dist/adapters/aws-lambda/index.js +1 -0
  4. package/dist/adapters/aws-lambda/index.mjs +1 -0
  5. package/dist/adapters/express.js +1 -0
  6. package/dist/adapters/express.mjs +1 -0
  7. package/dist/adapters/fastify/fastifyRequestHandler.js +2 -1
  8. package/dist/adapters/fastify/fastifyRequestHandler.mjs +2 -1
  9. package/dist/adapters/fetch/fetchRequestHandler.js +1 -0
  10. package/dist/adapters/fetch/fetchRequestHandler.mjs +1 -0
  11. package/dist/adapters/next-app-dir/nextAppDirCaller.js +1 -0
  12. package/dist/adapters/next-app-dir/nextAppDirCaller.mjs +1 -0
  13. package/dist/adapters/next-app-dir/notFound.js +1 -0
  14. package/dist/adapters/next-app-dir/notFound.mjs +1 -0
  15. package/dist/adapters/next-app-dir/redirect.js +1 -0
  16. package/dist/adapters/next-app-dir/redirect.mjs +1 -0
  17. package/dist/adapters/next.js +1 -0
  18. package/dist/adapters/next.mjs +1 -0
  19. package/dist/adapters/node-http/incomingMessageToRequest.d.ts +1 -1
  20. package/dist/adapters/node-http/incomingMessageToRequest.d.ts.map +1 -1
  21. package/dist/adapters/node-http/incomingMessageToRequest.js +7 -5
  22. package/dist/adapters/node-http/incomingMessageToRequest.mjs +7 -5
  23. package/dist/adapters/node-http/nodeHTTPRequestHandler.d.ts.map +1 -1
  24. package/dist/adapters/node-http/nodeHTTPRequestHandler.js +9 -42
  25. package/dist/adapters/node-http/nodeHTTPRequestHandler.mjs +9 -42
  26. package/dist/adapters/node-http/writeResponse.d.ts +18 -0
  27. package/dist/adapters/node-http/writeResponse.d.ts.map +1 -0
  28. package/dist/adapters/node-http/writeResponse.js +80 -0
  29. package/dist/adapters/node-http/writeResponse.mjs +77 -0
  30. package/dist/adapters/standalone.js +1 -0
  31. package/dist/adapters/standalone.mjs +1 -0
  32. package/dist/adapters/ws.js +1 -0
  33. package/dist/adapters/ws.mjs +1 -0
  34. package/dist/bundle-analysis.json +195 -168
  35. package/dist/http.js +1 -2
  36. package/dist/http.mjs +1 -1
  37. package/dist/index.js +1 -0
  38. package/dist/index.mjs +1 -0
  39. package/dist/rpc.js +1 -0
  40. package/dist/rpc.mjs +1 -0
  41. package/dist/shared.js +1 -0
  42. package/dist/shared.mjs +1 -0
  43. package/dist/unstable-core-do-not-import/http/isAbortError.d.ts +4 -0
  44. package/dist/unstable-core-do-not-import/http/isAbortError.d.ts.map +1 -0
  45. package/dist/unstable-core-do-not-import/http/isAbortError.js +9 -0
  46. package/dist/unstable-core-do-not-import/http/isAbortError.mjs +7 -0
  47. package/dist/unstable-core-do-not-import/http/resolveResponse.d.ts.map +1 -1
  48. package/dist/unstable-core-do-not-import/http/resolveResponse.js +3 -3
  49. package/dist/unstable-core-do-not-import/http/resolveResponse.mjs +3 -3
  50. package/dist/unstable-core-do-not-import/initTRPC.js +2 -2
  51. package/dist/unstable-core-do-not-import/initTRPC.mjs +2 -2
  52. package/dist/unstable-core-do-not-import/rootConfig.d.ts +14 -14
  53. package/dist/unstable-core-do-not-import/rootConfig.d.ts.map +1 -1
  54. package/dist/unstable-core-do-not-import/rpc/envelopes.d.ts +7 -10
  55. package/dist/unstable-core-do-not-import/rpc/envelopes.d.ts.map +1 -1
  56. package/dist/unstable-core-do-not-import/stream/jsonl.d.ts +6 -9
  57. package/dist/unstable-core-do-not-import/stream/jsonl.d.ts.map +1 -1
  58. package/dist/unstable-core-do-not-import/stream/jsonl.js +75 -124
  59. package/dist/unstable-core-do-not-import/stream/jsonl.mjs +76 -125
  60. package/dist/unstable-core-do-not-import/stream/sse.d.ts +11 -1
  61. package/dist/unstable-core-do-not-import/stream/sse.d.ts.map +1 -1
  62. package/dist/unstable-core-do-not-import/stream/sse.js +154 -86
  63. package/dist/unstable-core-do-not-import/stream/sse.mjs +155 -87
  64. package/dist/unstable-core-do-not-import/stream/utils/asyncIterable.d.ts +10 -10
  65. package/dist/unstable-core-do-not-import/stream/utils/asyncIterable.d.ts.map +1 -1
  66. package/dist/unstable-core-do-not-import/stream/utils/asyncIterable.js +47 -34
  67. package/dist/unstable-core-do-not-import/stream/utils/asyncIterable.mjs +47 -34
  68. package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.d.ts +0 -4
  69. package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.d.ts.map +1 -1
  70. package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.js +0 -11
  71. package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.mjs +1 -11
  72. package/dist/unstable-core-do-not-import/stream/utils/disposablePromiseTimer.d.ts +6 -0
  73. package/dist/unstable-core-do-not-import/stream/utils/disposablePromiseTimer.d.ts.map +1 -0
  74. package/dist/unstable-core-do-not-import/stream/utils/disposablePromiseTimer.js +28 -0
  75. package/dist/unstable-core-do-not-import/stream/utils/disposablePromiseTimer.mjs +25 -0
  76. package/dist/unstable-core-do-not-import/stream/utils/withPing.d.ts.map +1 -1
  77. package/dist/unstable-core-do-not-import/stream/utils/withPing.js +17 -17
  78. package/dist/unstable-core-do-not-import/stream/utils/withPing.mjs +17 -17
  79. package/dist/unstable-core-do-not-import/stream/utils/withRefCount.d.ts +17 -0
  80. package/dist/unstable-core-do-not-import/stream/utils/withRefCount.d.ts.map +1 -0
  81. package/dist/unstable-core-do-not-import/stream/utils/withRefCount.js +59 -0
  82. package/dist/unstable-core-do-not-import/stream/utils/withRefCount.mjs +57 -0
  83. package/dist/unstable-core-do-not-import/transformer.d.ts +1 -4
  84. package/dist/unstable-core-do-not-import/transformer.d.ts.map +1 -1
  85. package/dist/unstable-core-do-not-import.d.ts +2 -2
  86. package/dist/unstable-core-do-not-import.d.ts.map +1 -1
  87. package/dist/unstable-core-do-not-import.js +2 -2
  88. package/dist/unstable-core-do-not-import.mjs +1 -1
  89. package/package.json +3 -3
  90. package/src/@trpc/server/http.ts +0 -1
  91. package/src/adapters/fastify/fastifyRequestHandler.ts +1 -1
  92. package/src/adapters/node-http/incomingMessageToRequest.ts +8 -4
  93. package/src/adapters/node-http/nodeHTTPRequestHandler.ts +8 -46
  94. package/src/adapters/node-http/writeResponse.ts +91 -0
  95. package/src/unstable-core-do-not-import/http/isAbortError.ts +7 -0
  96. package/src/unstable-core-do-not-import/http/resolveResponse.ts +3 -4
  97. package/src/unstable-core-do-not-import/initTRPC.ts +1 -1
  98. package/src/unstable-core-do-not-import/rootConfig.ts +17 -17
  99. package/src/unstable-core-do-not-import/rpc/envelopes.ts +7 -12
  100. package/src/unstable-core-do-not-import/stream/jsonl.ts +85 -154
  101. package/src/unstable-core-do-not-import/stream/sse.ts +179 -92
  102. package/src/unstable-core-do-not-import/stream/utils/asyncIterable.ts +58 -37
  103. package/src/unstable-core-do-not-import/stream/utils/createReadableStream.ts +0 -13
  104. package/src/unstable-core-do-not-import/stream/utils/disposablePromiseTimer.ts +27 -0
  105. package/src/unstable-core-do-not-import/stream/utils/withPing.ts +31 -19
  106. package/src/unstable-core-do-not-import/stream/utils/withRefCount.ts +93 -0
  107. package/src/unstable-core-do-not-import.ts +2 -2
  108. package/dist/unstable-core-do-not-import/http/batchStreamFormatter.d.ts +0 -24
  109. package/dist/unstable-core-do-not-import/http/batchStreamFormatter.d.ts.map +0 -1
  110. package/dist/unstable-core-do-not-import/http/batchStreamFormatter.js +0 -32
  111. package/dist/unstable-core-do-not-import/http/batchStreamFormatter.mjs +0 -30
  112. package/dist/unstable-core-do-not-import/stream/utils/promiseTimer.d.ts +0 -8
  113. package/dist/unstable-core-do-not-import/stream/utils/promiseTimer.d.ts.map +0 -1
  114. package/dist/unstable-core-do-not-import/stream/utils/promiseTimer.js +0 -38
  115. package/dist/unstable-core-do-not-import/stream/utils/promiseTimer.mjs +0 -36
  116. package/src/unstable-core-do-not-import/http/batchStreamFormatter.ts +0 -29
  117. 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
- onCancel: ()=>opts.abortCtrl.abort()
33
+ abortCtrl: opts.abortCtrl
33
34
  });
34
35
  }
35
- let maxDurationTimer = null;
36
- if (opts.maxDurationMs != null && opts.maxDurationMs > 0 && opts.maxDurationMs !== Infinity) {
37
- maxDurationTimer = promiseTimer.createPromiseTimer(opts.maxDurationMs).start();
38
- iterable = asyncIterable.withCancel(iterable, maxDurationTimer.promise.then(()=>opts.abortCtrl.abort()));
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
- comment: 'ping'
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
- // ignore abort errors, send any other errors
71
- if (!(err instanceof Error) || err.name !== 'AbortError') {
72
- // `err` must be caused by `opts.data`, `JSON.stringify` or `serialize`.
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
- maxDurationTimer?.clear();
85
- stream.controller.close();
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 stream = new ReadableStream({
116
- async start (controller) {
117
- const [url, init] = await Promise.all([
118
- opts.url(),
119
- opts.init()
120
- ]);
121
- const eventSource = _es = new opts.EventSource(url, init);
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: 'opened',
130
- eventSource
152
+ type: 'connecting',
153
+ eventSource: _es,
154
+ event: null
131
155
  });
132
- });
133
- eventSource.addEventListener(SERIALIZED_ERROR_EVENT, (_msg)=>{
134
- const msg = _msg;
135
- controller.enqueue({
136
- type: 'serialized-error',
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
- eventSource.addEventListener('error', (event)=>{
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: 'connecting',
147
- eventSource,
148
- event
165
+ type: 'serialized-error',
166
+ error: deserialize(JSON.parse(msg.data)),
167
+ eventSource
149
168
  });
150
- }
151
- });
152
- eventSource.addEventListener('message', (_msg)=>{
153
- const msg = _msg;
154
- const chunk = deserialize(JSON.parse(msg.data));
155
- const def = {
156
- data: chunk
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 (msg.lastEventId) {
159
- def.id = msg.lastEventId;
206
+ if (signal.aborted) {
207
+ onAbort();
208
+ } else {
209
+ signal.addEventListener('abort', onAbort);
160
210
  }
161
- controller.enqueue({
162
- type: 'data',
163
- data: def,
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
- cancel () {
178
- _es?.close();
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
- const reader = stream.getReader();
229
+ let stream = getNewStreamAndReader();
184
230
  const iterator = {
185
231
  async next () {
186
- const value = await reader.read();
187
- if (value.done) {
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: undefined,
257
+ value: result.value,
190
258
  done: true
191
259
  };
192
260
  }
193
261
  return {
194
- value: value.value,
262
+ value: result.value,
195
263
  done: false
196
264
  };
197
265
  },
198
266
  async return () {
199
- reader.releaseLock();
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 { withCancel, takeWithGrace } from './utils/asyncIterable.mjs';
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
- onCancel: ()=>opts.abortCtrl.abort()
31
+ abortCtrl: opts.abortCtrl
31
32
  });
32
33
  }
33
- let maxDurationTimer = null;
34
- if (opts.maxDurationMs != null && opts.maxDurationMs > 0 && opts.maxDurationMs !== Infinity) {
35
- maxDurationTimer = createPromiseTimer(opts.maxDurationMs).start();
36
- iterable = withCancel(iterable, maxDurationTimer.promise.then(()=>opts.abortCtrl.abort()));
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
- comment: 'ping'
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
- // ignore abort errors, send any other errors
69
- if (!(err instanceof Error) || err.name !== 'AbortError') {
70
- // `err` must be caused by `opts.data`, `JSON.stringify` or `serialize`.
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
- maxDurationTimer?.clear();
83
- stream.controller.close();
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 stream = new ReadableStream({
114
- async start (controller) {
115
- const [url, init] = await Promise.all([
116
- opts.url(),
117
- opts.init()
118
- ]);
119
- const eventSource = _es = new opts.EventSource(url, init);
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: 'opened',
128
- eventSource
150
+ type: 'connecting',
151
+ eventSource: _es,
152
+ event: null
129
153
  });
130
- });
131
- eventSource.addEventListener(SERIALIZED_ERROR_EVENT, (_msg)=>{
132
- const msg = _msg;
133
- controller.enqueue({
134
- type: 'serialized-error',
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
- eventSource.addEventListener('error', (event)=>{
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: 'connecting',
145
- eventSource,
146
- event
163
+ type: 'serialized-error',
164
+ error: deserialize(JSON.parse(msg.data)),
165
+ eventSource
147
166
  });
148
- }
149
- });
150
- eventSource.addEventListener('message', (_msg)=>{
151
- const msg = _msg;
152
- const chunk = deserialize(JSON.parse(msg.data));
153
- const def = {
154
- data: chunk
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 (msg.lastEventId) {
157
- def.id = msg.lastEventId;
204
+ if (signal.aborted) {
205
+ onAbort();
206
+ } else {
207
+ signal.addEventListener('abort', onAbort);
158
208
  }
159
- controller.enqueue({
160
- type: 'data',
161
- data: def,
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
- cancel () {
176
- _es?.close();
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
- const reader = stream.getReader();
227
+ let stream = getNewStreamAndReader();
182
228
  const iterator = {
183
229
  async next () {
184
- const value = await reader.read();
185
- if (value.done) {
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: undefined,
255
+ value: result.value,
188
256
  done: true
189
257
  };
190
258
  }
191
259
  return {
192
- value: value.value,
260
+ value: result.value,
193
261
  done: false
194
262
  };
195
263
  },
196
264
  async return () {
197
- reader.releaseLock();
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 of {@link iterable}, that automatically stops with the
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 withCancel<T>(iterable: AsyncIterable<T>, cancel: Promise<unknown>): AsyncGenerator<T>;
6
- interface TakeWithGraceOptions {
7
- count: number;
8
- gracePeriodMs: number;
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>, { count, gracePeriodMs, onCancel }: TakeWithGraceOptions): AsyncGenerator<T>;
17
- export {};
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":"AAIA;;;GAGG;AACH,wBAAuB,UAAU,CAAC,CAAC,EACjC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,EAC1B,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GACvB,cAAc,CAAC,CAAC,CAAC,CAkBnB;AAED,UAAU,oBAAoB;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAuB,aAAa,CAAC,CAAC,EACpC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,EAC1B,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,oBAAoB,GACvD,cAAc,CAAC,CAAC,CAAC,CA0BnB"}
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"}