@trpc/client 10.29.0 → 10.30.0

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 (33) hide show
  1. package/dist/index.js +19 -4
  2. package/dist/index.mjs +19 -4
  3. package/dist/internals/types.d.ts +8 -1
  4. package/dist/internals/types.d.ts.map +1 -1
  5. package/dist/links/HTTPBatchStreamLinkOptions.d.ts +11 -0
  6. package/dist/links/HTTPBatchStreamLinkOptions.d.ts.map +1 -0
  7. package/dist/links/httpBatchLink.d.ts +2 -1
  8. package/dist/links/httpBatchLink.d.ts.map +1 -1
  9. package/dist/links/httpBatchStreamLink.d.ts +2 -1
  10. package/dist/links/httpBatchStreamLink.d.ts.map +1 -1
  11. package/dist/links/index.d.ts +1 -0
  12. package/dist/links/index.d.ts.map +1 -1
  13. package/dist/links/internals/createHTTPBatchLink.d.ts +3 -3
  14. package/dist/links/internals/createHTTPBatchLink.d.ts.map +1 -1
  15. package/dist/links/internals/getTextDecoder.d.ts +3 -0
  16. package/dist/links/internals/getTextDecoder.d.ts.map +1 -0
  17. package/dist/links/internals/httpUtils.d.ts +2 -0
  18. package/dist/links/internals/httpUtils.d.ts.map +1 -1
  19. package/dist/links/internals/parseJSONStream.d.ts +5 -1
  20. package/dist/links/internals/parseJSONStream.d.ts.map +1 -1
  21. package/dist/links/internals/streamingUtils.d.ts +7 -0
  22. package/dist/links/internals/streamingUtils.d.ts.map +1 -0
  23. package/package.json +5 -5
  24. package/src/internals/types.ts +9 -1
  25. package/src/links/HTTPBatchStreamLinkOptions.ts +11 -0
  26. package/src/links/httpBatchLink.ts +2 -1
  27. package/src/links/httpBatchStreamLink.ts +7 -1
  28. package/src/links/index.ts +1 -0
  29. package/src/links/internals/createHTTPBatchLink.ts +6 -4
  30. package/src/links/internals/getTextDecoder.ts +19 -0
  31. package/src/links/internals/httpUtils.ts +2 -0
  32. package/src/links/internals/parseJSONStream.ts +11 -8
  33. package/src/links/internals/streamingUtils.ts +6 -0
package/dist/index.js CHANGED
@@ -163,6 +163,19 @@ function createTRPCProxyClient(opts) {
163
163
  return proxy;
164
164
  }
165
165
 
166
+ function getTextDecoder(customTextDecoder) {
167
+ if (customTextDecoder) {
168
+ return customTextDecoder;
169
+ }
170
+ if (typeof window !== 'undefined' && window.TextDecoder) {
171
+ return new window.TextDecoder();
172
+ }
173
+ if (typeof globalThis !== 'undefined' && globalThis.TextDecoder) {
174
+ return new globalThis.TextDecoder();
175
+ }
176
+ throw new Error('No TextDecoder implementation found');
177
+ }
178
+
166
179
  // Stream parsing adapted from https://www.loginradius.com/blog/engineering/guest-post/http-streaming-with-nodejs-and-fetch-api/
167
180
  /**
168
181
  * @internal
@@ -190,9 +203,8 @@ function createTRPCProxyClient(opts) {
190
203
  const text = line.substring(indexOfColon + 1);
191
204
  opts.onSingle(Number(indexAsStr), parse(text));
192
205
  };
193
- await readLines(opts.readableStream, onLine);
206
+ await readLines(opts.readableStream, onLine, opts.textDecoder);
194
207
  }
195
- const textDecoder = new TextDecoder();
196
208
  /**
197
209
  * Handle transforming a stream of bytes into lines of text.
198
210
  * To avoid using AsyncIterators / AsyncGenerators,
@@ -200,7 +212,7 @@ const textDecoder = new TextDecoder();
200
212
  *
201
213
  * @param readableStream can be a NodeJS stream or a WebAPI stream
202
214
  * @param onLine will be called for every line ('\n' delimited) in the stream
203
- */ async function readLines(readableStream, onLine) {
215
+ */ async function readLines(readableStream, onLine, textDecoder) {
204
216
  let partOfLine = '';
205
217
  const onChunk = (chunk)=>{
206
218
  const chunkText = textDecoder.decode(chunk);
@@ -266,7 +278,8 @@ const streamingJsonHttpRequester = (opts, onSingle)=>{
266
278
  json: JSON.parse(string),
267
279
  meta
268
280
  }),
269
- signal: ac?.signal
281
+ signal: ac?.signal,
282
+ textDecoder: opts.textDecoder
270
283
  });
271
284
  });
272
285
  return {
@@ -276,11 +289,13 @@ const streamingJsonHttpRequester = (opts, onSingle)=>{
276
289
  };
277
290
 
278
291
  const streamRequester = (requesterOpts)=>{
292
+ const textDecoder = getTextDecoder(requesterOpts.opts.textDecoder);
279
293
  return (batchOps, unitResolver)=>{
280
294
  const path = batchOps.map((op)=>op.path).join(',');
281
295
  const inputs = batchOps.map((op)=>op.input);
282
296
  const { cancel , promise } = streamingJsonHttpRequester({
283
297
  ...requesterOpts,
298
+ textDecoder,
284
299
  path,
285
300
  inputs,
286
301
  headers () {
package/dist/index.mjs CHANGED
@@ -164,6 +164,19 @@ function createTRPCProxyClient(opts) {
164
164
  return proxy;
165
165
  }
166
166
 
167
+ function getTextDecoder(customTextDecoder) {
168
+ if (customTextDecoder) {
169
+ return customTextDecoder;
170
+ }
171
+ if (typeof window !== 'undefined' && window.TextDecoder) {
172
+ return new window.TextDecoder();
173
+ }
174
+ if (typeof globalThis !== 'undefined' && globalThis.TextDecoder) {
175
+ return new globalThis.TextDecoder();
176
+ }
177
+ throw new Error('No TextDecoder implementation found');
178
+ }
179
+
167
180
  // Stream parsing adapted from https://www.loginradius.com/blog/engineering/guest-post/http-streaming-with-nodejs-and-fetch-api/
168
181
  /**
169
182
  * @internal
@@ -191,9 +204,8 @@ function createTRPCProxyClient(opts) {
191
204
  const text = line.substring(indexOfColon + 1);
192
205
  opts.onSingle(Number(indexAsStr), parse(text));
193
206
  };
194
- await readLines(opts.readableStream, onLine);
207
+ await readLines(opts.readableStream, onLine, opts.textDecoder);
195
208
  }
196
- const textDecoder = new TextDecoder();
197
209
  /**
198
210
  * Handle transforming a stream of bytes into lines of text.
199
211
  * To avoid using AsyncIterators / AsyncGenerators,
@@ -201,7 +213,7 @@ const textDecoder = new TextDecoder();
201
213
  *
202
214
  * @param readableStream can be a NodeJS stream or a WebAPI stream
203
215
  * @param onLine will be called for every line ('\n' delimited) in the stream
204
- */ async function readLines(readableStream, onLine) {
216
+ */ async function readLines(readableStream, onLine, textDecoder) {
205
217
  let partOfLine = '';
206
218
  const onChunk = (chunk)=>{
207
219
  const chunkText = textDecoder.decode(chunk);
@@ -267,7 +279,8 @@ const streamingJsonHttpRequester = (opts, onSingle)=>{
267
279
  json: JSON.parse(string),
268
280
  meta
269
281
  }),
270
- signal: ac?.signal
282
+ signal: ac?.signal,
283
+ textDecoder: opts.textDecoder
271
284
  });
272
285
  });
273
286
  return {
@@ -277,11 +290,13 @@ const streamingJsonHttpRequester = (opts, onSingle)=>{
277
290
  };
278
291
 
279
292
  const streamRequester = (requesterOpts)=>{
293
+ const textDecoder = getTextDecoder(requesterOpts.opts.textDecoder);
280
294
  return (batchOps, unitResolver)=>{
281
295
  const path = batchOps.map((op)=>op.path).join(',');
282
296
  const inputs = batchOps.map((op)=>op.input);
283
297
  const { cancel , promise } = streamingJsonHttpRequester({
284
298
  ...requesterOpts,
299
+ textDecoder,
285
300
  path,
286
301
  inputs,
287
302
  headers () {
@@ -57,12 +57,19 @@ export interface RequestInitEsque {
57
57
  */
58
58
  signal?: AbortSignal | null;
59
59
  }
60
+ /**
61
+ * A subset of the standard ReadableStream properties needed by tRPC internally.
62
+ * @see ReadableStream from lib.dom.d.ts
63
+ */
64
+ export type WebReadableStreamEsque = {
65
+ getReader: () => ReadableStreamDefaultReader<Uint8Array>;
66
+ };
60
67
  /**
61
68
  * A subset of the standard Response properties needed by tRPC internally.
62
69
  * @see Response from lib.dom.d.ts
63
70
  */
64
71
  export interface ResponseEsque {
65
- readonly body?: ReadableStream<Uint8Array> | NodeJS.ReadableStream | null;
72
+ readonly body?: WebReadableStreamEsque | NodeJS.ReadableStream | null;
66
73
  /**
67
74
  * @remarks
68
75
  * The built-in Response::json() method returns Promise<any>, but
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/internals/types.ts"],"names":[],"mappings":";AAAA,MAAM,WAAW,oBAAoB;IACnC,QAAQ,4BAA4B,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAE7B;;;OAGG;IACH,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,CACvB,KAAK,EAAE,WAAW,GAAG,GAAG,GAAG,MAAM,EACjC,IAAI,CAAC,EAAE,WAAW,GAAG,gBAAgB,KAClC,OAAO,CAAC,aAAa,CAAC,CAAC;AAE5B;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,GAAG,EAAE,MAAM,GAAG,GAAG,EACjB,IAAI,CAAC,EAAE,yBAAyB,KAC7B,OAAO,CAAC,aAAa,CAAC,CAAC;AAE5B,MAAM,WAAW,yBAAyB;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,QAAQ,GAAG,IAAI,CAAC;IAEjD;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEtD;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC;IAC1E;;;;;OAKG;IACH,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,CAAC,KAAK,IAAI,CAAC,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/internals/types.ts"],"names":[],"mappings":";AAAA,MAAM,WAAW,oBAAoB;IACnC,QAAQ,4BAA4B,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAE7B;;;OAGG;IACH,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,CACvB,KAAK,EAAE,WAAW,GAAG,GAAG,GAAG,MAAM,EACjC,IAAI,CAAC,EAAE,WAAW,GAAG,gBAAgB,KAClC,OAAO,CAAC,aAAa,CAAC,CAAC;AAE5B;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,GAAG,EAAE,MAAM,GAAG,GAAG,EACjB,IAAI,CAAC,EAAE,yBAAyB,KAC7B,OAAO,CAAC,aAAa,CAAC,CAAC;AAE5B,MAAM,WAAW,yBAAyB;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,QAAQ,GAAG,IAAI,CAAC;IAEjD;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEtD;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,MAAM,2BAA2B,CAAC,UAAU,CAAC,CAAC;CAC1D,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,sBAAsB,GAAG,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC;IACtE;;;;;OAKG;IACH,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,CAAC,KAAK,IAAI,CAAC,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { HTTPBatchLinkOptions } from './HTTPBatchLinkOptions';
2
+ import { TextDecoderEsque } from './internals/streamingUtils';
3
+ export interface HTTPBatchStreamLinkOptions extends HTTPBatchLinkOptions {
4
+ /**
5
+ * Will default to the webAPI `TextDecoder`,
6
+ * but you can use this option if your client
7
+ * runtime doesn't provide it.
8
+ */
9
+ textDecoder?: TextDecoderEsque;
10
+ }
11
+ //# sourceMappingURL=HTTPBatchStreamLinkOptions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HTTPBatchStreamLinkOptions.d.ts","sourceRoot":"","sources":["../../src/links/HTTPBatchStreamLinkOptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAE9D,MAAM,WAAW,0BAA2B,SAAQ,oBAAoB;IACtE;;;;OAIG;IACH,WAAW,CAAC,EAAE,gBAAgB,CAAC;CAChC"}
@@ -1,2 +1,3 @@
1
- export declare const httpBatchLink: <TRouter extends import("@trpc/server").AnyRouter>(opts: import("./HTTPBatchLinkOptions").HTTPBatchLinkOptions) => import("./types").TRPCLink<TRouter>;
1
+ import { HTTPBatchLinkOptions } from './HTTPBatchLinkOptions';
2
+ export declare const httpBatchLink: <TRouter extends import("@trpc/server").AnyRouter>(opts: HTTPBatchLinkOptions) => import("./types").TRPCLink<TRouter>;
2
3
  //# sourceMappingURL=httpBatchLink.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"httpBatchLink.d.ts","sourceRoot":"","sources":["../../src/links/httpBatchLink.ts"],"names":[],"mappings":"AAgDA,eAAO,MAAM,aAAa,wJAAsC,CAAC"}
1
+ {"version":3,"file":"httpBatchLink.d.ts","sourceRoot":"","sources":["../../src/links/httpBatchLink.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAgD9D,eAAO,MAAM,aAAa,uHAAsC,CAAC"}
@@ -1,2 +1,3 @@
1
- export declare const unstable_httpBatchStreamLink: <TRouter extends import("@trpc/server").AnyRouter>(opts: import("./HTTPBatchLinkOptions").HTTPBatchLinkOptions) => import("./types").TRPCLink<TRouter>;
1
+ import { HTTPBatchStreamLinkOptions } from './HTTPBatchStreamLinkOptions';
2
+ export declare const unstable_httpBatchStreamLink: <TRouter extends import("@trpc/server").AnyRouter>(opts: HTTPBatchStreamLinkOptions) => import("./types").TRPCLink<TRouter>;
2
3
  //# sourceMappingURL=httpBatchStreamLink.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"httpBatchStreamLink.d.ts","sourceRoot":"","sources":["../../src/links/httpBatchStreamLink.ts"],"names":[],"mappings":"AA6CA,eAAO,MAAM,4BAA4B,wJACH,CAAC"}
1
+ {"version":3,"file":"httpBatchStreamLink.d.ts","sourceRoot":"","sources":["../../src/links/httpBatchStreamLink.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAkD1E,eAAO,MAAM,4BAA4B,6HACH,CAAC"}
@@ -2,6 +2,7 @@ export * from './types';
2
2
  export * from './httpBatchLink';
3
3
  export * from './httpBatchStreamLink';
4
4
  export * from './HTTPBatchLinkOptions';
5
+ export * from './HTTPBatchStreamLinkOptions';
5
6
  export * from './httpLink';
6
7
  export * from './loggerLink';
7
8
  export * from './splitLink';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/links/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AAExB,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/links/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AAExB,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,oBAAoB,CAAC"}
@@ -5,10 +5,10 @@ import { HTTPResult, ResolvedHTTPLinkOptions } from './httpUtils';
5
5
  /**
6
6
  * @internal
7
7
  */
8
- export type RequesterFn = (requesterOpts: ResolvedHTTPLinkOptions & {
8
+ export type RequesterFn<TOptions extends HTTPBatchLinkOptions> = (requesterOpts: ResolvedHTTPLinkOptions & {
9
9
  runtime: TRPCClientRuntime;
10
10
  type: ProcedureType;
11
- opts: HTTPBatchLinkOptions;
11
+ opts: TOptions;
12
12
  }) => (batchOps: Operation[], unitResolver: (index: number, value: NonNullable<HTTPResult>) => void) => {
13
13
  promise: Promise<HTTPResult[]>;
14
14
  cancel: CancelFn;
@@ -16,5 +16,5 @@ export type RequesterFn = (requesterOpts: ResolvedHTTPLinkOptions & {
16
16
  /**
17
17
  * @internal
18
18
  */
19
- export declare function createHTTPBatchLink(requester: RequesterFn): <TRouter extends AnyRouter>(opts: HTTPBatchLinkOptions) => TRPCLink<TRouter>;
19
+ export declare function createHTTPBatchLink<TOptions extends HTTPBatchLinkOptions>(requester: RequesterFn<TOptions>): <TRouter extends AnyRouter>(opts: TOptions) => TRPCLink<TRouter>;
20
20
  //# sourceMappingURL=createHTTPBatchLink.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createHTTPBatchLink.d.ts","sourceRoot":"","sources":["../../../src/links/internals/createHTTPBatchLink.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAKxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC5E,OAAO,EAEL,UAAU,EACV,uBAAuB,EAExB,MAAM,aAAa,CAAC;AAErB;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,CACxB,aAAa,EAAE,uBAAuB,GAAG;IACvC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,oBAAoB,CAAC;CAC5B,KACE,CACH,QAAQ,EAAE,SAAS,EAAE,EACrB,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,UAAU,CAAC,KAAK,IAAI,KAClE;IACH,OAAO,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAC/B,MAAM,EAAE,QAAQ,CAAC;CAClB,CAAC;AAEF;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,WAAW,qCAEhD,oBAAoB,uBA4E7B"}
1
+ {"version":3,"file":"createHTTPBatchLink.d.ts","sourceRoot":"","sources":["../../../src/links/internals/createHTTPBatchLink.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAKxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC5E,OAAO,EAEL,UAAU,EACV,uBAAuB,EAExB,MAAM,aAAa,CAAC;AAErB;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,QAAQ,SAAS,oBAAoB,IAAI,CAC/D,aAAa,EAAE,uBAAuB,GAAG;IACvC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,QAAQ,CAAC;CAChB,KACE,CACH,QAAQ,EAAE,SAAS,EAAE,EACrB,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,UAAU,CAAC,KAAK,IAAI,KAClE;IACH,OAAO,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAC/B,MAAM,EAAE,QAAQ,CAAC;CAClB,CAAC;AAEF;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,SAAS,oBAAoB,EACvE,SAAS,EAAE,WAAW,CAAC,QAAQ,CAAC,qCAGxB,QAAQ,uBA4EjB"}
@@ -0,0 +1,3 @@
1
+ import { TextDecoderEsque } from './streamingUtils';
2
+ export declare function getTextDecoder(customTextDecoder?: TextDecoderEsque): TextDecoderEsque;
3
+ //# sourceMappingURL=getTextDecoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getTextDecoder.d.ts","sourceRoot":"","sources":["../../../src/links/internals/getTextDecoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,wBAAgB,cAAc,CAC5B,iBAAiB,CAAC,EAAE,gBAAgB,GACnC,gBAAgB,CAclB"}
@@ -1,6 +1,7 @@
1
1
  import { ProcedureType } from '@trpc/server';
2
2
  import { TRPCResponse } from '@trpc/server/rpc';
3
3
  import { AbortControllerEsque, AbortControllerInstanceEsque, FetchEsque, RequestInitEsque, ResponseEsque } from '../../internals/types';
4
+ import { TextDecoderEsque } from '../internals/streamingUtils';
4
5
  import { HTTPHeaders, PromiseAndCancel, TRPCClientRuntime } from '../types';
5
6
  /**
6
7
  * @internal
@@ -55,6 +56,7 @@ export type Requester = (opts: HTTPBaseRequestOptions & {
55
56
  export declare const jsonHttpRequester: Requester;
56
57
  export type HTTPRequestOptions = HTTPBaseRequestOptions & ContentOptions & {
57
58
  headers: () => HTTPHeaders | Promise<HTTPHeaders>;
59
+ TextDecoder?: TextDecoderEsque;
58
60
  };
59
61
  export declare function fetchHTTPResponse(opts: HTTPRequestOptions, ac?: AbortControllerInstanceEsque | null): Promise<ResponseEsque>;
60
62
  export declare function httpRequest(opts: HTTPRequestOptions): PromiseAndCancel<HTTPResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"httpUtils.d.ts","sourceRoot":"","sources":["../../../src/links/internals/httpUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGhD,OAAO,EACL,oBAAoB,EACpB,4BAA4B,EAC5B,UAAU,EACV,gBAAgB,EAChB,aAAa,EACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE5E;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB;;OAEG;IACH,eAAe,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;CAC/C;AAED,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,UAAU,CAAC;IAClB,eAAe,EAAE,oBAAoB,GAAG,IAAI,CAAC;CAC9C;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,mBAAmB,GACxB,uBAAuB,CAMzB;AAiBD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE;QACJ,QAAQ,EAAE,aAAa,CAAC;KACzB,CAAC;CACH;AAED,KAAK,eAAe,GAAG;IACrB,OAAO,EAAE,iBAAiB,CAAC;CAC5B,GAAG,CAAC;IAAE,MAAM,EAAE,OAAO,EAAE,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAUjD,MAAM,MAAM,sBAAsB,GAAG,uBAAuB,GAC1D,eAAe,GAAG;IAChB,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEJ,MAAM,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,sBAAsB,KAAK,MAAM,CAAC;AAC9D,MAAM,MAAM,OAAO,GAAG,CACpB,IAAI,EAAE,sBAAsB,KACzB,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAE9B,MAAM,MAAM,cAAc,GAAG;IAC3B,eAAe,CAAC,EAAE,QAAQ,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,MAgBpB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,OAMrB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,CACtB,IAAI,EAAE,sBAAsB,GAAG;IAC7B,OAAO,EAAE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACnD,KACE,gBAAgB,CAAC,UAAU,CAAC,CAAC;AAElC,eAAO,MAAM,iBAAiB,EAAE,SAO/B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,GACrD,cAAc,GAAG;IACf,OAAO,EAAE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACnD,CAAC;AAEJ,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,kBAAkB,EACxB,EAAE,CAAC,EAAE,4BAA4B,GAAG,IAAI,0BAyBzC;AAED,wBAAgB,WAAW,CACzB,IAAI,EAAE,kBAAkB,GACvB,gBAAgB,CAAC,UAAU,CAAC,CAsB9B"}
1
+ {"version":3,"file":"httpUtils.d.ts","sourceRoot":"","sources":["../../../src/links/internals/httpUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGhD,OAAO,EACL,oBAAoB,EACpB,4BAA4B,EAC5B,UAAU,EACV,gBAAgB,EAChB,aAAa,EACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE5E;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB;;OAEG;IACH,eAAe,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;CAC/C;AAED,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,UAAU,CAAC;IAClB,eAAe,EAAE,oBAAoB,GAAG,IAAI,CAAC;CAC9C;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,mBAAmB,GACxB,uBAAuB,CAMzB;AAiBD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE;QACJ,QAAQ,EAAE,aAAa,CAAC;KACzB,CAAC;CACH;AAED,KAAK,eAAe,GAAG;IACrB,OAAO,EAAE,iBAAiB,CAAC;CAC5B,GAAG,CAAC;IAAE,MAAM,EAAE,OAAO,EAAE,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAUjD,MAAM,MAAM,sBAAsB,GAAG,uBAAuB,GAC1D,eAAe,GAAG;IAChB,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEJ,MAAM,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,sBAAsB,KAAK,MAAM,CAAC;AAC9D,MAAM,MAAM,OAAO,GAAG,CACpB,IAAI,EAAE,sBAAsB,KACzB,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAE9B,MAAM,MAAM,cAAc,GAAG;IAC3B,eAAe,CAAC,EAAE,QAAQ,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,MAgBpB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,OAMrB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,CACtB,IAAI,EAAE,sBAAsB,GAAG;IAC7B,OAAO,EAAE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACnD,KACE,gBAAgB,CAAC,UAAU,CAAC,CAAC;AAElC,eAAO,MAAM,iBAAiB,EAAE,SAO/B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,GACrD,cAAc,GAAG;IACf,OAAO,EAAE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAClD,WAAW,CAAC,EAAE,gBAAgB,CAAC;CAChC,CAAC;AAEJ,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,kBAAkB,EACxB,EAAE,CAAC,EAAE,4BAA4B,GAAG,IAAI,0BAyBzC;AAED,wBAAgB,WAAW,CACzB,IAAI,EAAE,kBAAkB,GACvB,gBAAgB,CAAC,UAAU,CAAC,CAsB9B"}
@@ -1,6 +1,8 @@
1
1
  /// <reference types="node" />
2
+ import { WebReadableStreamEsque } from '../../internals/types';
2
3
  import { HTTPHeaders } from '../types';
3
4
  import { HTTPBaseRequestOptions, HTTPResult } from './httpUtils';
5
+ import { TextDecoderEsque } from './streamingUtils';
4
6
  /**
5
7
  * @internal
6
8
  * @description Take a stream of bytes and call `onLine` with
@@ -16,7 +18,7 @@ export declare function parseJSONStream<TReturn>(opts: {
16
18
  /**
17
19
  * As given by `(await fetch(url)).body`
18
20
  */
19
- readableStream: ReadableStream<Uint8Array> | NodeJS.ReadableStream;
21
+ readableStream: WebReadableStreamEsque | NodeJS.ReadableStream;
20
22
  /**
21
23
  * Called for each line of the stream
22
24
  */
@@ -26,9 +28,11 @@ export declare function parseJSONStream<TReturn>(opts: {
26
28
  */
27
29
  parse?: (text: string) => TReturn;
28
30
  signal?: AbortSignal;
31
+ textDecoder: TextDecoderEsque;
29
32
  }): Promise<void>;
30
33
  export declare const streamingJsonHttpRequester: (opts: HTTPBaseRequestOptions & {
31
34
  headers: () => HTTPHeaders | Promise<HTTPHeaders>;
35
+ textDecoder: TextDecoderEsque;
32
36
  }, onSingle: (index: number, res: HTTPResult) => void) => {
33
37
  cancel: () => void | undefined;
34
38
  promise: Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"parseJSONStream.d.ts","sourceRoot":"","sources":["../../../src/links/internals/parseJSONStream.ts"],"names":[],"mappings":";AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAIL,sBAAsB,EACtB,UAAU,EACX,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,IAAI,EAAE;IACnD;;OAEG;IACH,cAAc,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,MAAM,CAAC,cAAc,CAAC;IACnE;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD;;OAEG;IACH,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAClC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBhB;AAyED,eAAO,MAAM,0BAA0B,SAC/B,sBAAsB,GAAG;IAC7B,OAAO,EAAE,MAAM,WAAW,GAAG,QAAQ,WAAW,CAAC,CAAC;CACnD,oBACiB,MAAM,OAAO,UAAU,KAAK,IAAI;;;CA6BnD,CAAC"}
1
+ {"version":3,"file":"parseJSONStream.d.ts","sourceRoot":"","sources":["../../../src/links/internals/parseJSONStream.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAIL,sBAAsB,EACtB,UAAU,EACX,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,IAAI,EAAE;IACnD;;OAEG;IACH,cAAc,EAAE,sBAAsB,GAAG,MAAM,CAAC,cAAc,CAAC;IAC/D;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD;;OAEG;IACH,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAClC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,WAAW,EAAE,gBAAgB,CAAC;CAC/B,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBhB;AAwED,eAAO,MAAM,0BAA0B,SAC/B,sBAAsB,GAAG;IAC7B,OAAO,EAAE,MAAM,WAAW,GAAG,QAAQ,WAAW,CAAC,CAAC;IAClD,WAAW,EAAE,gBAAgB,CAAC;CAC/B,oBACiB,MAAM,OAAO,UAAU,KAAK,IAAI;;;CA8BnD,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @internal
3
+ */
4
+ export interface TextDecoderEsque {
5
+ decode(chunk: Uint8Array): string;
6
+ }
7
+ //# sourceMappingURL=streamingUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamingUtils.d.ts","sourceRoot":"","sources":["../../../src/links/internals/streamingUtils.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAAC;CACnC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trpc/client",
3
- "version": "10.29.0",
3
+ "version": "10.30.0",
4
4
  "description": "The tRPC client library",
5
5
  "author": "KATT",
6
6
  "license": "MIT",
@@ -76,11 +76,11 @@
76
76
  "!**/*.test.*"
77
77
  ],
78
78
  "peerDependencies": {
79
- "@trpc/server": "10.29.0"
79
+ "@trpc/server": "10.30.0"
80
80
  },
81
81
  "devDependencies": {
82
82
  "@testing-library/dom": "^9.0.0",
83
- "@trpc/server": "10.29.0",
83
+ "@trpc/server": "10.30.0",
84
84
  "@types/isomorphic-fetch": "^0.0.36",
85
85
  "@types/node": "^18.16.16",
86
86
  "eslint": "^8.40.0",
@@ -90,7 +90,7 @@
90
90
  "rollup": "^2.79.1",
91
91
  "tsx": "^3.12.7",
92
92
  "undici": "^5.14.0",
93
- "vitest": "^0.28.5"
93
+ "vitest": "^0.32.0"
94
94
  },
95
95
  "publishConfig": {
96
96
  "access": "public"
@@ -98,5 +98,5 @@
98
98
  "funding": [
99
99
  "https://trpc.io/sponsor"
100
100
  ],
101
- "gitHead": "49b0a55b74b57bbf7451dad5976d315d9fb7785c"
101
+ "gitHead": "a841051a4deb9428acee54e98798e8c2402a0a35"
102
102
  }
@@ -72,12 +72,20 @@ export interface RequestInitEsque {
72
72
  signal?: AbortSignal | null;
73
73
  }
74
74
 
75
+ /**
76
+ * A subset of the standard ReadableStream properties needed by tRPC internally.
77
+ * @see ReadableStream from lib.dom.d.ts
78
+ */
79
+ export type WebReadableStreamEsque = {
80
+ getReader: () => ReadableStreamDefaultReader<Uint8Array>;
81
+ };
82
+
75
83
  /**
76
84
  * A subset of the standard Response properties needed by tRPC internally.
77
85
  * @see Response from lib.dom.d.ts
78
86
  */
79
87
  export interface ResponseEsque {
80
- readonly body?: ReadableStream<Uint8Array> | NodeJS.ReadableStream | null;
88
+ readonly body?: WebReadableStreamEsque | NodeJS.ReadableStream | null;
81
89
  /**
82
90
  * @remarks
83
91
  * The built-in Response::json() method returns Promise<any>, but
@@ -0,0 +1,11 @@
1
+ import { HTTPBatchLinkOptions } from './HTTPBatchLinkOptions';
2
+ import { TextDecoderEsque } from './internals/streamingUtils';
3
+
4
+ export interface HTTPBatchStreamLinkOptions extends HTTPBatchLinkOptions {
5
+ /**
6
+ * Will default to the webAPI `TextDecoder`,
7
+ * but you can use this option if your client
8
+ * runtime doesn't provide it.
9
+ */
10
+ textDecoder?: TextDecoderEsque;
11
+ }
@@ -1,4 +1,5 @@
1
1
  import { NonEmptyArray } from '../internals/types';
2
+ import { HTTPBatchLinkOptions } from './HTTPBatchLinkOptions';
2
3
  import {
3
4
  createHTTPBatchLink,
4
5
  RequesterFn,
@@ -6,7 +7,7 @@ import {
6
7
  import { jsonHttpRequester } from './internals/httpUtils';
7
8
  import { Operation } from './types';
8
9
 
9
- const batchRequester: RequesterFn = (requesterOpts) => {
10
+ const batchRequester: RequesterFn<HTTPBatchLinkOptions> = (requesterOpts) => {
10
11
  return (batchOps) => {
11
12
  const path = batchOps.map((op) => op.path).join(',');
12
13
  const inputs = batchOps.map((op) => op.input);
@@ -1,12 +1,17 @@
1
1
  import { NonEmptyArray } from '../internals/types';
2
+ import { HTTPBatchStreamLinkOptions } from './HTTPBatchStreamLinkOptions';
2
3
  import {
3
4
  createHTTPBatchLink,
4
5
  RequesterFn,
5
6
  } from './internals/createHTTPBatchLink';
7
+ import { getTextDecoder } from './internals/getTextDecoder';
6
8
  import { streamingJsonHttpRequester } from './internals/parseJSONStream';
7
9
  import { Operation } from './types';
8
10
 
9
- const streamRequester: RequesterFn = (requesterOpts) => {
11
+ const streamRequester: RequesterFn<HTTPBatchStreamLinkOptions> = (
12
+ requesterOpts,
13
+ ) => {
14
+ const textDecoder = getTextDecoder(requesterOpts.opts.textDecoder);
10
15
  return (batchOps, unitResolver) => {
11
16
  const path = batchOps.map((op) => op.path).join(',');
12
17
  const inputs = batchOps.map((op) => op.input);
@@ -14,6 +19,7 @@ const streamRequester: RequesterFn = (requesterOpts) => {
14
19
  const { cancel, promise } = streamingJsonHttpRequester(
15
20
  {
16
21
  ...requesterOpts,
22
+ textDecoder,
17
23
  path,
18
24
  inputs,
19
25
  headers() {
@@ -3,6 +3,7 @@ export * from './types';
3
3
  export * from './httpBatchLink';
4
4
  export * from './httpBatchStreamLink';
5
5
  export * from './HTTPBatchLinkOptions';
6
+ export * from './HTTPBatchStreamLinkOptions';
6
7
  export * from './httpLink';
7
8
  export * from './loggerLink';
8
9
  export * from './splitLink';
@@ -15,11 +15,11 @@ import {
15
15
  /**
16
16
  * @internal
17
17
  */
18
- export type RequesterFn = (
18
+ export type RequesterFn<TOptions extends HTTPBatchLinkOptions> = (
19
19
  requesterOpts: ResolvedHTTPLinkOptions & {
20
20
  runtime: TRPCClientRuntime;
21
21
  type: ProcedureType;
22
- opts: HTTPBatchLinkOptions;
22
+ opts: TOptions;
23
23
  },
24
24
  ) => (
25
25
  batchOps: Operation[],
@@ -32,9 +32,11 @@ export type RequesterFn = (
32
32
  /**
33
33
  * @internal
34
34
  */
35
- export function createHTTPBatchLink(requester: RequesterFn) {
35
+ export function createHTTPBatchLink<TOptions extends HTTPBatchLinkOptions>(
36
+ requester: RequesterFn<TOptions>,
37
+ ) {
36
38
  return function httpBatchLink<TRouter extends AnyRouter>(
37
- opts: HTTPBatchLinkOptions,
39
+ opts: TOptions,
38
40
  ): TRPCLink<TRouter> {
39
41
  const resolvedOpts = resolveHTTPLinkOptions(opts);
40
42
  const maxURLLength = opts.maxURLLength || Infinity;
@@ -0,0 +1,19 @@
1
+ import { TextDecoderEsque } from './streamingUtils';
2
+
3
+ export function getTextDecoder(
4
+ customTextDecoder?: TextDecoderEsque,
5
+ ): TextDecoderEsque {
6
+ if (customTextDecoder) {
7
+ return customTextDecoder;
8
+ }
9
+
10
+ if (typeof window !== 'undefined' && window.TextDecoder) {
11
+ return new window.TextDecoder();
12
+ }
13
+
14
+ if (typeof globalThis !== 'undefined' && globalThis.TextDecoder) {
15
+ return new globalThis.TextDecoder();
16
+ }
17
+
18
+ throw new Error('No TextDecoder implementation found');
19
+ }
@@ -9,6 +9,7 @@ import {
9
9
  RequestInitEsque,
10
10
  ResponseEsque,
11
11
  } from '../../internals/types';
12
+ import { TextDecoderEsque } from '../internals/streamingUtils';
12
13
  import { HTTPHeaders, PromiseAndCancel, TRPCClientRuntime } from '../types';
13
14
 
14
15
  /**
@@ -138,6 +139,7 @@ export const jsonHttpRequester: Requester = (opts) => {
138
139
  export type HTTPRequestOptions = HTTPBaseRequestOptions &
139
140
  ContentOptions & {
140
141
  headers: () => HTTPHeaders | Promise<HTTPHeaders>;
142
+ TextDecoder?: TextDecoderEsque;
141
143
  };
142
144
 
143
145
  export async function fetchHTTPResponse(
@@ -1,6 +1,6 @@
1
1
  // Stream parsing adapted from https://www.loginradius.com/blog/engineering/guest-post/http-streaming-with-nodejs-and-fetch-api/
2
-
3
2
  import { TRPCResponse } from '@trpc/server/rpc';
3
+ import { WebReadableStreamEsque } from '../../internals/types';
4
4
  import { HTTPHeaders } from '../types';
5
5
  import {
6
6
  fetchHTTPResponse,
@@ -9,6 +9,7 @@ import {
9
9
  HTTPBaseRequestOptions,
10
10
  HTTPResult,
11
11
  } from './httpUtils';
12
+ import { TextDecoderEsque } from './streamingUtils';
12
13
 
13
14
  /**
14
15
  * @internal
@@ -25,7 +26,7 @@ export async function parseJSONStream<TReturn>(opts: {
25
26
  /**
26
27
  * As given by `(await fetch(url)).body`
27
28
  */
28
- readableStream: ReadableStream<Uint8Array> | NodeJS.ReadableStream;
29
+ readableStream: WebReadableStreamEsque | NodeJS.ReadableStream;
29
30
  /**
30
31
  * Called for each line of the stream
31
32
  */
@@ -35,6 +36,7 @@ export async function parseJSONStream<TReturn>(opts: {
35
36
  */
36
37
  parse?: (text: string) => TReturn;
37
38
  signal?: AbortSignal;
39
+ textDecoder: TextDecoderEsque;
38
40
  }): Promise<void> {
39
41
  const parse = opts.parse ?? JSON.parse;
40
42
 
@@ -55,11 +57,9 @@ export async function parseJSONStream<TReturn>(opts: {
55
57
  opts.onSingle(Number(indexAsStr), parse(text));
56
58
  };
57
59
 
58
- await readLines(opts.readableStream, onLine);
60
+ await readLines(opts.readableStream, onLine, opts.textDecoder);
59
61
  }
60
62
 
61
- const textDecoder = new TextDecoder();
62
-
63
63
  /**
64
64
  * Handle transforming a stream of bytes into lines of text.
65
65
  * To avoid using AsyncIterators / AsyncGenerators,
@@ -69,8 +69,9 @@ const textDecoder = new TextDecoder();
69
69
  * @param onLine will be called for every line ('\n' delimited) in the stream
70
70
  */
71
71
  async function readLines(
72
- readableStream: ReadableStream<Uint8Array> | NodeJS.ReadableStream,
72
+ readableStream: WebReadableStreamEsque | NodeJS.ReadableStream,
73
73
  onLine: (line: string) => void,
74
+ textDecoder: TextDecoderEsque,
74
75
  ) {
75
76
  let partOfLine = '';
76
77
 
@@ -118,7 +119,7 @@ function readNodeChunks(
118
119
  * Handle WebAPI stream
119
120
  */
120
121
  async function readStandardChunks(
121
- stream: ReadableStream<Uint8Array>,
122
+ stream: WebReadableStreamEsque,
122
123
  onChunk: (chunk: Uint8Array) => void,
123
124
  ) {
124
125
  const reader = stream.getReader();
@@ -132,6 +133,7 @@ async function readStandardChunks(
132
133
  export const streamingJsonHttpRequester = (
133
134
  opts: HTTPBaseRequestOptions & {
134
135
  headers: () => HTTPHeaders | Promise<HTTPHeaders>;
136
+ textDecoder: TextDecoderEsque;
135
137
  },
136
138
  onSingle: (index: number, res: HTTPResult) => void,
137
139
  ) => {
@@ -150,7 +152,7 @@ export const streamingJsonHttpRequester = (
150
152
  const promise = responsePromise.then(async (res) => {
151
153
  if (!res.body) throw new Error('Received response without body');
152
154
  const meta: HTTPResult['meta'] = { response: res };
153
- return parseJSONStream({
155
+ return parseJSONStream<HTTPResult>({
154
156
  readableStream: res.body,
155
157
  onSingle,
156
158
  parse: (string) => ({
@@ -158,6 +160,7 @@ export const streamingJsonHttpRequester = (
158
160
  meta,
159
161
  }),
160
162
  signal: ac?.signal,
163
+ textDecoder: opts.textDecoder,
161
164
  });
162
165
  });
163
166
 
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @internal
3
+ */
4
+ export interface TextDecoderEsque {
5
+ decode(chunk: Uint8Array): string;
6
+ }