@trpc/server 11.0.0-rc.645 → 11.0.0-rc.657

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 (85) hide show
  1. package/dist/adapters/aws-lambda/index.js +1 -1
  2. package/dist/adapters/aws-lambda/index.mjs +1 -1
  3. package/dist/adapters/express.js +1 -1
  4. package/dist/adapters/express.mjs +1 -1
  5. package/dist/adapters/fastify/fastifyRequestHandler.js +1 -1
  6. package/dist/adapters/fastify/fastifyRequestHandler.mjs +1 -1
  7. package/dist/adapters/fetch/fetchRequestHandler.js +1 -1
  8. package/dist/adapters/fetch/fetchRequestHandler.mjs +1 -1
  9. package/dist/adapters/next-app-dir/nextAppDirCaller.js +1 -1
  10. package/dist/adapters/next-app-dir/nextAppDirCaller.mjs +1 -1
  11. package/dist/adapters/next-app-dir/notFound.js +1 -1
  12. package/dist/adapters/next-app-dir/notFound.mjs +1 -1
  13. package/dist/adapters/next-app-dir/redirect.js +15 -3
  14. package/dist/adapters/next-app-dir/redirect.mjs +14 -2
  15. package/dist/adapters/next.js +1 -1
  16. package/dist/adapters/next.mjs +1 -1
  17. package/dist/adapters/node-http/incomingMessageToRequest.js +1 -1
  18. package/dist/adapters/node-http/incomingMessageToRequest.mjs +1 -1
  19. package/dist/adapters/node-http/nodeHTTPRequestHandler.js +1 -1
  20. package/dist/adapters/node-http/nodeHTTPRequestHandler.mjs +1 -1
  21. package/dist/adapters/node-http/writeResponse.js +1 -1
  22. package/dist/adapters/node-http/writeResponse.mjs +1 -1
  23. package/dist/adapters/standalone.js +1 -1
  24. package/dist/adapters/standalone.mjs +1 -1
  25. package/dist/adapters/ws.d.ts.map +1 -1
  26. package/dist/adapters/ws.js +144 -65
  27. package/dist/adapters/ws.mjs +144 -65
  28. package/dist/bundle-analysis.json +190 -183
  29. package/dist/http.js +1 -1
  30. package/dist/http.mjs +1 -1
  31. package/dist/index.js +1 -1
  32. package/dist/index.mjs +1 -1
  33. package/dist/node_modules/.pnpm/@rollup_plugin-typescript@12.1.1_rollup@4.27.4_tslib@2.8.1_typescript@5.7.2/node_modules/tslib/tslib.es6.js +73 -0
  34. package/dist/rpc.js +1 -1
  35. package/dist/rpc.mjs +1 -1
  36. package/dist/shared.js +1 -1
  37. package/dist/shared.mjs +1 -1
  38. package/dist/unstable-core-do-not-import/error/TRPCError.d.ts +1 -1
  39. package/dist/unstable-core-do-not-import/error/TRPCError.js +14 -2
  40. package/dist/unstable-core-do-not-import/error/TRPCError.mjs +13 -1
  41. package/dist/unstable-core-do-not-import/http/resolveResponse.d.ts.map +1 -1
  42. package/dist/unstable-core-do-not-import/http/resolveResponse.js +3 -9
  43. package/dist/unstable-core-do-not-import/http/resolveResponse.mjs +3 -9
  44. package/dist/unstable-core-do-not-import/middleware.d.ts.map +1 -1
  45. package/dist/unstable-core-do-not-import/stream/jsonl.d.ts +8 -34
  46. package/dist/unstable-core-do-not-import/stream/jsonl.d.ts.map +1 -1
  47. package/dist/unstable-core-do-not-import/stream/jsonl.js +338 -209
  48. package/dist/unstable-core-do-not-import/stream/jsonl.mjs +337 -208
  49. package/dist/unstable-core-do-not-import/stream/sse.d.ts.map +1 -1
  50. package/dist/unstable-core-do-not-import/stream/sse.js +143 -74
  51. package/dist/unstable-core-do-not-import/stream/sse.mjs +144 -75
  52. package/dist/unstable-core-do-not-import/stream/utils/asyncIterable.d.ts +1 -0
  53. package/dist/unstable-core-do-not-import/stream/utils/asyncIterable.d.ts.map +1 -1
  54. package/dist/unstable-core-do-not-import/stream/utils/asyncIterable.js +103 -10
  55. package/dist/unstable-core-do-not-import/stream/utils/asyncIterable.mjs +104 -12
  56. package/dist/unstable-core-do-not-import/stream/utils/disposable.d.ts +17 -0
  57. package/dist/unstable-core-do-not-import/stream/utils/disposable.d.ts.map +1 -0
  58. package/dist/unstable-core-do-not-import/stream/utils/disposable.js +44 -0
  59. package/dist/unstable-core-do-not-import/stream/utils/disposable.mjs +41 -0
  60. package/dist/unstable-core-do-not-import/stream/utils/timerResource.d.ts +1 -2
  61. package/dist/unstable-core-do-not-import/stream/utils/timerResource.d.ts.map +1 -1
  62. package/dist/unstable-core-do-not-import/stream/utils/timerResource.js +8 -10
  63. package/dist/unstable-core-do-not-import/stream/utils/timerResource.mjs +8 -10
  64. package/dist/unstable-core-do-not-import/stream/utils/withPing.d.ts.map +1 -1
  65. package/dist/unstable-core-do-not-import/stream/utils/withPing.js +113 -24
  66. package/dist/unstable-core-do-not-import/stream/utils/withPing.mjs +114 -25
  67. package/dist/unstable-core-do-not-import/transformer.d.ts +1 -1
  68. package/dist/unstable-core-do-not-import.d.ts +1 -0
  69. package/dist/unstable-core-do-not-import.d.ts.map +1 -1
  70. package/dist/unstable-core-do-not-import.js +3 -0
  71. package/dist/unstable-core-do-not-import.mjs +1 -0
  72. package/dist/vendor/unpromise/unpromise.js +17 -6
  73. package/dist/vendor/unpromise/unpromise.mjs +13 -2
  74. package/package.json +3 -4
  75. package/src/adapters/ws.ts +7 -8
  76. package/src/unstable-core-do-not-import/http/resolveResponse.ts +3 -9
  77. package/src/unstable-core-do-not-import/stream/jsonl.ts +128 -153
  78. package/src/unstable-core-do-not-import/stream/sse.ts +64 -79
  79. package/src/unstable-core-do-not-import/stream/utils/asyncIterable.ts +50 -48
  80. package/src/unstable-core-do-not-import/stream/utils/disposable.ts +52 -0
  81. package/src/unstable-core-do-not-import/stream/utils/timerResource.ts +17 -15
  82. package/src/unstable-core-do-not-import/stream/utils/withPing.ts +18 -19
  83. package/src/unstable-core-do-not-import.ts +1 -0
  84. package/dist/node_modules/.pnpm/@swc_helpers@0.5.13/node_modules/@swc/helpers/esm/_define_property.js +0 -11
  85. package/dist/node_modules/.pnpm/@swc_helpers@0.5.13/node_modules/@swc/helpers/esm/_define_property.mjs +0 -9
@@ -1 +1 @@
1
- {"version":3,"file":"unstable-core-do-not-import.d.ts","sourceRoot":"","sources":["../src/unstable-core-do-not-import.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,cAAc,mDAAmD,CAAC;AAClE,cAAc,oDAAoD,CAAC;AACnE,cAAc,mDAAmD,CAAC;AAClE,cAAc,2CAA2C,CAAC;AAC1D,cAAc,+CAA+C,CAAC;AAC9D,cAAc,mDAAmD,CAAC;AAClE,cAAc,+CAA+C,CAAC;AAC9D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,uDAAuD,CAAC;AACtE,cAAc,qDAAqD,CAAC;AACpE,cAAc,sDAAsD,CAAC;AACrE,cAAc,iDAAiD,CAAC;AAChE,cAAc,0DAA0D,CAAC;AACzE,cAAc,oDAAoD,CAAC;AACnE,cAAc,0CAA0C,CAAC;AACzD,cAAc,wCAAwC,CAAC;AACvD,cAAc,0CAA0C,CAAC;AACzD,cAAc,sCAAsC,CAAC;AACrD,cAAc,yCAAyC,CAAC;AACxD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,0CAA0C,CAAC;AACzD,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,0CAA0C,CAAC;AACzD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,2DAA2D,CAAC;AAC1E,cAAc,2CAA2C,CAAC;AAC1D,cAAc,qCAAqC,CAAC;AACpD,cAAc,qCAAqC,CAAC"}
1
+ {"version":3,"file":"unstable-core-do-not-import.d.ts","sourceRoot":"","sources":["../src/unstable-core-do-not-import.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,cAAc,mDAAmD,CAAC;AAClE,cAAc,oDAAoD,CAAC;AACnE,cAAc,mDAAmD,CAAC;AAClE,cAAc,2CAA2C,CAAC;AAC1D,cAAc,+CAA+C,CAAC;AAC9D,cAAc,mDAAmD,CAAC;AAClE,cAAc,+CAA+C,CAAC;AAC9D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,uDAAuD,CAAC;AACtE,cAAc,qDAAqD,CAAC;AACpE,cAAc,sDAAsD,CAAC;AACrE,cAAc,iDAAiD,CAAC;AAChE,cAAc,0DAA0D,CAAC;AACzE,cAAc,oDAAoD,CAAC;AACnE,cAAc,0CAA0C,CAAC;AACzD,cAAc,wCAAwC,CAAC;AACvD,cAAc,0CAA0C,CAAC;AACzD,cAAc,sCAAsC,CAAC;AACrD,cAAc,yCAAyC,CAAC;AACxD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,0CAA0C,CAAC;AACzD,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,0CAA0C,CAAC;AACzD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,2DAA2D,CAAC;AAC1E,cAAc,uDAAuD,CAAC;AACtE,cAAc,2CAA2C,CAAC;AAC1D,cAAc,qCAAqC,CAAC;AACpD,cAAc,qCAAqC,CAAC"}
@@ -24,6 +24,7 @@ var jsonl = require('./unstable-core-do-not-import/stream/jsonl.js');
24
24
  var sse = require('./unstable-core-do-not-import/stream/sse.js');
25
25
  var tracked = require('./unstable-core-do-not-import/stream/tracked.js');
26
26
  var createDeferred = require('./unstable-core-do-not-import/stream/utils/createDeferred.js');
27
+ var disposable = require('./unstable-core-do-not-import/stream/utils/disposable.js');
27
28
  var transformer = require('./unstable-core-do-not-import/transformer.js');
28
29
  var utils = require('./unstable-core-do-not-import/utils.js');
29
30
 
@@ -76,6 +77,8 @@ exports.isTrackedEnvelope = tracked.isTrackedEnvelope;
76
77
  exports.sse = tracked.sse;
77
78
  exports.tracked = tracked.tracked;
78
79
  exports.createDeferred = createDeferred.createDeferred;
80
+ exports.makeAsyncResource = disposable.makeAsyncResource;
81
+ exports.makeResource = disposable.makeResource;
79
82
  exports.defaultTransformer = transformer.defaultTransformer;
80
83
  exports.getDataTransformer = transformer.getDataTransformer;
81
84
  exports.transformResult = transformer.transformResult;
@@ -22,5 +22,6 @@ export { isPromise, jsonlStreamConsumer, jsonlStreamProducer } from './unstable-
22
22
  export { sseHeaders, sseStreamConsumer, sseStreamProducer } from './unstable-core-do-not-import/stream/sse.mjs';
23
23
  export { isTrackedEnvelope, sse, tracked } from './unstable-core-do-not-import/stream/tracked.mjs';
24
24
  export { createDeferred } from './unstable-core-do-not-import/stream/utils/createDeferred.mjs';
25
+ export { makeAsyncResource, makeResource } from './unstable-core-do-not-import/stream/utils/disposable.mjs';
25
26
  export { defaultTransformer, getDataTransformer, transformResult, transformTRPCResponse } from './unstable-core-do-not-import/transformer.mjs';
26
27
  export { abortSignalsAnyPonyfill, assert, identity, isAsyncIterable, isFunction, isObject, mergeWithoutOverrides, noop, omitPrototype, run, sleep, unsetMarker } from './unstable-core-do-not-import/utils.mjs';
@@ -1,7 +1,18 @@
1
1
  'use strict';
2
2
 
3
- var _define_property = require('../../node_modules/.pnpm/@swc_helpers@0.5.13/node_modules/@swc/helpers/esm/_define_property.js');
4
-
3
+ /* eslint-disable @typescript-eslint/unbound-method */ function _define_property(obj, key, value) {
4
+ if (key in obj) {
5
+ Object.defineProperty(obj, key, {
6
+ value: value,
7
+ enumerable: true,
8
+ configurable: true,
9
+ writable: true
10
+ });
11
+ } else {
12
+ obj[key] = value;
13
+ }
14
+ return obj;
15
+ }
5
16
  var _computedKey;
6
17
  /** Memory safe (weakmapped) cache of the ProxyPromise for each Promise,
7
18
  * which is retained for the lifetime of the original Promise.
@@ -188,13 +199,13 @@ let _computedKey1 = _computedKey;
188
199
  }
189
200
  }
190
201
  constructor(arg){
191
- /** INSTANCE IMPLEMENTATION */ /** The promise shadowed by this Unpromise<T> */ _define_property._(this, "promise", void 0);
202
+ /** INSTANCE IMPLEMENTATION */ /** The promise shadowed by this Unpromise<T> */ _define_property(this, "promise", void 0);
192
203
  /** Promises expecting eventual settlement (unless unsubscribed first). This list is deleted
193
- * after the original promise settles - no further notifications will be issued. */ _define_property._(this, "subscribers", []);
204
+ * after the original promise settles - no further notifications will be issued. */ _define_property(this, "subscribers", []);
194
205
  /** The Promise's settlement (recorded when it fulfils or rejects). This is consulted when
195
206
  * calling .subscribe() .then() .catch() .finally() to see if an immediately-resolving Promise
196
- * can be returned, and therefore subscription can be bypassed. */ _define_property._(this, "settlement", null);
197
- /** TOSTRING SUPPORT */ _define_property._(this, _computedKey1, "Unpromise");
207
+ * can be returned, and therefore subscription can be bypassed. */ _define_property(this, "settlement", null);
208
+ /** TOSTRING SUPPORT */ _define_property(this, _computedKey1, "Unpromise");
198
209
  // handle either a Promise or a Promise executor function
199
210
  if (typeof arg === "function") {
200
211
  this.promise = new Promise(arg);
@@ -1,5 +1,16 @@
1
- import { _ as _define_property } from '../../node_modules/.pnpm/@swc_helpers@0.5.13/node_modules/@swc/helpers/esm/_define_property.mjs';
2
-
1
+ /* eslint-disable @typescript-eslint/unbound-method */ function _define_property(obj, key, value) {
2
+ if (key in obj) {
3
+ Object.defineProperty(obj, key, {
4
+ value: value,
5
+ enumerable: true,
6
+ configurable: true,
7
+ writable: true
8
+ });
9
+ } else {
10
+ obj[key] = value;
11
+ }
12
+ return obj;
13
+ }
3
14
  var _computedKey;
4
15
  /** Memory safe (weakmapped) cache of the ProxyPromise for each Promise,
5
16
  * which is retained for the lifetime of the original Promise.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trpc/server",
3
- "version": "11.0.0-rc.645+b25f4f627",
3
+ "version": "11.0.0-rc.657+7a369faa3",
4
4
  "description": "The tRPC server library",
5
5
  "author": "KATT",
6
6
  "license": "MIT",
@@ -139,9 +139,8 @@
139
139
  "rollup": "^4.24.4",
140
140
  "superjson": "^1.12.4",
141
141
  "superstruct": "^2.0.0",
142
- "tslib": "^2.8.1",
143
142
  "tsx": "^4.0.0",
144
- "typescript": "^5.6.2",
143
+ "typescript": "^5.7.0",
145
144
  "valibot": "^0.42.0",
146
145
  "ws": "^8.0.0",
147
146
  "yup": "^1.0.0",
@@ -153,5 +152,5 @@
153
152
  "peerDependencies": {
154
153
  "typescript": ">=5.6.2"
155
154
  },
156
- "gitHead": "b25f4f627ed3ffa6b2180b1b22a629d7486f6f55"
155
+ "gitHead": "7a369faa3db8c59f694397c15f589b72ee0919b5"
157
156
  }
@@ -33,6 +33,8 @@ import {
33
33
  run,
34
34
  type MaybePromise,
35
35
  } from '../unstable-core-do-not-import';
36
+ // eslint-disable-next-line no-restricted-imports
37
+ import { iteratorResource } from '../unstable-core-do-not-import/stream/utils/asyncIterable';
36
38
  import { Unpromise } from '../vendor/unpromise';
37
39
  import { createURL, type NodeHTTPCreateContextFnOptions } from './node-http';
38
40
 
@@ -275,14 +277,12 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
275
277
  ? observableToAsyncIterable(result, abortController.signal)
276
278
  : result;
277
279
 
278
- const iterator: AsyncIterator<unknown> =
279
- iterable[Symbol.asyncIterator]();
280
-
281
- const abortPromise = new Promise<'abort'>((resolve) => {
282
- abortController.signal.onabort = () => resolve('abort');
283
- });
284
-
285
280
  run(async () => {
281
+ await using iterator = iteratorResource(iterable);
282
+
283
+ const abortPromise = new Promise<'abort'>((resolve) => {
284
+ abortController.signal.onabort = () => resolve('abort');
285
+ });
286
286
  // We need those declarations outside the loop for garbage collection reasons. If they
287
287
  // were declared inside, they would not be freed until the next value is present.
288
288
  let next:
@@ -349,7 +349,6 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
349
349
  result = null;
350
350
  }
351
351
 
352
- await iterator.return?.();
353
352
  respond({
354
353
  id,
355
354
  jsonrpc,
@@ -25,15 +25,9 @@ import type {
25
25
  } from './types';
26
26
 
27
27
  function errorToAsyncIterable(err: TRPCError): AsyncIterable<never> {
28
- return {
29
- [Symbol.asyncIterator]: () => {
30
- return {
31
- next() {
32
- throw err;
33
- },
34
- };
35
- },
36
- };
28
+ return run(async function* () {
29
+ throw err;
30
+ });
37
31
  }
38
32
  type HTTPMethods =
39
33
  | 'GET'
@@ -1,7 +1,9 @@
1
1
  import { Unpromise } from '../../vendor/unpromise';
2
2
  import { isAsyncIterable, isFunction, isObject, run } from '../utils';
3
+ import { iteratorResource } from './utils/asyncIterable';
3
4
  import type { Deferred } from './utils/createDeferred';
4
5
  import { createDeferred } from './utils/createDeferred';
6
+ import { makeAsyncResource, makeResource } from './utils/disposable';
5
7
  import { readableStreamFrom } from './utils/readableStreamFrom';
6
8
 
7
9
  /**
@@ -126,10 +128,15 @@ async function* createBatchStreamProducer(
126
128
  let counter = 0 as ChunkIndex;
127
129
  const placeholder = 0 as PlaceholderValue;
128
130
 
129
- const queue = new Set<{
130
- iterator: AsyncIterator<ChunkData, ChunkData>;
131
- nextPromise: Promise<IteratorResult<ChunkData, ChunkData>>;
132
- }>();
131
+ await using queue = makeAsyncResource(
132
+ new Set<{
133
+ iterator: AsyncIterator<ChunkData, ChunkData>;
134
+ nextPromise: Promise<IteratorResult<ChunkData, ChunkData>>;
135
+ }>(),
136
+ async () => {
137
+ await Promise.all(Array.from(queue).map((it) => it.iterator.return?.()));
138
+ },
139
+ );
133
140
  function registerAsync(
134
141
  callback: (idx: ChunkIndex) => AsyncIterable<ChunkData, ChunkData>,
135
142
  ) {
@@ -183,7 +190,7 @@ async function* createBatchStreamProducer(
183
190
  if (error) {
184
191
  throw error;
185
192
  }
186
- const iterator = iterable[Symbol.asyncIterator]();
193
+ await using iterator = iteratorResource(iterable);
187
194
 
188
195
  try {
189
196
  while (true) {
@@ -204,8 +211,6 @@ async function* createBatchStreamProducer(
204
211
  ASYNC_ITERABLE_STATUS_ERROR,
205
212
  opts.formatError?.({ error: cause, path }),
206
213
  ];
207
- } finally {
208
- await iterator.return?.();
209
214
  }
210
215
  });
211
216
  }
@@ -258,37 +263,28 @@ async function* createBatchStreamProducer(
258
263
  return [[newObj], ...asyncValues];
259
264
  }
260
265
 
261
- try {
262
- const newHead: Head = {};
263
- for (const [key, item] of Object.entries(data)) {
264
- newHead[key] = encode(item, [key]);
265
- }
266
+ const newHead: Head = {};
267
+ for (const [key, item] of Object.entries(data)) {
268
+ newHead[key] = encode(item, [key]);
269
+ }
266
270
 
267
- yield newHead;
271
+ yield newHead;
268
272
 
269
- // Process all async iterables in parallel by racing their next values
270
- while (queue.size > 0) {
271
- // Race all iterators to get the next value from any of them
272
- const [entry, res] = await Unpromise.race(
273
- Array.from(queue).map(
274
- async (it) => [it, await it.nextPromise] as const,
275
- ),
276
- );
273
+ // Process all async iterables in parallel by racing their next values
274
+ while (queue.size > 0) {
275
+ // Race all iterators to get the next value from any of them
276
+ const [entry, res] = await Unpromise.race(
277
+ Array.from(queue).map(async (it) => [it, await it.nextPromise] as const),
278
+ );
277
279
 
278
- yield res.value;
280
+ yield res.value;
279
281
 
280
- // Remove current iterator and re-add if not done
281
- queue.delete(entry);
282
- if (!res.done) {
283
- entry.nextPromise = entry.iterator.next();
284
- queue.add(entry);
285
- }
282
+ // Remove current iterator and re-add if not done
283
+ queue.delete(entry);
284
+ if (!res.done) {
285
+ entry.nextPromise = entry.iterator.next();
286
+ queue.add(entry);
286
287
  }
287
- } finally {
288
- // Properly clean up any remaining iterators by calling return()
289
- // Ensures resources are released if the loop exits early (e.g. due to error)
290
- await Promise.all(Array.from(queue).map((it) => it.iterator.return?.()));
291
- queue.clear();
292
288
  }
293
289
  }
294
290
  /**
@@ -419,40 +415,14 @@ function createConsumerStream<THead>(
419
415
  */
420
416
  type ControllerChunk = ChunkData | StreamInterruptedError;
421
417
 
422
- /**
423
- * Interface for a controller that can enqueue chunks and be closed
424
- */
425
- /**
426
- * Interface for controlling a stream's lifecycle and data flow
427
- */
428
- interface StreamController {
429
- /**
430
- * Enqueues a chunk of data or error into the stream
431
- * @param chunk The data chunk or error to enqueue
432
- */
433
- enqueue: (chunk: ControllerChunk) => void;
434
-
435
- /**
436
- * Closes the stream and prevents further data from being enqueued
437
- */
438
- close: () => void;
439
-
440
- /**
441
- * Whether the stream has been closed
442
- */
443
- closed: boolean;
444
-
445
- /**
446
- * Gets a reader for consuming the stream's data
447
- */
448
- getReader: () => ReadableStreamDefaultReader<ControllerChunk>;
449
- }
450
-
451
418
  /**
452
419
  * Creates a handler for managing stream controllers and their lifecycle
453
420
  */
454
421
  function createStreamsManager(abortController: AbortController) {
455
- const controllerMap = new Map<ChunkIndex, StreamController>();
422
+ const controllerMap = new Map<
423
+ ChunkIndex,
424
+ ReturnType<typeof createStreamController>
425
+ >();
456
426
 
457
427
  /**
458
428
  * Checks if there are no pending controllers or deferred promises
@@ -461,63 +431,79 @@ function createStreamsManager(abortController: AbortController) {
461
431
  return Array.from(controllerMap.values()).every((c) => c.closed);
462
432
  }
463
433
 
464
- return {
465
- getOrCreate(chunkId: ChunkIndex): StreamController {
466
- const c = controllerMap.get(chunkId);
467
- if (c) {
468
- return c;
469
- }
434
+ /**
435
+ * Creates a stream controller
436
+ */
437
+ function createStreamController() {
438
+ let originalController: ReadableStreamDefaultController<ControllerChunk>;
439
+ const stream = new ReadableStream<ControllerChunk>({
440
+ start(controller) {
441
+ originalController = controller;
442
+ },
443
+ });
470
444
 
471
- let originalController: ReadableStreamDefaultController<ControllerChunk>;
472
- const stream = new ReadableStream<ControllerChunk>({
473
- start(controller) {
474
- originalController = controller;
475
- },
476
- });
445
+ const streamController = {
446
+ enqueue: (v: ControllerChunk) => originalController.enqueue(v),
447
+ close: () => {
448
+ originalController.close();
449
+
450
+ // mark as closed and remove methods
451
+ Object.assign(streamController, {
452
+ closed: true,
453
+ close: () => {
454
+ // noop
455
+ },
456
+ enqueue: () => {
457
+ // noop
458
+ },
459
+ getReaderResource: null,
460
+ });
477
461
 
478
- const controllerEsque: StreamController = {
479
- enqueue: (v) => originalController.enqueue(v as ChunkData),
480
- close: () => {
481
- originalController.close();
482
-
483
- // mark as closed and remove methods
484
- Object.assign(controllerEsque, {
485
- closed: true,
486
- close: () => {
487
- // noop
488
- },
489
- enqueue: () => {
490
- // noop
491
- },
492
- });
462
+ if (isEmpty()) {
463
+ abortController.abort();
464
+ }
465
+ },
466
+ closed: false,
467
+ getReaderResource: () => {
468
+ const reader = stream.getReader();
493
469
 
494
- if (isEmpty()) {
495
- abortController.abort();
496
- }
497
- },
498
- closed: false,
499
- getReader: () => stream.getReader(),
500
- };
501
- controllerMap.set(chunkId, controllerEsque);
470
+ return makeResource(reader, () => {
471
+ reader.releaseLock();
472
+ streamController.close();
473
+ });
474
+ },
475
+ };
502
476
 
503
- return controllerEsque;
504
- },
477
+ return streamController;
478
+ }
505
479
 
506
- /**
507
- * Check if there are no pending controllers
508
- **/
509
- isEmpty,
480
+ /**
481
+ * Gets or creates a stream controller
482
+ */
483
+ function getOrCreate(chunkId: ChunkIndex) {
484
+ let c = controllerMap.get(chunkId);
485
+ if (!c) {
486
+ c = createStreamController();
487
+ controllerMap.set(chunkId, c);
488
+ }
489
+ return c;
490
+ }
510
491
 
511
- /**
512
- * Cancels all pending controllers and rejects deferred promises
513
- */
514
- cancelAll(reason: unknown) {
515
- const error = new StreamInterruptedError(reason);
516
- for (const controller of controllerMap.values()) {
517
- controller.enqueue(error);
518
- controller.close();
519
- }
520
- },
492
+ /**
493
+ * Cancels all pending controllers and rejects deferred promises
494
+ */
495
+ function cancelAll(reason: unknown) {
496
+ const error = new StreamInterruptedError(reason);
497
+ for (const controller of controllerMap.values()) {
498
+ controller.enqueue(error);
499
+ controller.close();
500
+ }
501
+ }
502
+
503
+ return {
504
+ getOrCreate,
505
+ isEmpty,
506
+ cancelAll,
521
507
  };
522
508
  }
523
509
 
@@ -559,58 +545,47 @@ export async function jsonlStreamConsumer<THead>(opts: {
559
545
  switch (type) {
560
546
  case CHUNK_VALUE_TYPE_PROMISE: {
561
547
  return run(async () => {
562
- const reader = controller.getReader();
563
- try {
548
+ using reader = controller.getReaderResource();
549
+
550
+ const { value } = await reader.read();
551
+ if (value instanceof StreamInterruptedError) {
552
+ throw value;
553
+ }
554
+ const [_chunkId, status, data] = value as PromiseChunk;
555
+ switch (status) {
556
+ case PROMISE_STATUS_FULFILLED:
557
+ return decode(data);
558
+ case PROMISE_STATUS_REJECTED:
559
+ throw opts.formatError?.({ error: data }) ?? new AsyncError(data);
560
+ }
561
+ });
562
+ }
563
+ case CHUNK_VALUE_TYPE_ASYNC_ITERABLE: {
564
+ return run(async function* () {
565
+ using reader = controller.getReaderResource();
566
+
567
+ while (true) {
564
568
  const { value } = await reader.read();
565
569
  if (value instanceof StreamInterruptedError) {
566
570
  throw value;
567
571
  }
568
- const [_chunkId, status, data] = value as PromiseChunk;
572
+
573
+ const [_chunkId, status, data] = value as IterableChunk;
574
+
569
575
  switch (status) {
570
- case PROMISE_STATUS_FULFILLED:
576
+ case ASYNC_ITERABLE_STATUS_YIELD:
577
+ yield decode(data);
578
+ break;
579
+ case ASYNC_ITERABLE_STATUS_RETURN:
571
580
  return decode(data);
572
- case PROMISE_STATUS_REJECTED:
581
+ case ASYNC_ITERABLE_STATUS_ERROR:
573
582
  throw (
574
583
  opts.formatError?.({ error: data }) ?? new AsyncError(data)
575
584
  );
576
585
  }
577
- } finally {
578
- reader.releaseLock();
579
- controller.close();
580
586
  }
581
587
  });
582
588
  }
583
- case CHUNK_VALUE_TYPE_ASYNC_ITERABLE: {
584
- async function* generator() {
585
- const reader = controller.getReader();
586
- try {
587
- while (true) {
588
- const { value } = await reader.read();
589
- if (value instanceof StreamInterruptedError) {
590
- throw value;
591
- }
592
-
593
- const [_chunkId, status, data] = value as IterableChunk;
594
-
595
- switch (status) {
596
- case ASYNC_ITERABLE_STATUS_YIELD:
597
- yield decode(data);
598
- break;
599
- case ASYNC_ITERABLE_STATUS_RETURN:
600
- return decode(data);
601
- case ASYNC_ITERABLE_STATUS_ERROR:
602
- throw (
603
- opts.formatError?.({ error: data }) ?? new AsyncError(data)
604
- );
605
- }
606
- }
607
- } finally {
608
- reader.releaseLock();
609
- controller.close();
610
- }
611
- }
612
- return generator();
613
- }
614
589
  }
615
590
  }
616
591