@trpc/client 11.0.0-rc.370 → 11.0.0-rc.374

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 (47) hide show
  1. package/dist/bundle-analysis.json +60 -106
  2. package/dist/index.js +0 -1
  3. package/dist/index.mjs +1 -1
  4. package/dist/internals/dataLoader.d.ts +3 -4
  5. package/dist/internals/dataLoader.d.ts.map +1 -1
  6. package/dist/internals/dataLoader.js +14 -13
  7. package/dist/internals/dataLoader.mjs +14 -13
  8. package/dist/links/httpBatchLink.d.ts +6 -1
  9. package/dist/links/httpBatchLink.d.ts.map +1 -1
  10. package/dist/links/httpBatchLink.js +95 -30
  11. package/dist/links/httpBatchLink.mjs +96 -31
  12. package/dist/links/httpBatchStreamLink.d.ts +9 -6
  13. package/dist/links/httpBatchStreamLink.d.ts.map +1 -1
  14. package/dist/links/httpBatchStreamLink.js +132 -34
  15. package/dist/links/httpBatchStreamLink.mjs +132 -34
  16. package/dist/links/httpLink.d.ts +4 -7
  17. package/dist/links/httpLink.d.ts.map +1 -1
  18. package/dist/links/httpLink.js +72 -46
  19. package/dist/links/httpLink.mjs +74 -47
  20. package/dist/links/internals/httpUtils.d.ts +2 -4
  21. package/dist/links/internals/httpUtils.d.ts.map +1 -1
  22. package/dist/links/internals/httpUtils.js +4 -32
  23. package/dist/links/internals/httpUtils.mjs +4 -32
  24. package/package.json +4 -4
  25. package/src/internals/dataLoader.ts +21 -19
  26. package/src/links/httpBatchLink.ts +132 -46
  27. package/src/links/httpBatchStreamLink.ts +173 -48
  28. package/src/links/httpLink.ts +100 -60
  29. package/src/links/internals/httpUtils.ts +5 -41
  30. package/dist/links/internals/createHTTPBatchLink.d.ts +0 -20
  31. package/dist/links/internals/createHTTPBatchLink.d.ts.map +0 -1
  32. package/dist/links/internals/createHTTPBatchLink.js +0 -85
  33. package/dist/links/internals/createHTTPBatchLink.mjs +0 -83
  34. package/dist/links/internals/getTextDecoder.d.ts +0 -3
  35. package/dist/links/internals/getTextDecoder.d.ts.map +0 -1
  36. package/dist/links/internals/getTextDecoder.js +0 -16
  37. package/dist/links/internals/getTextDecoder.mjs +0 -14
  38. package/dist/links/internals/parseJSONStream.d.ts +0 -39
  39. package/dist/links/internals/parseJSONStream.d.ts.map +0 -1
  40. package/dist/links/internals/parseJSONStream.js +0 -118
  41. package/dist/links/internals/parseJSONStream.mjs +0 -115
  42. package/dist/links/internals/streamingUtils.d.ts +0 -7
  43. package/dist/links/internals/streamingUtils.d.ts.map +0 -1
  44. package/src/links/internals/createHTTPBatchLink.ts +0 -133
  45. package/src/links/internals/getTextDecoder.ts +0 -19
  46. package/src/links/internals/parseJSONStream.ts +0 -166
  47. package/src/links/internals/streamingUtils.ts +0 -6
@@ -1,20 +0,0 @@
1
- import type { AnyRootTypes, AnyRouter, inferClientTypes, ProcedureType } from '@trpc/server/unstable-core-do-not-import';
2
- import type { HTTPBatchLinkOptions } from '../HTTPBatchLinkOptions';
3
- import type { CancelFn, Operation, TRPCClientRuntime, TRPCLink } from '../types';
4
- import type { HTTPResult, ResolvedHTTPLinkOptions } from './httpUtils';
5
- /**
6
- * @internal
7
- */
8
- export type RequesterFn<TOptions extends HTTPBatchLinkOptions<AnyRootTypes>> = (requesterOpts: ResolvedHTTPLinkOptions & {
9
- runtime: TRPCClientRuntime;
10
- type: ProcedureType;
11
- opts: TOptions;
12
- }) => (batchOps: Operation[], unitResolver: (index: number, value: NonNullable<HTTPResult>) => void) => {
13
- promise: Promise<HTTPResult[]>;
14
- cancel: CancelFn;
15
- };
16
- /**
17
- * @internal
18
- */
19
- export declare function createHTTPBatchLink(requester: RequesterFn<HTTPBatchLinkOptions<AnyRootTypes>>): <TRouter extends AnyRouter>(opts: HTTPBatchLinkOptions<inferClientTypes<TRouter>>) => TRPCLink<TRouter>;
20
- //# sourceMappingURL=createHTTPBatchLink.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createHTTPBatchLink.d.ts","sourceRoot":"","sources":["../../../src/links/internals/createHTTPBatchLink.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,SAAS,EACT,gBAAgB,EAChB,aAAa,EACd,MAAM,0CAA0C,CAAC;AAIlD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,KAAK,EACV,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACT,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,UAAU,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAGvE;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,QAAQ,SAAS,oBAAoB,CAAC,YAAY,CAAC,IAAI,CAC7E,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,CACjC,SAAS,EAAE,WAAW,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAAC,qCAGlD,qBAAqB,iBAAiB,OAAO,CAAC,CAAC,KACpD,SAAS,OAAO,CAAC,CAuFrB"}
@@ -1,85 +0,0 @@
1
- 'use strict';
2
-
3
- var observable = require('@trpc/server/observable');
4
- var unstableCoreDoNotImport = require('@trpc/server/unstable-core-do-not-import');
5
- var dataLoader = require('../../internals/dataLoader.js');
6
- var TRPCClientError = require('../../TRPCClientError.js');
7
- var httpUtils = require('./httpUtils.js');
8
-
9
- /**
10
- * @internal
11
- */ function createHTTPBatchLink(requester) {
12
- return function httpBatchLink(opts) {
13
- const resolvedOpts = httpUtils.resolveHTTPLinkOptions(opts);
14
- const maxURLLength = opts.maxURLLength ?? Infinity;
15
- // initialized config
16
- return (runtime)=>{
17
- const batchLoader = (type)=>{
18
- const validate = (batchOps)=>{
19
- if (maxURLLength === Infinity) {
20
- // escape hatch for quick calcs
21
- return true;
22
- }
23
- const path = batchOps.map((op)=>op.path).join(',');
24
- const inputs = batchOps.map((op)=>op.input);
25
- const url = httpUtils.getUrl({
26
- ...resolvedOpts,
27
- type,
28
- path,
29
- inputs
30
- });
31
- return url.length <= maxURLLength;
32
- };
33
- const fetch = requester({
34
- ...resolvedOpts,
35
- runtime,
36
- type,
37
- opts
38
- });
39
- return {
40
- validate,
41
- fetch
42
- };
43
- };
44
- const query = dataLoader.dataLoader(batchLoader('query'));
45
- const mutation = dataLoader.dataLoader(batchLoader('mutation'));
46
- const subscription = dataLoader.dataLoader(batchLoader('subscription'));
47
- const loaders = {
48
- query,
49
- subscription,
50
- mutation
51
- };
52
- return ({ op })=>{
53
- return observable.observable((observer)=>{
54
- const loader = loaders[op.type];
55
- const { promise , cancel } = loader.load(op);
56
- let _res = undefined;
57
- promise.then((res)=>{
58
- _res = res;
59
- const transformed = unstableCoreDoNotImport.transformResult(res.json, resolvedOpts.transformer.output);
60
- if (!transformed.ok) {
61
- observer.error(TRPCClientError.TRPCClientError.from(transformed.error, {
62
- meta: res.meta
63
- }));
64
- return;
65
- }
66
- observer.next({
67
- context: res.meta,
68
- result: transformed.result
69
- });
70
- observer.complete();
71
- }).catch((err)=>{
72
- observer.error(TRPCClientError.TRPCClientError.from(err, {
73
- meta: _res?.meta
74
- }));
75
- });
76
- return ()=>{
77
- cancel();
78
- };
79
- });
80
- };
81
- };
82
- };
83
- }
84
-
85
- exports.createHTTPBatchLink = createHTTPBatchLink;
@@ -1,83 +0,0 @@
1
- import { observable } from '@trpc/server/observable';
2
- import { transformResult } from '@trpc/server/unstable-core-do-not-import';
3
- import { dataLoader } from '../../internals/dataLoader.mjs';
4
- import { TRPCClientError } from '../../TRPCClientError.mjs';
5
- import { resolveHTTPLinkOptions, getUrl } from './httpUtils.mjs';
6
-
7
- /**
8
- * @internal
9
- */ function createHTTPBatchLink(requester) {
10
- return function httpBatchLink(opts) {
11
- const resolvedOpts = resolveHTTPLinkOptions(opts);
12
- const maxURLLength = opts.maxURLLength ?? Infinity;
13
- // initialized config
14
- return (runtime)=>{
15
- const batchLoader = (type)=>{
16
- const validate = (batchOps)=>{
17
- if (maxURLLength === Infinity) {
18
- // escape hatch for quick calcs
19
- return true;
20
- }
21
- const path = batchOps.map((op)=>op.path).join(',');
22
- const inputs = batchOps.map((op)=>op.input);
23
- const url = getUrl({
24
- ...resolvedOpts,
25
- type,
26
- path,
27
- inputs
28
- });
29
- return url.length <= maxURLLength;
30
- };
31
- const fetch = requester({
32
- ...resolvedOpts,
33
- runtime,
34
- type,
35
- opts
36
- });
37
- return {
38
- validate,
39
- fetch
40
- };
41
- };
42
- const query = dataLoader(batchLoader('query'));
43
- const mutation = dataLoader(batchLoader('mutation'));
44
- const subscription = dataLoader(batchLoader('subscription'));
45
- const loaders = {
46
- query,
47
- subscription,
48
- mutation
49
- };
50
- return ({ op })=>{
51
- return observable((observer)=>{
52
- const loader = loaders[op.type];
53
- const { promise , cancel } = loader.load(op);
54
- let _res = undefined;
55
- promise.then((res)=>{
56
- _res = res;
57
- const transformed = transformResult(res.json, resolvedOpts.transformer.output);
58
- if (!transformed.ok) {
59
- observer.error(TRPCClientError.from(transformed.error, {
60
- meta: res.meta
61
- }));
62
- return;
63
- }
64
- observer.next({
65
- context: res.meta,
66
- result: transformed.result
67
- });
68
- observer.complete();
69
- }).catch((err)=>{
70
- observer.error(TRPCClientError.from(err, {
71
- meta: _res?.meta
72
- }));
73
- });
74
- return ()=>{
75
- cancel();
76
- };
77
- });
78
- };
79
- };
80
- };
81
- }
82
-
83
- export { createHTTPBatchLink };
@@ -1,3 +0,0 @@
1
- import type { TextDecoderEsque } from './streamingUtils';
2
- export declare function getTextDecoder(customTextDecoder?: TextDecoderEsque): TextDecoderEsque;
3
- //# sourceMappingURL=getTextDecoder.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"getTextDecoder.d.ts","sourceRoot":"","sources":["../../../src/links/internals/getTextDecoder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,wBAAgB,cAAc,CAC5B,iBAAiB,CAAC,EAAE,gBAAgB,GACnC,gBAAgB,CAclB"}
@@ -1,16 +0,0 @@
1
- 'use strict';
2
-
3
- function getTextDecoder(customTextDecoder) {
4
- if (customTextDecoder) {
5
- return customTextDecoder;
6
- }
7
- if (typeof window !== 'undefined' && window.TextDecoder) {
8
- return new window.TextDecoder();
9
- }
10
- if (typeof globalThis !== 'undefined' && globalThis.TextDecoder) {
11
- return new globalThis.TextDecoder();
12
- }
13
- throw new Error('No TextDecoder implementation found');
14
- }
15
-
16
- exports.getTextDecoder = getTextDecoder;
@@ -1,14 +0,0 @@
1
- function getTextDecoder(customTextDecoder) {
2
- if (customTextDecoder) {
3
- return customTextDecoder;
4
- }
5
- if (typeof window !== 'undefined' && window.TextDecoder) {
6
- return new window.TextDecoder();
7
- }
8
- if (typeof globalThis !== 'undefined' && globalThis.TextDecoder) {
9
- return new globalThis.TextDecoder();
10
- }
11
- throw new Error('No TextDecoder implementation found');
12
- }
13
-
14
- export { getTextDecoder };
@@ -1,39 +0,0 @@
1
- import type { NodeJSReadableStreamEsque, WebReadableStreamEsque } from '../../internals/types';
2
- import type { HTTPHeaders } from '../types';
3
- import type { HTTPBaseRequestOptions, HTTPResult } from './httpUtils';
4
- import type { TextDecoderEsque } from './streamingUtils';
5
- /**
6
- * @internal
7
- * @description Take a stream of bytes and call `onLine` with
8
- * a JSON object for each line in the stream. Expected stream
9
- * format is:
10
- * ```json
11
- * {"1": {...}
12
- * ,"0": {...}
13
- * }
14
- * ```
15
- */
16
- export declare function parseJSONStream<TReturn>(opts: {
17
- /**
18
- * As given by `(await fetch(url)).body`
19
- */
20
- readableStream: NodeJSReadableStreamEsque | WebReadableStreamEsque;
21
- /**
22
- * Called for each line of the stream
23
- */
24
- onSingle: (index: number, res: TReturn) => void;
25
- /**
26
- * Transform text into useable data object (defaults to JSON.parse)
27
- */
28
- parse?: (text: string) => TReturn;
29
- signal?: AbortSignal;
30
- textDecoder: TextDecoderEsque;
31
- }): Promise<void>;
32
- export declare const streamingJsonHttpRequester: (opts: HTTPBaseRequestOptions & {
33
- headers: () => HTTPHeaders | Promise<HTTPHeaders>;
34
- textDecoder: TextDecoderEsque;
35
- }, onSingle: (index: number, res: HTTPResult) => void) => {
36
- cancel: () => void | undefined;
37
- promise: Promise<void>;
38
- };
39
- //# sourceMappingURL=parseJSONStream.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"parseJSONStream.d.ts","sourceRoot":"","sources":["../../../src/links/internals/parseJSONStream.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,IAAI,EAAE;IACnD;;OAEG;IACH,cAAc,EAAE,yBAAyB,GAAG,sBAAsB,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;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"}
@@ -1,118 +0,0 @@
1
- 'use strict';
2
-
3
- var httpUtils = require('./httpUtils.js');
4
-
5
- // Stream parsing adapted from https://www.loginradius.com/blog/engineering/guest-post/http-streaming-with-nodejs-and-fetch-api/
6
- /**
7
- * @internal
8
- * @description Take a stream of bytes and call `onLine` with
9
- * a JSON object for each line in the stream. Expected stream
10
- * format is:
11
- * ```json
12
- * {"1": {...}
13
- * ,"0": {...}
14
- * }
15
- * ```
16
- */ async function parseJSONStream(opts) {
17
- const parse = opts.parse ?? JSON.parse;
18
- const onLine = (line)=>{
19
- if (opts.signal?.aborted) return;
20
- if (!line || line === '}') {
21
- return;
22
- }
23
- /**
24
- * At this point, `line` can be one of two things:
25
- * - The first line of the stream `{"2":{...}`
26
- * - A line in the middle of the stream `,"2":{...}`
27
- */ const indexOfColon = line.indexOf(':');
28
- const indexAsStr = line.substring(2, indexOfColon - 1);
29
- const text = line.substring(indexOfColon + 1);
30
- opts.onSingle(Number(indexAsStr), parse(text));
31
- };
32
- await readLines(opts.readableStream, onLine, opts.textDecoder);
33
- }
34
- /**
35
- * Handle transforming a stream of bytes into lines of text.
36
- * To avoid using AsyncIterators / AsyncGenerators,
37
- * we use a callback for each line.
38
- *
39
- * @param readableStream can be a NodeJS stream or a WebAPI stream
40
- * @param onLine will be called for every line ('\n' delimited) in the stream
41
- */ async function readLines(readableStream, onLine, textDecoder) {
42
- let partOfLine = '';
43
- const onChunk = (chunk)=>{
44
- const chunkText = textDecoder.decode(chunk);
45
- const chunkLines = chunkText.split('\n');
46
- if (chunkLines.length === 1) {
47
- partOfLine += chunkLines[0];
48
- } else if (chunkLines.length > 1) {
49
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- length checked on line above
50
- onLine(partOfLine + chunkLines[0]);
51
- for(let i = 1; i < chunkLines.length - 1; i++){
52
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- length checked on line above
53
- onLine(chunkLines[i]);
54
- }
55
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- length doesn't change, so is necessarily > 1
56
- partOfLine = chunkLines[chunkLines.length - 1];
57
- }
58
- };
59
- // we handle 2 different types of streams, this if where we figure out which one we have
60
- if ('getReader' in readableStream) {
61
- await readStandardChunks(readableStream, onChunk);
62
- } else {
63
- await readNodeChunks(readableStream, onChunk);
64
- }
65
- onLine(partOfLine);
66
- }
67
- /**
68
- * Handle NodeJS stream
69
- */ function readNodeChunks(stream, onChunk) {
70
- return new Promise((resolve)=>{
71
- stream.on('data', onChunk);
72
- stream.on('end', resolve);
73
- });
74
- }
75
- /**
76
- * Handle WebAPI stream
77
- */ async function readStandardChunks(stream, onChunk) {
78
- const reader = stream.getReader();
79
- let readResult = await reader.read();
80
- while(!readResult.done){
81
- onChunk(readResult.value);
82
- readResult = await reader.read();
83
- }
84
- }
85
- const streamingJsonHttpRequester = (opts, onSingle)=>{
86
- const ac = opts.AbortController ? new opts.AbortController() : null;
87
- const responsePromise = httpUtils.fetchHTTPResponse({
88
- ...opts,
89
- contentTypeHeader: 'application/json',
90
- batchModeHeader: 'stream',
91
- getUrl: httpUtils.getUrl,
92
- getBody: httpUtils.getBody
93
- }, ac);
94
- const cancel = ()=>ac?.abort();
95
- const promise = responsePromise.then(async (res)=>{
96
- if (!res.body) throw new Error('Received response without body');
97
- const meta = {
98
- response: res
99
- };
100
- return parseJSONStream({
101
- readableStream: res.body,
102
- onSingle,
103
- parse: (string)=>({
104
- json: JSON.parse(string),
105
- meta
106
- }),
107
- signal: ac?.signal,
108
- textDecoder: opts.textDecoder
109
- });
110
- });
111
- return {
112
- cancel,
113
- promise
114
- };
115
- };
116
-
117
- exports.parseJSONStream = parseJSONStream;
118
- exports.streamingJsonHttpRequester = streamingJsonHttpRequester;
@@ -1,115 +0,0 @@
1
- import { fetchHTTPResponse, getUrl, getBody } from './httpUtils.mjs';
2
-
3
- // Stream parsing adapted from https://www.loginradius.com/blog/engineering/guest-post/http-streaming-with-nodejs-and-fetch-api/
4
- /**
5
- * @internal
6
- * @description Take a stream of bytes and call `onLine` with
7
- * a JSON object for each line in the stream. Expected stream
8
- * format is:
9
- * ```json
10
- * {"1": {...}
11
- * ,"0": {...}
12
- * }
13
- * ```
14
- */ async function parseJSONStream(opts) {
15
- const parse = opts.parse ?? JSON.parse;
16
- const onLine = (line)=>{
17
- if (opts.signal?.aborted) return;
18
- if (!line || line === '}') {
19
- return;
20
- }
21
- /**
22
- * At this point, `line` can be one of two things:
23
- * - The first line of the stream `{"2":{...}`
24
- * - A line in the middle of the stream `,"2":{...}`
25
- */ const indexOfColon = line.indexOf(':');
26
- const indexAsStr = line.substring(2, indexOfColon - 1);
27
- const text = line.substring(indexOfColon + 1);
28
- opts.onSingle(Number(indexAsStr), parse(text));
29
- };
30
- await readLines(opts.readableStream, onLine, opts.textDecoder);
31
- }
32
- /**
33
- * Handle transforming a stream of bytes into lines of text.
34
- * To avoid using AsyncIterators / AsyncGenerators,
35
- * we use a callback for each line.
36
- *
37
- * @param readableStream can be a NodeJS stream or a WebAPI stream
38
- * @param onLine will be called for every line ('\n' delimited) in the stream
39
- */ async function readLines(readableStream, onLine, textDecoder) {
40
- let partOfLine = '';
41
- const onChunk = (chunk)=>{
42
- const chunkText = textDecoder.decode(chunk);
43
- const chunkLines = chunkText.split('\n');
44
- if (chunkLines.length === 1) {
45
- partOfLine += chunkLines[0];
46
- } else if (chunkLines.length > 1) {
47
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- length checked on line above
48
- onLine(partOfLine + chunkLines[0]);
49
- for(let i = 1; i < chunkLines.length - 1; i++){
50
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- length checked on line above
51
- onLine(chunkLines[i]);
52
- }
53
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- length doesn't change, so is necessarily > 1
54
- partOfLine = chunkLines[chunkLines.length - 1];
55
- }
56
- };
57
- // we handle 2 different types of streams, this if where we figure out which one we have
58
- if ('getReader' in readableStream) {
59
- await readStandardChunks(readableStream, onChunk);
60
- } else {
61
- await readNodeChunks(readableStream, onChunk);
62
- }
63
- onLine(partOfLine);
64
- }
65
- /**
66
- * Handle NodeJS stream
67
- */ function readNodeChunks(stream, onChunk) {
68
- return new Promise((resolve)=>{
69
- stream.on('data', onChunk);
70
- stream.on('end', resolve);
71
- });
72
- }
73
- /**
74
- * Handle WebAPI stream
75
- */ async function readStandardChunks(stream, onChunk) {
76
- const reader = stream.getReader();
77
- let readResult = await reader.read();
78
- while(!readResult.done){
79
- onChunk(readResult.value);
80
- readResult = await reader.read();
81
- }
82
- }
83
- const streamingJsonHttpRequester = (opts, onSingle)=>{
84
- const ac = opts.AbortController ? new opts.AbortController() : null;
85
- const responsePromise = fetchHTTPResponse({
86
- ...opts,
87
- contentTypeHeader: 'application/json',
88
- batchModeHeader: 'stream',
89
- getUrl,
90
- getBody
91
- }, ac);
92
- const cancel = ()=>ac?.abort();
93
- const promise = responsePromise.then(async (res)=>{
94
- if (!res.body) throw new Error('Received response without body');
95
- const meta = {
96
- response: res
97
- };
98
- return parseJSONStream({
99
- readableStream: res.body,
100
- onSingle,
101
- parse: (string)=>({
102
- json: JSON.parse(string),
103
- meta
104
- }),
105
- signal: ac?.signal,
106
- textDecoder: opts.textDecoder
107
- });
108
- });
109
- return {
110
- cancel,
111
- promise
112
- };
113
- };
114
-
115
- export { parseJSONStream, streamingJsonHttpRequester };
@@ -1,7 +0,0 @@
1
- /**
2
- * @internal
3
- */
4
- export interface TextDecoderEsque {
5
- decode(chunk: Uint8Array): string;
6
- }
7
- //# sourceMappingURL=streamingUtils.d.ts.map
@@ -1 +0,0 @@
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"}
@@ -1,133 +0,0 @@
1
- import { observable } from '@trpc/server/observable';
2
- import type {
3
- AnyRootTypes,
4
- AnyRouter,
5
- inferClientTypes,
6
- ProcedureType,
7
- } from '@trpc/server/unstable-core-do-not-import';
8
- import { transformResult } from '@trpc/server/unstable-core-do-not-import';
9
- import { dataLoader } from '../../internals/dataLoader';
10
- import { TRPCClientError } from '../../TRPCClientError';
11
- import type { HTTPBatchLinkOptions } from '../HTTPBatchLinkOptions';
12
- import type {
13
- CancelFn,
14
- Operation,
15
- TRPCClientRuntime,
16
- TRPCLink,
17
- } from '../types';
18
- import type { HTTPResult, ResolvedHTTPLinkOptions } from './httpUtils';
19
- import { getUrl, resolveHTTPLinkOptions } from './httpUtils';
20
-
21
- /**
22
- * @internal
23
- */
24
- export type RequesterFn<TOptions extends HTTPBatchLinkOptions<AnyRootTypes>> = (
25
- requesterOpts: ResolvedHTTPLinkOptions & {
26
- runtime: TRPCClientRuntime;
27
- type: ProcedureType;
28
- opts: TOptions;
29
- },
30
- ) => (
31
- batchOps: Operation[],
32
- unitResolver: (index: number, value: NonNullable<HTTPResult>) => void,
33
- ) => {
34
- promise: Promise<HTTPResult[]>;
35
- cancel: CancelFn;
36
- };
37
-
38
- /**
39
- * @internal
40
- */
41
- export function createHTTPBatchLink(
42
- requester: RequesterFn<HTTPBatchLinkOptions<AnyRootTypes>>,
43
- ) {
44
- return function httpBatchLink<TRouter extends AnyRouter>(
45
- opts: HTTPBatchLinkOptions<inferClientTypes<TRouter>>,
46
- ): TRPCLink<TRouter> {
47
- const resolvedOpts = resolveHTTPLinkOptions(opts);
48
- const maxURLLength = opts.maxURLLength ?? Infinity;
49
-
50
- // initialized config
51
- return (runtime) => {
52
- const batchLoader = (type: ProcedureType) => {
53
- const validate = (batchOps: Operation[]) => {
54
- if (maxURLLength === Infinity) {
55
- // escape hatch for quick calcs
56
- return true;
57
- }
58
- const path = batchOps.map((op) => op.path).join(',');
59
- const inputs = batchOps.map((op) => op.input);
60
-
61
- const url = getUrl({
62
- ...resolvedOpts,
63
- type,
64
- path,
65
- inputs,
66
- });
67
-
68
- return url.length <= maxURLLength;
69
- };
70
-
71
- const fetch = requester({
72
- ...resolvedOpts,
73
- runtime,
74
- type,
75
- opts,
76
- });
77
-
78
- return { validate, fetch };
79
- };
80
-
81
- const query = dataLoader<Operation, HTTPResult>(batchLoader('query'));
82
- const mutation = dataLoader<Operation, HTTPResult>(
83
- batchLoader('mutation'),
84
- );
85
- const subscription = dataLoader<Operation, HTTPResult>(
86
- batchLoader('subscription'),
87
- );
88
-
89
- const loaders = { query, subscription, mutation };
90
- return ({ op }) => {
91
- return observable((observer) => {
92
- const loader = loaders[op.type];
93
- const { promise, cancel } = loader.load(op);
94
-
95
- let _res = undefined as HTTPResult | undefined;
96
- promise
97
- .then((res) => {
98
- _res = res;
99
- const transformed = transformResult(
100
- res.json,
101
- resolvedOpts.transformer.output,
102
- );
103
-
104
- if (!transformed.ok) {
105
- observer.error(
106
- TRPCClientError.from(transformed.error, {
107
- meta: res.meta,
108
- }),
109
- );
110
- return;
111
- }
112
- observer.next({
113
- context: res.meta,
114
- result: transformed.result,
115
- });
116
- observer.complete();
117
- })
118
- .catch((err) => {
119
- observer.error(
120
- TRPCClientError.from(err, {
121
- meta: _res?.meta,
122
- }),
123
- );
124
- });
125
-
126
- return () => {
127
- cancel();
128
- };
129
- });
130
- };
131
- };
132
- };
133
- }
@@ -1,19 +0,0 @@
1
- import type { 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
- }