@trpc/server 11.0.0-rc.693 → 11.0.0-rc.695

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.
@@ -1,8 +1,8 @@
1
- import { Unpromise } from '../../vendor/unpromise/unpromise.mjs';
2
- import { isObject, isFunction, isAsyncIterable, run } from '../utils.mjs';
1
+ import { isObject, isFunction, run, isAsyncIterable } from '../utils.mjs';
3
2
  import { iteratorResource } from './utils/asyncIterable.mjs';
4
3
  import { createDeferred } from './utils/createDeferred.mjs';
5
- import { makeAsyncResource, makeResource } from './utils/disposable.mjs';
4
+ import { makeResource } from './utils/disposable.mjs';
5
+ import { mergeAsyncIterables } from './utils/mergeAsyncIterables.mjs';
6
6
  import { readableStreamFrom } from './utils/readableStreamFrom.mjs';
7
7
 
8
8
  function _define_property(obj, key, value) {
@@ -101,223 +101,189 @@ class MaxDepthError extends Error {
101
101
  }
102
102
  }
103
103
  async function* createBatchStreamProducer(opts) {
104
- const env = {
105
- stack: [],
106
- error: void 0,
107
- hasError: false
108
- };
109
- try {
110
- const { data } = opts;
111
- let counter = 0;
112
- const placeholder = 0;
113
- const queue = _ts_add_disposable_resource(env, makeAsyncResource(new Set(), async ()=>{
114
- await Promise.all(Array.from(queue).map((it)=>it.iterator.return?.()));
115
- }), true);
116
- ;
117
- function registerAsync(callback) {
118
- const idx = counter++;
119
- const iterator = callback(idx)[Symbol.asyncIterator]();
120
- const nextPromise = iterator.next();
121
- nextPromise.catch(()=>{
122
- // prevent unhandled promise rejection
123
- });
124
- queue.add({
125
- iterator,
126
- nextPromise
127
- });
128
- return idx;
129
- }
130
- function encodePromise(promise, path) {
131
- return registerAsync(async function*(idx) {
104
+ const { data } = opts;
105
+ let counter = 0;
106
+ const placeholder = 0;
107
+ const mergedIterables = mergeAsyncIterables();
108
+ function registerAsync(callback) {
109
+ const idx = counter++;
110
+ const iterable = callback(idx);
111
+ mergedIterables.add(iterable);
112
+ return idx;
113
+ }
114
+ function encodePromise(promise, path) {
115
+ return registerAsync(async function*(idx) {
116
+ const error = checkMaxDepth(path);
117
+ if (error) {
118
+ // Catch any errors from the original promise to ensure they're reported
119
+ promise.catch((cause)=>{
120
+ opts.onError?.({
121
+ error: cause,
122
+ path
123
+ });
124
+ });
125
+ // Replace the promise with a rejected one containing the max depth error
126
+ promise = Promise.reject(error);
127
+ }
128
+ try {
129
+ const next = await promise;
130
+ yield [
131
+ idx,
132
+ PROMISE_STATUS_FULFILLED,
133
+ encode(next, path)
134
+ ];
135
+ } catch (cause) {
136
+ opts.onError?.({
137
+ error: cause,
138
+ path
139
+ });
140
+ yield [
141
+ idx,
142
+ PROMISE_STATUS_REJECTED,
143
+ opts.formatError?.({
144
+ error: cause,
145
+ path
146
+ })
147
+ ];
148
+ }
149
+ });
150
+ }
151
+ function encodeAsyncIterable(iterable, path) {
152
+ return registerAsync(async function*(idx) {
153
+ const env = {
154
+ stack: [],
155
+ error: void 0,
156
+ hasError: false
157
+ };
158
+ try {
132
159
  const error = checkMaxDepth(path);
133
160
  if (error) {
134
- // Catch any errors from the original promise to ensure they're reported
135
- promise.catch((cause)=>{
136
- opts.onError?.({
137
- error: cause,
138
- path
139
- });
140
- });
141
- // Replace the promise with a rejected one containing the max depth error
142
- promise = Promise.reject(error);
161
+ throw error;
143
162
  }
163
+ const iterator = _ts_add_disposable_resource(env, iteratorResource(iterable), true);
164
+ ;
144
165
  try {
145
- const next = await promise;
146
- return [
147
- idx,
148
- PROMISE_STATUS_FULFILLED,
149
- encode(next, path)
150
- ];
166
+ while(true){
167
+ const next = await iterator.next();
168
+ if (next.done) {
169
+ yield [
170
+ idx,
171
+ ASYNC_ITERABLE_STATUS_RETURN,
172
+ encode(next.value, path)
173
+ ];
174
+ break;
175
+ }
176
+ yield [
177
+ idx,
178
+ ASYNC_ITERABLE_STATUS_YIELD,
179
+ encode(next.value, path)
180
+ ];
181
+ }
151
182
  } catch (cause) {
152
183
  opts.onError?.({
153
184
  error: cause,
154
185
  path
155
186
  });
156
- return [
187
+ yield [
157
188
  idx,
158
- PROMISE_STATUS_REJECTED,
189
+ ASYNC_ITERABLE_STATUS_ERROR,
159
190
  opts.formatError?.({
160
191
  error: cause,
161
192
  path
162
193
  })
163
194
  ];
164
195
  }
165
- });
196
+ } catch (e) {
197
+ env.error = e;
198
+ env.hasError = true;
199
+ } finally{
200
+ const result = _ts_dispose_resources(env);
201
+ if (result) await result;
202
+ }
203
+ });
204
+ }
205
+ function checkMaxDepth(path) {
206
+ if (opts.maxDepth && path.length > opts.maxDepth) {
207
+ return new MaxDepthError(path);
166
208
  }
167
- function encodeAsyncIterable(iterable, path) {
168
- return registerAsync(async function*(idx) {
169
- const env = {
170
- stack: [],
171
- error: void 0,
172
- hasError: false
173
- };
174
- try {
175
- const error = checkMaxDepth(path);
176
- if (error) {
177
- throw error;
178
- }
179
- const iterator = _ts_add_disposable_resource(env, iteratorResource(iterable), true);
180
- ;
181
- try {
182
- while(true){
183
- const next = await iterator.next();
184
- if (next.done) {
185
- return [
186
- idx,
187
- ASYNC_ITERABLE_STATUS_RETURN,
188
- encode(next.value, path)
189
- ];
190
- }
191
- yield [
192
- idx,
193
- ASYNC_ITERABLE_STATUS_YIELD,
194
- encode(next.value, path)
195
- ];
196
- }
197
- } catch (cause) {
198
- opts.onError?.({
199
- error: cause,
200
- path
201
- });
202
- return [
203
- idx,
204
- ASYNC_ITERABLE_STATUS_ERROR,
205
- opts.formatError?.({
206
- error: cause,
207
- path
208
- })
209
- ];
210
- }
211
- } catch (e) {
212
- env.error = e;
213
- env.hasError = true;
214
- } finally{
215
- const result = _ts_dispose_resources(env);
216
- if (result) await result;
217
- }
218
- });
209
+ return null;
210
+ }
211
+ function encodeAsync(value, path) {
212
+ if (isPromise(value)) {
213
+ return [
214
+ CHUNK_VALUE_TYPE_PROMISE,
215
+ encodePromise(value, path)
216
+ ];
219
217
  }
220
- function checkMaxDepth(path) {
221
- if (opts.maxDepth && path.length > opts.maxDepth) {
222
- return new MaxDepthError(path);
218
+ if (isAsyncIterable(value)) {
219
+ if (opts.maxDepth && path.length >= opts.maxDepth) {
220
+ throw new Error('Max depth reached');
223
221
  }
224
- return null;
222
+ return [
223
+ CHUNK_VALUE_TYPE_ASYNC_ITERABLE,
224
+ encodeAsyncIterable(value, path)
225
+ ];
225
226
  }
226
- function encodeAsync(value, path) {
227
- if (isPromise(value)) {
228
- return [
229
- CHUNK_VALUE_TYPE_PROMISE,
230
- encodePromise(value, path)
231
- ];
232
- }
233
- if (isAsyncIterable(value)) {
234
- if (opts.maxDepth && path.length >= opts.maxDepth) {
235
- throw new Error('Max depth reached');
236
- }
237
- return [
238
- CHUNK_VALUE_TYPE_ASYNC_ITERABLE,
239
- encodeAsyncIterable(value, path)
240
- ];
241
- }
242
- return null;
227
+ return null;
228
+ }
229
+ function encode(value, path) {
230
+ if (value === undefined) {
231
+ return [
232
+ []
233
+ ];
243
234
  }
244
- function encode(value, path) {
245
- if (value === undefined) {
246
- return [
247
- []
248
- ];
249
- }
250
- if (!isObject(value)) {
251
- return [
252
- [
253
- value
254
- ]
255
- ];
256
- }
257
- const reg = encodeAsync(value, path);
258
- if (reg) {
259
- return [
260
- [
261
- placeholder
262
- ],
263
- [
264
- null,
265
- ...reg
266
- ]
267
- ];
268
- }
269
- const newObj = {};
270
- const asyncValues = [];
271
- for (const [key, item] of Object.entries(value)){
272
- const transformed = encodeAsync(item, [
273
- ...path,
274
- key
275
- ]);
276
- if (!transformed) {
277
- newObj[key] = item;
278
- continue;
279
- }
280
- newObj[key] = placeholder;
281
- asyncValues.push([
282
- key,
283
- ...transformed
284
- ]);
285
- }
235
+ if (!isObject(value)) {
236
+ return [
237
+ [
238
+ value
239
+ ]
240
+ ];
241
+ }
242
+ const reg = encodeAsync(value, path);
243
+ if (reg) {
286
244
  return [
287
245
  [
288
- newObj
246
+ placeholder
289
247
  ],
290
- ...asyncValues
248
+ [
249
+ null,
250
+ ...reg
251
+ ]
291
252
  ];
292
253
  }
293
- const newHead = {};
294
- for (const [key, item] of Object.entries(data)){
295
- newHead[key] = encode(item, [
254
+ const newObj = {};
255
+ const asyncValues = [];
256
+ for (const [key, item] of Object.entries(value)){
257
+ const transformed = encodeAsync(item, [
258
+ ...path,
296
259
  key
297
260
  ]);
298
- }
299
- yield newHead;
300
- // Process all async iterables in parallel by racing their next values
301
- while(queue.size > 0){
302
- // Race all iterators to get the next value from any of them
303
- const [entry, res] = await Unpromise.race(Array.from(queue).map(async (it)=>[
304
- it,
305
- await it.nextPromise
306
- ]));
307
- yield res.value;
308
- // Remove current iterator and re-add if not done
309
- queue.delete(entry);
310
- if (!res.done) {
311
- entry.nextPromise = entry.iterator.next();
312
- queue.add(entry);
261
+ if (!transformed) {
262
+ newObj[key] = item;
263
+ continue;
313
264
  }
265
+ newObj[key] = placeholder;
266
+ asyncValues.push([
267
+ key,
268
+ ...transformed
269
+ ]);
314
270
  }
315
- } catch (e) {
316
- env.error = e;
317
- env.hasError = true;
318
- } finally{
319
- const result = _ts_dispose_resources(env);
320
- if (result) await result;
271
+ return [
272
+ [
273
+ newObj
274
+ ],
275
+ ...asyncValues
276
+ ];
277
+ }
278
+ const newHead = {};
279
+ for (const [key, item] of Object.entries(data)){
280
+ newHead[key] = encode(item, [
281
+ key
282
+ ]);
283
+ }
284
+ yield newHead;
285
+ for await (const value of mergedIterables){
286
+ yield value;
321
287
  }
322
288
  }
323
289
  /**
@@ -0,0 +1,17 @@
1
+ interface MergedAsyncIterables<TYield> extends AsyncIterable<TYield, void, unknown> {
2
+ add(iterable: AsyncIterable<TYield>): void;
3
+ }
4
+ /**
5
+ * Creates a new async iterable that merges multiple async iterables into a single stream.
6
+ * Values from the input iterables are yielded in the order they resolve, similar to Promise.race().
7
+ *
8
+ * New iterables can be added dynamically using the returned {@link MergedAsyncIterables.add} method, even after iteration has started.
9
+ *
10
+ * If any of the input iterables throws an error, that error will be propagated through the merged stream.
11
+ * Other iterables will not continue to be processed.
12
+ *
13
+ * @template TYield The type of values yielded by the input iterables
14
+ */
15
+ export declare function mergeAsyncIterables<TYield>(): MergedAsyncIterables<TYield>;
16
+ export {};
17
+ //# sourceMappingURL=mergeAsyncIterables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mergeAsyncIterables.d.ts","sourceRoot":"","sources":["../../../../src/unstable-core-do-not-import/stream/utils/mergeAsyncIterables.ts"],"names":[],"mappings":"AAyDA,UAAU,oBAAoB,CAAC,MAAM,CACnC,SAAQ,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC;IAC5C,GAAG,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;CAC5C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,KAAK,oBAAoB,CAAC,MAAM,CAAC,CAuH1E"}
@@ -0,0 +1,241 @@
1
+ 'use strict';
2
+
3
+ var createDeferred = require('./createDeferred.js');
4
+ var disposable = require('./disposable.js');
5
+
6
+ function _ts_add_disposable_resource(env, value, async) {
7
+ if (value !== null && value !== void 0) {
8
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
9
+ var dispose, inner;
10
+ {
11
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
12
+ dispose = value[Symbol.asyncDispose];
13
+ }
14
+ if (dispose === void 0) {
15
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
16
+ dispose = value[Symbol.dispose];
17
+ inner = dispose;
18
+ }
19
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
20
+ if (inner) dispose = function() {
21
+ try {
22
+ inner.call(this);
23
+ } catch (e) {
24
+ return Promise.reject(e);
25
+ }
26
+ };
27
+ env.stack.push({
28
+ value: value,
29
+ dispose: dispose,
30
+ async: async
31
+ });
32
+ } else {
33
+ env.stack.push({
34
+ async: true
35
+ });
36
+ }
37
+ return value;
38
+ }
39
+ function _ts_dispose_resources(env) {
40
+ var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
41
+ var e = new Error(message);
42
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
43
+ };
44
+ return (_ts_dispose_resources = function _ts_dispose_resources(env) {
45
+ function fail(e) {
46
+ env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
47
+ env.hasError = true;
48
+ }
49
+ var r, s = 0;
50
+ function next() {
51
+ while(r = env.stack.pop()){
52
+ try {
53
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
54
+ if (r.dispose) {
55
+ var result = r.dispose.call(r.value);
56
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
57
+ fail(e);
58
+ return next();
59
+ });
60
+ } else s |= 1;
61
+ } catch (e) {
62
+ fail(e);
63
+ }
64
+ }
65
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
66
+ if (env.hasError) throw env.error;
67
+ }
68
+ return next();
69
+ })(env);
70
+ }
71
+ function createManagedIterator(iterable, onResult) {
72
+ const iterator = iterable[Symbol.asyncIterator]();
73
+ let state = 'idle';
74
+ function cleanup() {
75
+ state = 'done';
76
+ onResult = ()=>{
77
+ // noop
78
+ };
79
+ }
80
+ function pull() {
81
+ if (state !== 'idle') {
82
+ return;
83
+ }
84
+ state = 'pending';
85
+ const next = iterator.next();
86
+ next.then((result)=>{
87
+ if (result.done) {
88
+ state = 'done';
89
+ onResult({
90
+ status: 'return',
91
+ value: result.value
92
+ });
93
+ cleanup();
94
+ return;
95
+ }
96
+ state = 'idle';
97
+ onResult({
98
+ status: 'yield',
99
+ value: result.value
100
+ });
101
+ }).catch((cause)=>{
102
+ onResult({
103
+ status: 'error',
104
+ error: cause
105
+ });
106
+ cleanup();
107
+ });
108
+ }
109
+ return {
110
+ pull,
111
+ destroy: async ()=>{
112
+ cleanup();
113
+ await iterator.return?.();
114
+ }
115
+ };
116
+ }
117
+ /**
118
+ * Creates a new async iterable that merges multiple async iterables into a single stream.
119
+ * Values from the input iterables are yielded in the order they resolve, similar to Promise.race().
120
+ *
121
+ * New iterables can be added dynamically using the returned {@link MergedAsyncIterables.add} method, even after iteration has started.
122
+ *
123
+ * If any of the input iterables throws an error, that error will be propagated through the merged stream.
124
+ * Other iterables will not continue to be processed.
125
+ *
126
+ * @template TYield The type of values yielded by the input iterables
127
+ */ function mergeAsyncIterables() {
128
+ let state = 'idle';
129
+ let flushSignal = createDeferred.createDeferred();
130
+ /**
131
+ * used while {@link state} is `idle`
132
+ */ const iterables = [];
133
+ /**
134
+ * used while {@link state} is `pending`
135
+ */ const iterators = new Set();
136
+ const buffer = [];
137
+ function initIterable(iterable) {
138
+ if (state !== 'pending') {
139
+ // shouldn't happen
140
+ return;
141
+ }
142
+ const iterator = createManagedIterator(iterable, (result)=>{
143
+ if (state !== 'pending') {
144
+ // shouldn't happen
145
+ return;
146
+ }
147
+ switch(result.status){
148
+ case 'yield':
149
+ buffer.push([
150
+ iterator,
151
+ result
152
+ ]);
153
+ break;
154
+ case 'return':
155
+ iterators.delete(iterator);
156
+ break;
157
+ case 'error':
158
+ buffer.push([
159
+ iterator,
160
+ result
161
+ ]);
162
+ iterators.delete(iterator);
163
+ break;
164
+ }
165
+ flushSignal.resolve();
166
+ });
167
+ iterators.add(iterator);
168
+ iterator.pull();
169
+ }
170
+ return {
171
+ add (iterable) {
172
+ switch(state){
173
+ case 'idle':
174
+ iterables.push(iterable);
175
+ break;
176
+ case 'pending':
177
+ initIterable(iterable);
178
+ break;
179
+ }
180
+ },
181
+ async *[Symbol.asyncIterator] () {
182
+ const env = {
183
+ stack: [],
184
+ error: void 0,
185
+ hasError: false
186
+ };
187
+ try {
188
+ if (state !== 'idle') {
189
+ throw new Error('Cannot iterate twice');
190
+ }
191
+ state = 'pending';
192
+ const _finally = _ts_add_disposable_resource(env, disposable.makeAsyncResource({}, async ()=>{
193
+ state = 'done';
194
+ const errors = [];
195
+ await Promise.all(Array.from(iterators.values()).map(async (it)=>{
196
+ try {
197
+ await it.destroy();
198
+ } catch (cause) {
199
+ errors.push(cause);
200
+ }
201
+ }));
202
+ buffer.length = 0;
203
+ iterators.clear();
204
+ flushSignal.resolve();
205
+ if (errors.length > 0) {
206
+ throw new AggregateError(errors);
207
+ }
208
+ }), true);
209
+ ;
210
+ while(iterables.length > 0){
211
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
212
+ initIterable(iterables.shift());
213
+ }
214
+ while(iterators.size > 0){
215
+ await flushSignal.promise;
216
+ while(buffer.length > 0){
217
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
218
+ const [iterator, result] = buffer.shift();
219
+ switch(result.status){
220
+ case 'yield':
221
+ yield result.value;
222
+ iterator.pull();
223
+ break;
224
+ case 'error':
225
+ throw result.error;
226
+ }
227
+ }
228
+ flushSignal = createDeferred.createDeferred();
229
+ }
230
+ } catch (e) {
231
+ env.error = e;
232
+ env.hasError = true;
233
+ } finally{
234
+ const result = _ts_dispose_resources(env);
235
+ if (result) await result;
236
+ }
237
+ }
238
+ };
239
+ }
240
+
241
+ exports.mergeAsyncIterables = mergeAsyncIterables;