@trpc/client 11.18.1-canary.17 → 11.18.1-canary.19

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,7 +1,7 @@
1
1
  const require_chunk = require('./chunk-DWy1uDak.cjs');
2
2
  const require_objectSpread2$1 = require('./objectSpread2-Bsvh_OqM.cjs');
3
3
  const require_TRPCClientError = require('./TRPCClientError-CQrTQLrk.cjs');
4
- const require_httpUtils = require('./httpUtils-wv2o-njD.cjs');
4
+ const require_httpUtils = require('./httpUtils-s6LGgoIm.cjs');
5
5
  const __trpc_server_observable = require_chunk.__toESM(require("@trpc/server/observable"));
6
6
  const __trpc_server_unstable_core_do_not_import = require_chunk.__toESM(require("@trpc/server/unstable-core-do-not-import"));
7
7
 
@@ -116,48 +116,6 @@ function dataLoader(batchLoader) {
116
116
  return { load };
117
117
  }
118
118
 
119
- //#endregion
120
- //#region src/internals/signals.ts
121
- /**
122
- * Like `Promise.all()` but for abort signals
123
- * - When all signals have been aborted, the merged signal will be aborted
124
- * - If one signal is `null`, no signal will be aborted
125
- */
126
- function allAbortSignals(...signals) {
127
- const ac = new AbortController();
128
- const count = signals.length;
129
- let abortedCount = 0;
130
- const onAbort = () => {
131
- if (++abortedCount === count) ac.abort();
132
- };
133
- for (const signal of signals) if (signal === null || signal === void 0 ? void 0 : signal.aborted) onAbort();
134
- else signal === null || signal === void 0 || signal.addEventListener("abort", onAbort, { once: true });
135
- return ac.signal;
136
- }
137
- /**
138
- * Like `Promise.race` but for abort signals
139
- *
140
- * Basically, a ponyfill for
141
- * [`AbortSignal.any`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/any_static).
142
- */
143
- function raceAbortSignals(...signals) {
144
- const ac = new AbortController();
145
- for (const signal of signals) if (signal === null || signal === void 0 ? void 0 : signal.aborted) ac.abort();
146
- else signal === null || signal === void 0 || signal.addEventListener("abort", () => ac.abort(), { once: true });
147
- return ac.signal;
148
- }
149
- function abortSignalToPromise(signal) {
150
- return new Promise((_, reject) => {
151
- if (signal.aborted) {
152
- reject(signal.reason);
153
- return;
154
- }
155
- signal.addEventListener("abort", () => {
156
- reject(signal.reason);
157
- }, { once: true });
158
- });
159
- }
160
-
161
119
  //#endregion
162
120
  //#region src/links/httpBatchLink.ts
163
121
  var import_objectSpread2 = require_chunk.__toESM(require_objectSpread2$1.require_objectSpread2(), 1);
@@ -188,7 +146,7 @@ function httpBatchLink(opts) {
188
146
  async fetch(batchOps) {
189
147
  const path = batchOps.map((op) => op.path).join(",");
190
148
  const inputs = batchOps.map((op) => op.input);
191
- const signal = allAbortSignals(...batchOps.map((op) => op.signal));
149
+ const signal = require_httpUtils.allAbortSignals(...batchOps.map((op) => op.signal));
192
150
  const res = await require_httpUtils.jsonHttpRequester((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, resolvedOpts), {}, {
193
151
  path,
194
152
  inputs,
@@ -219,10 +177,13 @@ function httpBatchLink(opts) {
219
177
  return (0, __trpc_server_observable.observable)((observer) => {
220
178
  /* istanbul ignore if -- @preserve */
221
179
  if (op.type === "subscription") throw new Error("Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`");
180
+ const ac = new AbortController();
222
181
  const loader = loaders[op.type];
223
- const promise = loader.load(op);
182
+ const promise = loader.load((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, op), {}, { signal: require_httpUtils.raceAbortSignals(op.signal, ac.signal) }));
183
+ let isDone = false;
224
184
  let _res = void 0;
225
185
  promise.then((res) => {
186
+ isDone = true;
226
187
  _res = res;
227
188
  const transformed = (0, __trpc_server_unstable_core_do_not_import.transformResult)(res.json, resolvedOpts.transformer.output);
228
189
  if (!transformed.ok) {
@@ -235,27 +196,18 @@ function httpBatchLink(opts) {
235
196
  });
236
197
  observer.complete();
237
198
  }).catch((err) => {
199
+ isDone = true;
238
200
  observer.error(require_TRPCClientError.TRPCClientError.from(err, { meta: _res === null || _res === void 0 ? void 0 : _res.meta }));
239
201
  });
240
- return () => {};
202
+ return () => {
203
+ if (!isDone) ac.abort();
204
+ };
241
205
  });
242
206
  };
243
207
  };
244
208
  }
245
209
 
246
210
  //#endregion
247
- Object.defineProperty(exports, 'abortSignalToPromise', {
248
- enumerable: true,
249
- get: function () {
250
- return abortSignalToPromise;
251
- }
252
- });
253
- Object.defineProperty(exports, 'allAbortSignals', {
254
- enumerable: true,
255
- get: function () {
256
- return allAbortSignals;
257
- }
258
- });
259
211
  Object.defineProperty(exports, 'dataLoader', {
260
212
  enumerable: true,
261
213
  get: function () {
@@ -267,10 +219,4 @@ Object.defineProperty(exports, 'httpBatchLink', {
267
219
  get: function () {
268
220
  return httpBatchLink;
269
221
  }
270
- });
271
- Object.defineProperty(exports, 'raceAbortSignals', {
272
- enumerable: true,
273
- get: function () {
274
- return raceAbortSignals;
275
- }
276
222
  });
@@ -1,6 +1,6 @@
1
1
  import { __toESM, require_objectSpread2 } from "./objectSpread2-BvkFp-_Y.mjs";
2
2
  import { TRPCClientError } from "./TRPCClientError-apv8gw59.mjs";
3
- import { getUrl, jsonHttpRequester, resolveHTTPLinkOptions } from "./httpUtils-pyf5RF99.mjs";
3
+ import { allAbortSignals, getUrl, jsonHttpRequester, raceAbortSignals, resolveHTTPLinkOptions } from "./httpUtils-B2s2BleG.mjs";
4
4
  import { observable } from "@trpc/server/observable";
5
5
  import { transformResult } from "@trpc/server/unstable-core-do-not-import";
6
6
 
@@ -115,48 +115,6 @@ function dataLoader(batchLoader) {
115
115
  return { load };
116
116
  }
117
117
 
118
- //#endregion
119
- //#region src/internals/signals.ts
120
- /**
121
- * Like `Promise.all()` but for abort signals
122
- * - When all signals have been aborted, the merged signal will be aborted
123
- * - If one signal is `null`, no signal will be aborted
124
- */
125
- function allAbortSignals(...signals) {
126
- const ac = new AbortController();
127
- const count = signals.length;
128
- let abortedCount = 0;
129
- const onAbort = () => {
130
- if (++abortedCount === count) ac.abort();
131
- };
132
- for (const signal of signals) if (signal === null || signal === void 0 ? void 0 : signal.aborted) onAbort();
133
- else signal === null || signal === void 0 || signal.addEventListener("abort", onAbort, { once: true });
134
- return ac.signal;
135
- }
136
- /**
137
- * Like `Promise.race` but for abort signals
138
- *
139
- * Basically, a ponyfill for
140
- * [`AbortSignal.any`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/any_static).
141
- */
142
- function raceAbortSignals(...signals) {
143
- const ac = new AbortController();
144
- for (const signal of signals) if (signal === null || signal === void 0 ? void 0 : signal.aborted) ac.abort();
145
- else signal === null || signal === void 0 || signal.addEventListener("abort", () => ac.abort(), { once: true });
146
- return ac.signal;
147
- }
148
- function abortSignalToPromise(signal) {
149
- return new Promise((_, reject) => {
150
- if (signal.aborted) {
151
- reject(signal.reason);
152
- return;
153
- }
154
- signal.addEventListener("abort", () => {
155
- reject(signal.reason);
156
- }, { once: true });
157
- });
158
- }
159
-
160
118
  //#endregion
161
119
  //#region src/links/httpBatchLink.ts
162
120
  var import_objectSpread2 = __toESM(require_objectSpread2(), 1);
@@ -218,10 +176,13 @@ function httpBatchLink(opts) {
218
176
  return observable((observer) => {
219
177
  /* istanbul ignore if -- @preserve */
220
178
  if (op.type === "subscription") throw new Error("Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`");
179
+ const ac = new AbortController();
221
180
  const loader = loaders[op.type];
222
- const promise = loader.load(op);
181
+ const promise = loader.load((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, op), {}, { signal: raceAbortSignals(op.signal, ac.signal) }));
182
+ let isDone = false;
223
183
  let _res = void 0;
224
184
  promise.then((res) => {
185
+ isDone = true;
225
186
  _res = res;
226
187
  const transformed = transformResult(res.json, resolvedOpts.transformer.output);
227
188
  if (!transformed.ok) {
@@ -234,14 +195,17 @@ function httpBatchLink(opts) {
234
195
  });
235
196
  observer.complete();
236
197
  }).catch((err) => {
198
+ isDone = true;
237
199
  observer.error(TRPCClientError.from(err, { meta: _res === null || _res === void 0 ? void 0 : _res.meta }));
238
200
  });
239
- return () => {};
201
+ return () => {
202
+ if (!isDone) ac.abort();
203
+ };
240
204
  });
241
205
  };
242
206
  };
243
207
  }
244
208
 
245
209
  //#endregion
246
- export { abortSignalToPromise, allAbortSignals, dataLoader, httpBatchLink, raceAbortSignals };
247
- //# sourceMappingURL=httpBatchLink-LhidKAPw.mjs.map
210
+ export { dataLoader, httpBatchLink };
211
+ //# sourceMappingURL=httpBatchLink-RBPi17Tn.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpBatchLink-RBPi17Tn.mjs","names":["batchLoader: BatchLoader<TKey, TValue>","pendingItems: BatchItem<TKey, TValue>[] | null","dispatchTimer: ReturnType<typeof setTimeout> | null","items: BatchItem<TKey, TValue>[]","groupedItems: BatchItem<TKey, TValue>[][]","batch: Batch<TKey, TValue>","key: TKey","item: BatchItem<TKey, TValue>","opts: HTTPBatchLinkOptions<TRouter['_def']['_config']['$types']>","type: ProcedureType"],"sources":["../src/internals/dataLoader.ts","../src/links/httpBatchLink.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\ntype BatchItem<TKey, TValue> = {\n aborted: boolean;\n key: TKey;\n resolve: ((value: TValue) => void) | null;\n reject: ((error: Error) => void) | null;\n batch: Batch<TKey, TValue> | null;\n};\ntype Batch<TKey, TValue> = {\n items: BatchItem<TKey, TValue>[];\n};\nexport type BatchLoader<TKey, TValue> = {\n validate: (keys: TKey[]) => boolean;\n fetch: (keys: TKey[]) => Promise<TValue[] | Promise<TValue>[]>;\n};\n\n/**\n * A function that should never be called unless we messed something up.\n */\nconst throwFatalError = () => {\n throw new Error(\n 'Something went wrong. Please submit an issue at https://github.com/trpc/trpc/issues/new',\n );\n};\n\n/**\n * Dataloader that's very inspired by https://github.com/graphql/dataloader\n * Less configuration, no caching, and allows you to cancel requests\n * When cancelling a single fetch the whole batch will be cancelled only when _all_ items are cancelled\n */\nexport function dataLoader<TKey, TValue>(\n batchLoader: BatchLoader<TKey, TValue>,\n) {\n let pendingItems: BatchItem<TKey, TValue>[] | null = null;\n let dispatchTimer: ReturnType<typeof setTimeout> | null = null;\n\n const destroyTimerAndPendingItems = () => {\n clearTimeout(dispatchTimer as any);\n dispatchTimer = null;\n pendingItems = null;\n };\n\n /**\n * Iterate through the items and split them into groups based on the `batchLoader`'s validate function\n */\n function groupItems(items: BatchItem<TKey, TValue>[]) {\n const groupedItems: BatchItem<TKey, TValue>[][] = [[]];\n let index = 0;\n while (true) {\n const item = items[index];\n if (!item) {\n // we're done\n break;\n }\n const lastGroup = groupedItems[groupedItems.length - 1]!;\n\n if (item.aborted) {\n // Item was aborted before it was dispatched\n item.reject?.(new Error('Aborted'));\n index++;\n continue;\n }\n\n const isValid = batchLoader.validate(\n lastGroup.concat(item).map((it) => it.key),\n );\n\n if (isValid) {\n lastGroup.push(item);\n index++;\n continue;\n }\n\n if (lastGroup.length === 0) {\n item.reject?.(new Error('Input is too big for a single dispatch'));\n index++;\n continue;\n }\n // Create new group, next iteration will try to add the item to that\n groupedItems.push([]);\n }\n return groupedItems;\n }\n\n function dispatch() {\n const groupedItems = groupItems(pendingItems!);\n destroyTimerAndPendingItems();\n\n // Create batches for each group of items\n for (const items of groupedItems) {\n if (!items.length) {\n continue;\n }\n const batch: Batch<TKey, TValue> = {\n items,\n };\n for (const item of items) {\n item.batch = batch;\n }\n const promise = batchLoader.fetch(batch.items.map((_item) => _item.key));\n\n promise\n .then(async (result) => {\n await Promise.all(\n result.map(async (valueOrPromise, index) => {\n const item = batch.items[index]!;\n try {\n const value = await Promise.resolve(valueOrPromise);\n\n item.resolve?.(value);\n } catch (cause) {\n item.reject?.(cause as Error);\n }\n\n item.batch = null;\n item.reject = null;\n item.resolve = null;\n }),\n );\n\n for (const item of batch.items) {\n item.reject?.(new Error('Missing result'));\n item.batch = null;\n }\n })\n .catch((cause) => {\n for (const item of batch.items) {\n item.reject?.(cause);\n item.batch = null;\n }\n });\n }\n }\n function load(key: TKey): Promise<TValue> {\n const item: BatchItem<TKey, TValue> = {\n aborted: false,\n key,\n batch: null,\n resolve: throwFatalError,\n reject: throwFatalError,\n };\n\n const promise = new Promise<TValue>((resolve, reject) => {\n item.reject = reject;\n item.resolve = resolve;\n\n pendingItems ??= [];\n pendingItems.push(item);\n });\n\n dispatchTimer ??= setTimeout(dispatch);\n\n return promise;\n }\n\n return {\n load,\n };\n}\n","import type { AnyRouter, ProcedureType } from '@trpc/server';\nimport { observable } from '@trpc/server/observable';\nimport { transformResult } from '@trpc/server/unstable-core-do-not-import';\nimport type { BatchLoader } from '../internals/dataLoader';\nimport { dataLoader } from '../internals/dataLoader';\nimport { allAbortSignals, raceAbortSignals } from '../internals/signals';\nimport type { NonEmptyArray } from '../internals/types';\nimport { TRPCClientError } from '../TRPCClientError';\nimport type { HTTPBatchLinkOptions } from './HTTPBatchLinkOptions';\nimport type { HTTPResult } from './internals/httpUtils';\nimport {\n getUrl,\n jsonHttpRequester,\n resolveHTTPLinkOptions,\n} from './internals/httpUtils';\nimport type { Operation, TRPCLink } from './types';\n\n/**\n * @see https://trpc.io/docs/client/links/httpBatchLink\n */\nexport function httpBatchLink<TRouter extends AnyRouter>(\n opts: HTTPBatchLinkOptions<TRouter['_def']['_config']['$types']>,\n): TRPCLink<TRouter> {\n const resolvedOpts = resolveHTTPLinkOptions(opts);\n const maxURLLength = opts.maxURLLength ?? Infinity;\n const maxItems = opts.maxItems ?? Infinity;\n\n return () => {\n const batchLoader = (\n type: ProcedureType,\n ): BatchLoader<Operation, HTTPResult> => {\n return {\n validate(batchOps) {\n if (maxURLLength === Infinity && maxItems === Infinity) {\n // escape hatch for quick calcs\n return true;\n }\n if (batchOps.length > maxItems) {\n return false;\n }\n const path = batchOps.map((op) => op.path).join(',');\n const inputs = batchOps.map((op) => op.input);\n\n const url = getUrl({\n ...resolvedOpts,\n type,\n path,\n inputs,\n signal: null,\n });\n\n return url.length <= maxURLLength;\n },\n async fetch(batchOps) {\n const path = batchOps.map((op) => op.path).join(',');\n const inputs = batchOps.map((op) => op.input);\n const signal = allAbortSignals(...batchOps.map((op) => op.signal));\n\n const res = await jsonHttpRequester({\n ...resolvedOpts,\n path,\n inputs,\n type,\n headers() {\n if (!opts.headers) {\n return {};\n }\n if (typeof opts.headers === 'function') {\n return opts.headers({\n opList: batchOps as NonEmptyArray<Operation>,\n });\n }\n return opts.headers;\n },\n signal,\n });\n const resJSON = Array.isArray(res.json)\n ? res.json\n : batchOps.map(() => res.json);\n const result = resJSON.map((item) => ({\n meta: res.meta,\n json: item,\n }));\n return result;\n },\n };\n };\n\n const query = dataLoader(batchLoader('query'));\n const mutation = dataLoader(batchLoader('mutation'));\n\n const loaders = { query, mutation };\n return ({ op }) => {\n return observable((observer) => {\n /* istanbul ignore if -- @preserve */\n if (op.type === 'subscription') {\n throw new Error(\n 'Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`',\n );\n }\n const ac = new AbortController();\n const loader = loaders[op.type];\n const promise = loader.load({\n ...op,\n signal: raceAbortSignals(op.signal, ac.signal),\n });\n\n let isDone = false;\n let _res = undefined as HTTPResult | undefined;\n promise\n .then((res) => {\n isDone = true;\n _res = res;\n const transformed = transformResult(\n res.json,\n resolvedOpts.transformer.output,\n );\n\n if (!transformed.ok) {\n observer.error(\n TRPCClientError.from(transformed.error, {\n meta: res.meta,\n }),\n );\n return;\n }\n observer.next({\n context: res.meta,\n result: transformed.result,\n });\n observer.complete();\n })\n .catch((err) => {\n isDone = true;\n observer.error(\n TRPCClientError.from(err, {\n meta: _res?.meta,\n }),\n );\n });\n\n return () => {\n if (!isDone) {\n ac.abort();\n }\n };\n });\n };\n };\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  const require_chunk = require('./chunk-DWy1uDak.cjs');
2
2
  const require_objectSpread2$1 = require('./objectSpread2-Bsvh_OqM.cjs');
3
3
  const require_TRPCClientError = require('./TRPCClientError-CQrTQLrk.cjs');
4
- const require_httpUtils = require('./httpUtils-wv2o-njD.cjs');
4
+ const require_httpUtils = require('./httpUtils-s6LGgoIm.cjs');
5
5
  const __trpc_server_observable = require_chunk.__toESM(require("@trpc/server/observable"));
6
6
  const __trpc_server_unstable_core_do_not_import = require_chunk.__toESM(require("@trpc/server/unstable-core-do-not-import"));
7
7
 
@@ -53,19 +53,22 @@ function httpLink(opts) {
53
53
  const { path, input, type } = op;
54
54
  /* istanbul ignore if -- @preserve */
55
55
  if (type === "subscription") throw new Error("Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`");
56
+ const ac = new AbortController();
56
57
  const request = universalRequester((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, resolvedOpts), {}, {
57
58
  type,
58
59
  path,
59
60
  input,
60
- signal: op.signal,
61
+ signal: require_httpUtils.raceAbortSignals(op.signal, ac.signal),
61
62
  headers() {
62
63
  if (!opts.headers) return {};
63
64
  if (typeof opts.headers === "function") return opts.headers({ op });
64
65
  return opts.headers;
65
66
  }
66
67
  }));
68
+ let isDone = false;
67
69
  let meta = void 0;
68
70
  request.then((res) => {
71
+ isDone = true;
69
72
  meta = res.meta;
70
73
  const transformed = (0, __trpc_server_unstable_core_do_not_import.transformResult)(res.json, resolvedOpts.transformer.output);
71
74
  if (!transformed.ok) {
@@ -78,9 +81,12 @@ function httpLink(opts) {
78
81
  });
79
82
  observer.complete();
80
83
  }).catch((cause) => {
84
+ isDone = true;
81
85
  observer.error(require_TRPCClientError.TRPCClientError.from(cause, { meta }));
82
86
  });
83
- return () => {};
87
+ return () => {
88
+ if (!isDone) ac.abort();
89
+ };
84
90
  });
85
91
  };
86
92
  };
@@ -1,6 +1,6 @@
1
1
  import { __toESM, require_objectSpread2 } from "./objectSpread2-BvkFp-_Y.mjs";
2
2
  import { TRPCClientError } from "./TRPCClientError-apv8gw59.mjs";
3
- import { getUrl, httpRequest, jsonHttpRequester, resolveHTTPLinkOptions } from "./httpUtils-pyf5RF99.mjs";
3
+ import { getUrl, httpRequest, jsonHttpRequester, raceAbortSignals, resolveHTTPLinkOptions } from "./httpUtils-B2s2BleG.mjs";
4
4
  import { observable } from "@trpc/server/observable";
5
5
  import { transformResult } from "@trpc/server/unstable-core-do-not-import";
6
6
 
@@ -52,19 +52,22 @@ function httpLink(opts) {
52
52
  const { path, input, type } = op;
53
53
  /* istanbul ignore if -- @preserve */
54
54
  if (type === "subscription") throw new Error("Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`");
55
+ const ac = new AbortController();
55
56
  const request = universalRequester((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, resolvedOpts), {}, {
56
57
  type,
57
58
  path,
58
59
  input,
59
- signal: op.signal,
60
+ signal: raceAbortSignals(op.signal, ac.signal),
60
61
  headers() {
61
62
  if (!opts.headers) return {};
62
63
  if (typeof opts.headers === "function") return opts.headers({ op });
63
64
  return opts.headers;
64
65
  }
65
66
  }));
67
+ let isDone = false;
66
68
  let meta = void 0;
67
69
  request.then((res) => {
70
+ isDone = true;
68
71
  meta = res.meta;
69
72
  const transformed = transformResult(res.json, resolvedOpts.transformer.output);
70
73
  if (!transformed.ok) {
@@ -77,9 +80,12 @@ function httpLink(opts) {
77
80
  });
78
81
  observer.complete();
79
82
  }).catch((cause) => {
83
+ isDone = true;
80
84
  observer.error(TRPCClientError.from(cause, { meta }));
81
85
  });
82
- return () => {};
86
+ return () => {
87
+ if (!isDone) ac.abort();
88
+ };
83
89
  });
84
90
  };
85
91
  };
@@ -87,4 +93,4 @@ function httpLink(opts) {
87
93
 
88
94
  //#endregion
89
95
  export { httpLink, isFormData, isNonJsonSerializable, isOctetType };
90
- //# sourceMappingURL=httpLink-lG_6juPY.mjs.map
96
+ //# sourceMappingURL=httpLink-esWsGBTO.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpLink-esWsGBTO.mjs","names":["input: unknown","universalRequester: Requester","opts: HTTPLinkOptions<TRouter['_def']['_config']['$types']>","meta: HTTPResult['meta'] | undefined"],"sources":["../src/links/internals/contentTypes.ts","../src/links/httpLink.ts"],"sourcesContent":["export function isOctetType(\n input: unknown,\n): input is Uint8Array<ArrayBuffer> | Blob {\n return (\n input instanceof Uint8Array ||\n // File extends from Blob but is only available in nodejs from v20\n input instanceof Blob\n );\n}\n\nexport function isFormData(input: unknown) {\n return input instanceof FormData;\n}\n\nexport function isNonJsonSerializable(input: unknown) {\n return isOctetType(input) || isFormData(input);\n}\n","import { observable } from '@trpc/server/observable';\nimport type {\n AnyClientTypes,\n AnyRouter,\n} from '@trpc/server/unstable-core-do-not-import';\nimport { transformResult } from '@trpc/server/unstable-core-do-not-import';\nimport { raceAbortSignals } from '../internals/signals';\nimport { TRPCClientError } from '../TRPCClientError';\nimport type {\n HTTPLinkBaseOptions,\n HTTPResult,\n Requester,\n} from './internals/httpUtils';\nimport {\n getUrl,\n httpRequest,\n jsonHttpRequester,\n resolveHTTPLinkOptions,\n} from './internals/httpUtils';\nimport {\n isFormData,\n isOctetType,\n type HTTPHeaders,\n type Operation,\n type TRPCLink,\n} from './types';\n\nexport type HTTPLinkOptions<TRoot extends AnyClientTypes> =\n HTTPLinkBaseOptions<TRoot> & {\n /**\n * Headers to be set on outgoing requests or a callback that of said headers\n * @see http://trpc.io/docs/client/headers\n */\n headers?:\n | HTTPHeaders\n | ((opts: { op: Operation }) => HTTPHeaders | Promise<HTTPHeaders>);\n };\n\nconst universalRequester: Requester = (opts) => {\n if ('input' in opts) {\n const { input } = opts;\n if (isFormData(input)) {\n if (opts.type !== 'mutation' && opts.methodOverride !== 'POST') {\n throw new Error('FormData is only supported for mutations');\n }\n\n return httpRequest({\n ...opts,\n // The browser will set this automatically and include the boundary= in it\n contentTypeHeader: undefined,\n getUrl,\n getBody: () => input,\n });\n }\n\n if (isOctetType(input)) {\n if (opts.type !== 'mutation' && opts.methodOverride !== 'POST') {\n throw new Error('Octet type input is only supported for mutations');\n }\n\n return httpRequest({\n ...opts,\n contentTypeHeader: 'application/octet-stream',\n getUrl,\n getBody: () => input,\n });\n }\n }\n\n return jsonHttpRequester(opts);\n};\n\n/**\n * @see https://trpc.io/docs/client/links/httpLink\n */\nexport function httpLink<TRouter extends AnyRouter = AnyRouter>(\n opts: HTTPLinkOptions<TRouter['_def']['_config']['$types']>,\n): TRPCLink<TRouter> {\n const resolvedOpts = resolveHTTPLinkOptions(opts);\n return () => {\n return (operationOpts) => {\n const { op } = operationOpts;\n return observable((observer) => {\n const { path, input, type } = op;\n /* istanbul ignore if -- @preserve */\n if (type === 'subscription') {\n throw new Error(\n 'Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`',\n );\n }\n\n const ac = new AbortController();\n const request = universalRequester({\n ...resolvedOpts,\n type,\n path,\n input,\n signal: raceAbortSignals(op.signal, ac.signal),\n headers() {\n if (!opts.headers) {\n return {};\n }\n if (typeof opts.headers === 'function') {\n return opts.headers({\n op,\n });\n }\n return opts.headers;\n },\n });\n let isDone = false;\n let meta: HTTPResult['meta'] | undefined = undefined;\n request\n .then((res) => {\n isDone = true;\n meta = res.meta;\n const transformed = transformResult(\n res.json,\n resolvedOpts.transformer.output,\n );\n\n if (!transformed.ok) {\n observer.error(\n TRPCClientError.from(transformed.error, {\n meta,\n }),\n );\n return;\n }\n observer.next({\n context: res.meta,\n result: transformed.result,\n });\n observer.complete();\n })\n .catch((cause) => {\n isDone = true;\n observer.error(TRPCClientError.from(cause, { meta }));\n });\n\n return () => {\n if (!isDone) {\n ac.abort();\n }\n };\n });\n };\n };\n}\n"],"mappings":";;;;;;;AAAA,SAAgB,YACdA,OACyC;AACzC,QACE,iBAAiB,cAEjB,iBAAiB;AAEpB;AAED,SAAgB,WAAWA,OAAgB;AACzC,QAAO,iBAAiB;AACzB;AAED,SAAgB,sBAAsBA,OAAgB;AACpD,QAAO,YAAY,MAAM,IAAI,WAAW,MAAM;AAC/C;;;;;ACsBD,MAAMC,qBAAgC,CAAC,SAAS;AAC9C,KAAI,WAAW,MAAM;EACnB,MAAM,EAAE,OAAO,GAAG;AAClB,MAAI,WAAW,MAAM,EAAE;AACrB,OAAI,KAAK,SAAS,cAAc,KAAK,mBAAmB,OACtD,OAAM,IAAI,MAAM;AAGlB,UAAO,oFACF;IAEH;IACA;IACA,SAAS,MAAM;MACf;EACH;AAED,MAAI,YAAY,MAAM,EAAE;AACtB,OAAI,KAAK,SAAS,cAAc,KAAK,mBAAmB,OACtD,OAAM,IAAI,MAAM;AAGlB,UAAO,oFACF;IACH,mBAAmB;IACnB;IACA,SAAS,MAAM;MACf;EACH;CACF;AAED,QAAO,kBAAkB,KAAK;AAC/B;;;;AAKD,SAAgB,SACdC,MACmB;CACnB,MAAM,eAAe,uBAAuB,KAAK;AACjD,QAAO,MAAM;AACX,SAAO,CAAC,kBAAkB;GACxB,MAAM,EAAE,IAAI,GAAG;AACf,UAAO,WAAW,CAAC,aAAa;IAC9B,MAAM,EAAE,MAAM,OAAO,MAAM,GAAG;;AAE9B,QAAI,SAAS,eACX,OAAM,IAAI,MACR;IAIJ,MAAM,KAAK,IAAI;IACf,MAAM,UAAU,2FACX;KACH;KACA;KACA;KACA,QAAQ,iBAAiB,GAAG,QAAQ,GAAG,OAAO;KAC9C,UAAU;AACR,WAAK,KAAK,QACR,QAAO,CAAE;AAEX,iBAAW,KAAK,YAAY,WAC1B,QAAO,KAAK,QAAQ,EAClB,GACD,EAAC;AAEJ,aAAO,KAAK;KACb;OACD;IACF,IAAI,SAAS;IACb,IAAIC;AACJ,YACG,KAAK,CAAC,QAAQ;AACb,cAAS;AACT,YAAO,IAAI;KACX,MAAM,cAAc,gBAClB,IAAI,MACJ,aAAa,YAAY,OAC1B;AAED,UAAK,YAAY,IAAI;AACnB,eAAS,MACP,gBAAgB,KAAK,YAAY,OAAO,EACtC,KACD,EAAC,CACH;AACD;KACD;AACD,cAAS,KAAK;MACZ,SAAS,IAAI;MACb,QAAQ,YAAY;KACrB,EAAC;AACF,cAAS,UAAU;IACpB,EAAC,CACD,MAAM,CAAC,UAAU;AAChB,cAAS;AACT,cAAS,MAAM,gBAAgB,KAAK,OAAO,EAAE,KAAM,EAAC,CAAC;IACtD,EAAC;AAEJ,WAAO,MAAM;AACX,UAAK,OACH,IAAG,OAAO;IAEb;GACF,EAAC;EACH;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"httpLink.d-CVOTlkUT.d.mts","names":[],"sources":["../src/links/httpLink.ts"],"sourcesContent":[],"mappings":";;;;;KA0BY,8BAA8B,kBACxC,oBAAoB;;AADtB;;;EAAwD,OAClC,CAAA,EAMd,WANc,GAAA,CAAA,CAAA,IAAA,EAAA;IAApB,EAAA,EAOoB,SAPpB;EAAmB,CAAA,EAMb,GAC8B,WAD9B,GAC4C,OAD5C,CACoD,WADpD,CAAA,CAAA;CAAW;;;;AACwC,iBAwC3C,QAxC2C,CAAA,gBAwClB,SAxCkB,GAwCN,SAxCM,CAAA,CAAA,IAAA,EAyCnD,eAzCmD,CAyCnC,OAzCmC,CAAA,MAAA,CAAA,CAAA,SAAA,CAAA,CAAA,QAAA,CAAA,CAAA,CAAA,EA0CxD,QA1CwD,CA0C/C,OA1C+C,CAAA;AAwC3D"}
1
+ {"version":3,"file":"httpLink.d-CVOTlkUT.d.mts","names":[],"sources":["../src/links/httpLink.ts"],"sourcesContent":[],"mappings":";;;;;KA2BY,8BAA8B,kBACxC,oBAAoB;;AADtB;;;EAAwD,OAClC,CAAA,EAMd,WANc,GAAA,CAAA,CAAA,IAAA,EAAA;IAApB,EAAA,EAOoB,SAPpB;EAAmB,CAAA,EAMb,GAC8B,WAD9B,GAC4C,OAD5C,CACoD,WADpD,CAAA,CAAA;CAAW;;;;AACwC,iBAwC3C,QAxC2C,CAAA,gBAwClB,SAxCkB,GAwCN,SAxCM,CAAA,CAAA,IAAA,EAyCnD,eAzCmD,CAyCnC,OAzCmC,CAAA,MAAA,CAAA,CAAA,SAAA,CAAA,CAAA,QAAA,CAAA,CAAA,CAAA,EA0CxD,QA1CwD,CA0C/C,OA1C+C,CAAA;AAwC3D"}
@@ -1 +1 @@
1
- {"version":3,"file":"httpLink.d-D5qR9haY.d.cts","names":[],"sources":["../src/links/httpLink.ts"],"sourcesContent":[],"mappings":";;;;;KA0BY,8BAA8B,kBACxC,oBAAoB;;AADtB;;;EAAwD,OAClC,CAAA,EAMd,WANc,GAAA,CAAA,CAAA,IAAA,EAAA;IAApB,EAAA,EAOoB,SAPpB;EAAmB,CAAA,EAMb,GAC8B,WAD9B,GAC4C,OAD5C,CACoD,WADpD,CAAA,CAAA;CAAW;;;;AACwC,iBAwC3C,QAxC2C,CAAA,gBAwClB,SAxCkB,GAwCN,SAxCM,CAAA,CAAA,IAAA,EAyCnD,eAzCmD,CAyCnC,OAzCmC,CAAA,MAAA,CAAA,CAAA,SAAA,CAAA,CAAA,QAAA,CAAA,CAAA,CAAA,EA0CxD,QA1CwD,CA0C/C,OA1C+C,CAAA;AAwC3D"}
1
+ {"version":3,"file":"httpLink.d-D5qR9haY.d.cts","names":[],"sources":["../src/links/httpLink.ts"],"sourcesContent":[],"mappings":";;;;;KA2BY,8BAA8B,kBACxC,oBAAoB;;AADtB;;;EAAwD,OAClC,CAAA,EAMd,WANc,GAAA,CAAA,CAAA,IAAA,EAAA;IAApB,EAAA,EAOoB,SAPpB;EAAmB,CAAA,EAMb,GAC8B,WAD9B,GAC4C,OAD5C,CACoD,WADpD,CAAA,CAAA;CAAW;;;;AACwC,iBAwC3C,QAxC2C,CAAA,gBAwClB,SAxCkB,GAwCN,SAxCM,CAAA,CAAA,IAAA,EAyCnD,eAzCmD,CAyCnC,OAzCmC,CAAA,MAAA,CAAA,CAAA,SAAA,CAAA,CAAA,QAAA,CAAA,CAAA,CAAA,EA0CxD,QA1CwD,CA0C/C,OA1C+C,CAAA;AAwC3D"}
@@ -10,9 +10,51 @@ function getFetch(customFetchImpl) {
10
10
  throw new Error("No fetch implementation found");
11
11
  }
12
12
 
13
+ //#endregion
14
+ //#region src/internals/signals.ts
15
+ /**
16
+ * Like `Promise.all()` but for abort signals
17
+ * - When all signals have been aborted, the merged signal will be aborted
18
+ * - If one signal is `null`, no signal will be aborted
19
+ */
20
+ function allAbortSignals(...signals) {
21
+ const ac = new AbortController();
22
+ const count = signals.length;
23
+ let abortedCount = 0;
24
+ const onAbort = () => {
25
+ if (++abortedCount === count) ac.abort();
26
+ };
27
+ for (const signal of signals) if (signal === null || signal === void 0 ? void 0 : signal.aborted) onAbort();
28
+ else signal === null || signal === void 0 || signal.addEventListener("abort", onAbort, { once: true });
29
+ return ac.signal;
30
+ }
31
+ /**
32
+ * Like `Promise.race` but for abort signals
33
+ *
34
+ * Basically, a ponyfill for
35
+ * [`AbortSignal.any`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/any_static).
36
+ */
37
+ function raceAbortSignals(...signals) {
38
+ const ac = new AbortController();
39
+ for (const signal of signals) if (signal === null || signal === void 0 ? void 0 : signal.aborted) ac.abort();
40
+ else signal === null || signal === void 0 || signal.addEventListener("abort", () => ac.abort(), { once: true });
41
+ return ac.signal;
42
+ }
43
+ function abortSignalToPromise(signal) {
44
+ return new Promise((_, reject) => {
45
+ if (signal.aborted) {
46
+ reject(signal.reason);
47
+ return;
48
+ }
49
+ signal.addEventListener("abort", () => {
50
+ reject(signal.reason);
51
+ }, { once: true });
52
+ });
53
+ }
54
+
13
55
  //#endregion
14
56
  //#region src/links/internals/httpUtils.ts
15
- var import_objectSpread2 = __toESM(require_objectSpread2(), 1);
57
+ var import_objectSpread2 = __toESM(require_objectSpread2());
16
58
  function resolveHTTPLinkOptions(opts) {
17
59
  return {
18
60
  url: opts.url.toString(),
@@ -118,5 +160,5 @@ async function httpRequest(opts) {
118
160
  }
119
161
 
120
162
  //#endregion
121
- export { fetchHTTPResponse, getBody, getFetch, getUrl, httpRequest, jsonHttpRequester, resolveHTTPLinkOptions };
122
- //# sourceMappingURL=httpUtils-pyf5RF99.mjs.map
163
+ export { abortSignalToPromise, allAbortSignals, fetchHTTPResponse, getBody, getFetch, getUrl, httpRequest, jsonHttpRequester, raceAbortSignals, resolveHTTPLinkOptions };
164
+ //# sourceMappingURL=httpUtils-B2s2BleG.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpUtils-B2s2BleG.mjs","names":["fn: unknown","customFetchImpl?: FetchEsque | NativeFetchEsque","signal: AbortSignal","opts: HTTPLinkBaseOptions<AnyClientTypes>","array: unknown[]","dict: Record<number, unknown>","opts: GetInputOptions","getUrl: GetUrl","queryParts: string[]","getBody: GetBody","jsonHttpRequester: Requester","signal: Maybe<AbortSignal>","opts: HTTPRequestOptions"],"sources":["../src/getFetch.ts","../src/internals/signals.ts","../src/links/internals/httpUtils.ts"],"sourcesContent":["import type { FetchEsque, NativeFetchEsque } from './internals/types';\n\ntype AnyFn = (...args: any[]) => unknown;\n\nconst isFunction = (fn: unknown): fn is AnyFn => typeof fn === 'function';\n\nexport function getFetch(\n customFetchImpl?: FetchEsque | NativeFetchEsque,\n): FetchEsque {\n if (customFetchImpl) {\n return customFetchImpl as FetchEsque;\n }\n\n if (typeof window !== 'undefined' && isFunction(window.fetch)) {\n return window.fetch as FetchEsque;\n }\n\n if (typeof globalThis !== 'undefined' && isFunction(globalThis.fetch)) {\n return globalThis.fetch as FetchEsque;\n }\n\n throw new Error('No fetch implementation found');\n}\n","import type { Maybe } from '@trpc/server/unstable-core-do-not-import';\n\n/**\n * Like `Promise.all()` but for abort signals\n * - When all signals have been aborted, the merged signal will be aborted\n * - If one signal is `null`, no signal will be aborted\n */\nexport function allAbortSignals(...signals: Maybe<AbortSignal>[]): AbortSignal {\n const ac = new AbortController();\n\n const count = signals.length;\n\n let abortedCount = 0;\n\n const onAbort = () => {\n if (++abortedCount === count) {\n ac.abort();\n }\n };\n\n for (const signal of signals) {\n if (signal?.aborted) {\n onAbort();\n } else {\n signal?.addEventListener('abort', onAbort, {\n once: true,\n });\n }\n }\n\n return ac.signal;\n}\n\n/**\n * Like `Promise.race` but for abort signals\n *\n * Basically, a ponyfill for\n * [`AbortSignal.any`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/any_static).\n */\nexport function raceAbortSignals(\n ...signals: Maybe<AbortSignal>[]\n): AbortSignal {\n const ac = new AbortController();\n\n for (const signal of signals) {\n if (signal?.aborted) {\n ac.abort();\n } else {\n signal?.addEventListener('abort', () => ac.abort(), { once: true });\n }\n }\n\n return ac.signal;\n}\n\nexport function abortSignalToPromise(signal: AbortSignal): Promise<never> {\n return new Promise((_, reject) => {\n if (signal.aborted) {\n reject(signal.reason);\n return;\n }\n signal.addEventListener(\n 'abort',\n () => {\n reject(signal.reason);\n },\n { once: true },\n );\n });\n}\n","import type {\n AnyClientTypes,\n CombinedDataTransformer,\n Maybe,\n ProcedureType,\n TRPCAcceptHeader,\n TRPCResponse,\n} from '@trpc/server/unstable-core-do-not-import';\nimport { getFetch } from '../../getFetch';\nimport type {\n FetchEsque,\n RequestInitEsque,\n ResponseEsque,\n} from '../../internals/types';\nimport type { TransformerOptions } from '../../unstable-internals';\nimport { getTransformer } from '../../unstable-internals';\nimport type { HTTPHeaders } from '../types';\n\n/**\n * @internal\n */\nexport type HTTPLinkBaseOptions<\n TRoot extends Pick<AnyClientTypes, 'transformer'>,\n> = {\n url: string | URL;\n /**\n * Add ponyfill for fetch\n */\n fetch?: FetchEsque;\n /**\n * Send all requests `as POST`s requests regardless of the procedure type\n * The HTTP handler must separately allow overriding the method. See:\n * @see https://trpc.io/docs/rpc\n */\n methodOverride?: 'POST';\n} & TransformerOptions<TRoot>;\n\nexport interface ResolvedHTTPLinkOptions {\n url: string;\n fetch?: FetchEsque;\n transformer: CombinedDataTransformer;\n methodOverride?: 'POST';\n}\n\nexport function resolveHTTPLinkOptions(\n opts: HTTPLinkBaseOptions<AnyClientTypes>,\n): ResolvedHTTPLinkOptions {\n return {\n url: opts.url.toString(),\n fetch: opts.fetch,\n transformer: getTransformer(opts.transformer),\n methodOverride: opts.methodOverride,\n };\n}\n\n// https://github.com/trpc/trpc/pull/669\nfunction arrayToDict(array: unknown[]) {\n const dict: Record<number, unknown> = {};\n for (let index = 0; index < array.length; index++) {\n const element = array[index];\n dict[index] = element;\n }\n return dict;\n}\n\nconst METHOD = {\n query: 'GET',\n mutation: 'POST',\n subscription: 'PATCH',\n} as const;\n\nexport interface HTTPResult {\n json: TRPCResponse;\n meta: {\n response: ResponseEsque;\n responseJSON?: unknown;\n };\n}\n\ntype GetInputOptions = {\n transformer: CombinedDataTransformer;\n} & ({ input: unknown } | { inputs: unknown[] });\n\nexport function getInput(opts: GetInputOptions) {\n return 'input' in opts\n ? opts.transformer.input.serialize(opts.input)\n : arrayToDict(\n opts.inputs.map((_input) => opts.transformer.input.serialize(_input)),\n );\n}\n\nexport type HTTPBaseRequestOptions = GetInputOptions &\n ResolvedHTTPLinkOptions & {\n type: ProcedureType;\n path: string;\n signal: Maybe<AbortSignal>;\n };\n\ntype GetUrl = (opts: HTTPBaseRequestOptions) => string;\ntype GetBody = (opts: HTTPBaseRequestOptions) => RequestInitEsque['body'];\n\nexport type ContentOptions = {\n trpcAcceptHeader?: TRPCAcceptHeader;\n trpcAcceptHeaderKey?: 'trpc-accept' | 'accept';\n contentTypeHeader?: string;\n getUrl: GetUrl;\n getBody: GetBody;\n};\n\nexport const getUrl: GetUrl = (opts) => {\n const parts = opts.url.split('?') as [string, string?];\n const base = parts[0].replace(/\\/$/, ''); // Remove any trailing slashes\n\n let url = base + '/' + opts.path;\n const queryParts: string[] = [];\n\n if (parts[1]) {\n queryParts.push(parts[1]);\n }\n if ('inputs' in opts) {\n queryParts.push('batch=1');\n }\n if (opts.type === 'query' || opts.type === 'subscription') {\n const input = getInput(opts);\n if (input !== undefined && opts.methodOverride !== 'POST') {\n queryParts.push(`input=${encodeURIComponent(JSON.stringify(input))}`);\n }\n }\n if (queryParts.length) {\n url += '?' + queryParts.join('&');\n }\n return url;\n};\n\nexport const getBody: GetBody = (opts) => {\n if (opts.type === 'query' && opts.methodOverride !== 'POST') {\n return undefined;\n }\n const input = getInput(opts);\n return input !== undefined ? JSON.stringify(input) : undefined;\n};\n\nexport type Requester = (\n opts: HTTPBaseRequestOptions & {\n headers: () => HTTPHeaders | Promise<HTTPHeaders>;\n },\n) => Promise<HTTPResult>;\n\nexport const jsonHttpRequester: Requester = (opts) => {\n return httpRequest({\n ...opts,\n contentTypeHeader: 'application/json',\n getUrl,\n getBody,\n });\n};\n\n/**\n * Polyfill for DOMException with AbortError name\n */\nclass AbortError extends Error {\n constructor() {\n const name = 'AbortError';\n super(name);\n this.name = name;\n this.message = name;\n }\n}\n\nexport type HTTPRequestOptions = ContentOptions &\n HTTPBaseRequestOptions & {\n headers: () => HTTPHeaders | Promise<HTTPHeaders>;\n };\n\n/**\n * Polyfill for `signal.throwIfAborted()`\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/throwIfAborted\n */\nconst throwIfAborted = (signal: Maybe<AbortSignal>) => {\n if (!signal?.aborted) {\n return;\n }\n // If available, use the native implementation\n signal.throwIfAborted?.();\n\n // If we have `DOMException`, use it\n if (typeof DOMException !== 'undefined') {\n throw new DOMException('AbortError', 'AbortError');\n }\n\n // Otherwise, use our own implementation\n throw new AbortError();\n};\n\nexport async function fetchHTTPResponse(opts: HTTPRequestOptions) {\n throwIfAborted(opts.signal);\n\n const url = opts.getUrl(opts);\n const body = opts.getBody(opts);\n const method = opts.methodOverride ?? METHOD[opts.type];\n const resolvedHeaders = await (async () => {\n const heads = await opts.headers();\n if (Symbol.iterator in heads) {\n return Object.fromEntries(heads);\n }\n return heads;\n })();\n const headers = {\n ...(opts.contentTypeHeader && method !== 'GET'\n ? { 'content-type': opts.contentTypeHeader }\n : {}),\n ...(opts.trpcAcceptHeader\n ? { [opts.trpcAcceptHeaderKey ?? 'trpc-accept']: opts.trpcAcceptHeader }\n : undefined),\n ...resolvedHeaders,\n };\n\n return getFetch(opts.fetch)(url, {\n method,\n signal: opts.signal,\n body,\n headers,\n });\n}\n\nexport async function httpRequest(\n opts: HTTPRequestOptions,\n): Promise<HTTPResult> {\n const meta = {} as HTTPResult['meta'];\n\n const res = await fetchHTTPResponse(opts);\n meta.response = res;\n\n const json = await res.json();\n\n meta.responseJSON = json;\n\n return {\n json: json as TRPCResponse,\n meta,\n };\n}\n"],"mappings":"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"}
@@ -11,6 +11,48 @@ function getFetch(customFetchImpl) {
11
11
  throw new Error("No fetch implementation found");
12
12
  }
13
13
 
14
+ //#endregion
15
+ //#region src/internals/signals.ts
16
+ /**
17
+ * Like `Promise.all()` but for abort signals
18
+ * - When all signals have been aborted, the merged signal will be aborted
19
+ * - If one signal is `null`, no signal will be aborted
20
+ */
21
+ function allAbortSignals(...signals) {
22
+ const ac = new AbortController();
23
+ const count = signals.length;
24
+ let abortedCount = 0;
25
+ const onAbort = () => {
26
+ if (++abortedCount === count) ac.abort();
27
+ };
28
+ for (const signal of signals) if (signal === null || signal === void 0 ? void 0 : signal.aborted) onAbort();
29
+ else signal === null || signal === void 0 || signal.addEventListener("abort", onAbort, { once: true });
30
+ return ac.signal;
31
+ }
32
+ /**
33
+ * Like `Promise.race` but for abort signals
34
+ *
35
+ * Basically, a ponyfill for
36
+ * [`AbortSignal.any`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/any_static).
37
+ */
38
+ function raceAbortSignals(...signals) {
39
+ const ac = new AbortController();
40
+ for (const signal of signals) if (signal === null || signal === void 0 ? void 0 : signal.aborted) ac.abort();
41
+ else signal === null || signal === void 0 || signal.addEventListener("abort", () => ac.abort(), { once: true });
42
+ return ac.signal;
43
+ }
44
+ function abortSignalToPromise(signal) {
45
+ return new Promise((_, reject) => {
46
+ if (signal.aborted) {
47
+ reject(signal.reason);
48
+ return;
49
+ }
50
+ signal.addEventListener("abort", () => {
51
+ reject(signal.reason);
52
+ }, { once: true });
53
+ });
54
+ }
55
+
14
56
  //#endregion
15
57
  //#region src/links/internals/httpUtils.ts
16
58
  var import_objectSpread2 = require_chunk.__toESM(require_objectSpread2$1.require_objectSpread2(), 1);
@@ -119,6 +161,18 @@ async function httpRequest(opts) {
119
161
  }
120
162
 
121
163
  //#endregion
164
+ Object.defineProperty(exports, 'abortSignalToPromise', {
165
+ enumerable: true,
166
+ get: function () {
167
+ return abortSignalToPromise;
168
+ }
169
+ });
170
+ Object.defineProperty(exports, 'allAbortSignals', {
171
+ enumerable: true,
172
+ get: function () {
173
+ return allAbortSignals;
174
+ }
175
+ });
122
176
  Object.defineProperty(exports, 'fetchHTTPResponse', {
123
177
  enumerable: true,
124
178
  get: function () {
@@ -155,6 +209,12 @@ Object.defineProperty(exports, 'jsonHttpRequester', {
155
209
  return jsonHttpRequester;
156
210
  }
157
211
  });
212
+ Object.defineProperty(exports, 'raceAbortSignals', {
213
+ enumerable: true,
214
+ get: function () {
215
+ return raceAbortSignals;
216
+ }
217
+ });
158
218
  Object.defineProperty(exports, 'resolveHTTPLinkOptions', {
159
219
  enumerable: true,
160
220
  get: function () {
package/dist/index.cjs CHANGED
@@ -2,9 +2,9 @@ const require_chunk = require('./chunk-DWy1uDak.cjs');
2
2
  const require_splitLink = require('./splitLink-BMgxggng.cjs');
3
3
  const require_objectSpread2$1 = require('./objectSpread2-Bsvh_OqM.cjs');
4
4
  const require_TRPCClientError = require('./TRPCClientError-CQrTQLrk.cjs');
5
- const require_httpUtils = require('./httpUtils-wv2o-njD.cjs');
6
- const require_httpLink = require('./httpLink-B8Iv31Ee.cjs');
7
- const require_httpBatchLink = require('./httpBatchLink-BGZRsGNf.cjs');
5
+ const require_httpUtils = require('./httpUtils-s6LGgoIm.cjs');
6
+ const require_httpLink = require('./httpLink-CxKWeCm2.cjs');
7
+ const require_httpBatchLink = require('./httpBatchLink-CAxRfaIq.cjs');
8
8
  const require_unstable_internals = require('./unstable-internals-M84gUQCV.cjs');
9
9
  const require_loggerLink = require('./loggerLink-CuYvRzyH.cjs');
10
10
  const require_wsLink = require('./wsLink-adtuc895.cjs');
@@ -188,10 +188,10 @@ function httpBatchStreamLink(opts) {
188
188
  var _opts$streamHeader;
189
189
  const path = batchOps.map((op) => op.path).join(",");
190
190
  const inputs = batchOps.map((op) => op.input);
191
- const batchSignals = require_httpBatchLink.allAbortSignals(...batchOps.map((op) => op.signal));
191
+ const batchSignals = require_httpUtils.allAbortSignals(...batchOps.map((op) => op.signal));
192
192
  const abortController = new AbortController();
193
193
  const responsePromise = require_httpUtils.fetchHTTPResponse((0, import_objectSpread2$3.default)((0, import_objectSpread2$3.default)({}, resolvedOpts), {}, {
194
- signal: require_httpBatchLink.raceAbortSignals(batchSignals, abortController.signal),
194
+ signal: require_httpUtils.raceAbortSignals(batchSignals, abortController.signal),
195
195
  type,
196
196
  contentTypeHeader: "application/json",
197
197
  trpcAcceptHeader: "application/jsonl",
@@ -255,7 +255,7 @@ function httpBatchStreamLink(opts) {
255
255
  if (op.type === "subscription") throw new Error("Subscriptions are unsupported by `httpBatchStreamLink` - use `httpSubscriptionLink` or `wsLink`");
256
256
  const ac = new AbortController();
257
257
  const loader = loaders[op.type];
258
- const promise = loader.load((0, import_objectSpread2$3.default)((0, import_objectSpread2$3.default)({}, op), {}, { signal: require_httpBatchLink.raceAbortSignals(op.signal, ac.signal) }));
258
+ const promise = loader.load((0, import_objectSpread2$3.default)((0, import_objectSpread2$3.default)({}, op), {}, { signal: require_httpUtils.raceAbortSignals(op.signal, ac.signal) }));
259
259
  let isDone = false;
260
260
  let _res = void 0;
261
261
  promise.then((res) => {
@@ -371,7 +371,7 @@ function httpSubscriptionLink(opts) {
371
371
  if (type !== "subscription") throw new Error("httpSubscriptionLink only supports subscriptions");
372
372
  let lastEventId = void 0;
373
373
  const ac = new AbortController();
374
- const signal = require_httpBatchLink.raceAbortSignals(op.signal, ac.signal);
374
+ const signal = require_httpUtils.raceAbortSignals(op.signal, ac.signal);
375
375
  const eventSourceStream = (0, __trpc_server_unstable_core_do_not_import.sseStreamConsumer)({
376
376
  url: async () => require_httpUtils.getUrl({
377
377
  transformer,
@@ -725,8 +725,8 @@ function unstable_localLink(opts) {
725
725
  return () => ({ op }) => (0, __trpc_server_observable.observable)((observer) => {
726
726
  let ctx = void 0;
727
727
  const ac = new AbortController();
728
- const signal = require_httpBatchLink.raceAbortSignals(op.signal, ac.signal);
729
- const signalPromise = require_httpBatchLink.abortSignalToPromise(signal);
728
+ const signal = require_httpUtils.raceAbortSignals(op.signal, ac.signal);
729
+ const signalPromise = require_httpUtils.abortSignalToPromise(signal);
730
730
  signalPromise.catch(() => {});
731
731
  let input = op.input;
732
732
  async function runProcedure(newInput) {
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import { __commonJS, __toESM, require_defineProperty, require_objectSpread2 } from "./objectSpread2-BvkFp-_Y.mjs";
2
2
  import { createChain, splitLink } from "./splitLink-B7Cuf2c_.mjs";
3
3
  import { TRPCClientError, isTRPCClientError } from "./TRPCClientError-apv8gw59.mjs";
4
- import { fetchHTTPResponse, getBody, getFetch, getUrl, resolveHTTPLinkOptions } from "./httpUtils-pyf5RF99.mjs";
5
- import { httpLink, isFormData, isNonJsonSerializable, isOctetType } from "./httpLink-lG_6juPY.mjs";
6
- import { abortSignalToPromise, allAbortSignals, dataLoader, httpBatchLink, raceAbortSignals } from "./httpBatchLink-LhidKAPw.mjs";
4
+ import { abortSignalToPromise, allAbortSignals, fetchHTTPResponse, getBody, getFetch, getUrl, raceAbortSignals, resolveHTTPLinkOptions } from "./httpUtils-B2s2BleG.mjs";
5
+ import { httpLink, isFormData, isNonJsonSerializable, isOctetType } from "./httpLink-esWsGBTO.mjs";
6
+ import { dataLoader, httpBatchLink } from "./httpBatchLink-RBPi17Tn.mjs";
7
7
  import { getTransformer } from "./unstable-internals-Bg7n9BBj.mjs";
8
8
  import { loggerLink } from "./loggerLink-ineCN1PO.mjs";
9
9
  import { createWSClient, jsonEncoder, resultOf, wsLink } from "./wsLink-BClZ0qKo.mjs";
@@ -1,7 +1,7 @@
1
1
  require('../objectSpread2-Bsvh_OqM.cjs');
2
2
  require('../TRPCClientError-CQrTQLrk.cjs');
3
- require('../httpUtils-wv2o-njD.cjs');
4
- const require_httpBatchLink = require('../httpBatchLink-BGZRsGNf.cjs');
3
+ require('../httpUtils-s6LGgoIm.cjs');
4
+ const require_httpBatchLink = require('../httpBatchLink-CAxRfaIq.cjs');
5
5
  require('../unstable-internals-M84gUQCV.cjs');
6
6
 
7
7
  exports.httpBatchLink = require_httpBatchLink.httpBatchLink;
@@ -1,7 +1,7 @@
1
1
  import "../objectSpread2-BvkFp-_Y.mjs";
2
2
  import "../TRPCClientError-apv8gw59.mjs";
3
- import "../httpUtils-pyf5RF99.mjs";
4
- import { httpBatchLink } from "../httpBatchLink-LhidKAPw.mjs";
3
+ import "../httpUtils-B2s2BleG.mjs";
4
+ import { httpBatchLink } from "../httpBatchLink-RBPi17Tn.mjs";
5
5
  import "../unstable-internals-Bg7n9BBj.mjs";
6
6
 
7
7
  export { httpBatchLink };
@@ -1,7 +1,7 @@
1
1
  require('../objectSpread2-Bsvh_OqM.cjs');
2
2
  require('../TRPCClientError-CQrTQLrk.cjs');
3
- require('../httpUtils-wv2o-njD.cjs');
4
- const require_httpLink = require('../httpLink-B8Iv31Ee.cjs');
3
+ require('../httpUtils-s6LGgoIm.cjs');
4
+ const require_httpLink = require('../httpLink-CxKWeCm2.cjs');
5
5
  require('../unstable-internals-M84gUQCV.cjs');
6
6
 
7
7
  exports.httpLink = require_httpLink.httpLink;
@@ -1,7 +1,7 @@
1
1
  import "../objectSpread2-BvkFp-_Y.mjs";
2
2
  import "../TRPCClientError-apv8gw59.mjs";
3
- import "../httpUtils-pyf5RF99.mjs";
4
- import { httpLink } from "../httpLink-lG_6juPY.mjs";
3
+ import "../httpUtils-B2s2BleG.mjs";
4
+ import { httpLink } from "../httpLink-esWsGBTO.mjs";
5
5
  import "../unstable-internals-Bg7n9BBj.mjs";
6
6
 
7
7
  export { httpLink };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@trpc/client",
3
3
  "type": "module",
4
- "version": "11.18.1-canary.17+6408c54ba",
4
+ "version": "11.18.1-canary.19+d1a9ec68c",
5
5
  "description": "The tRPC client library",
6
6
  "author": "KATT",
7
7
  "license": "MIT",
@@ -145,5 +145,5 @@
145
145
  "bin": {
146
146
  "intent": "./bin/intent.js"
147
147
  },
148
- "gitHead": "6408c54ba9bea7b18c39be3a7abd79c8841a2333"
148
+ "gitHead": "d1a9ec68cea9740a5a46dcf98399d9a876f2313a"
149
149
  }
@@ -3,7 +3,7 @@ import { observable } from '@trpc/server/observable';
3
3
  import { transformResult } from '@trpc/server/unstable-core-do-not-import';
4
4
  import type { BatchLoader } from '../internals/dataLoader';
5
5
  import { dataLoader } from '../internals/dataLoader';
6
- import { allAbortSignals } from '../internals/signals';
6
+ import { allAbortSignals, raceAbortSignals } from '../internals/signals';
7
7
  import type { NonEmptyArray } from '../internals/types';
8
8
  import { TRPCClientError } from '../TRPCClientError';
9
9
  import type { HTTPBatchLinkOptions } from './HTTPBatchLinkOptions';
@@ -98,12 +98,18 @@ export function httpBatchLink<TRouter extends AnyRouter>(
98
98
  'Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`',
99
99
  );
100
100
  }
101
+ const ac = new AbortController();
101
102
  const loader = loaders[op.type];
102
- const promise = loader.load(op);
103
+ const promise = loader.load({
104
+ ...op,
105
+ signal: raceAbortSignals(op.signal, ac.signal),
106
+ });
103
107
 
108
+ let isDone = false;
104
109
  let _res = undefined as HTTPResult | undefined;
105
110
  promise
106
111
  .then((res) => {
112
+ isDone = true;
107
113
  _res = res;
108
114
  const transformed = transformResult(
109
115
  res.json,
@@ -125,6 +131,7 @@ export function httpBatchLink<TRouter extends AnyRouter>(
125
131
  observer.complete();
126
132
  })
127
133
  .catch((err) => {
134
+ isDone = true;
128
135
  observer.error(
129
136
  TRPCClientError.from(err, {
130
137
  meta: _res?.meta,
@@ -133,7 +140,9 @@ export function httpBatchLink<TRouter extends AnyRouter>(
133
140
  });
134
141
 
135
142
  return () => {
136
- // noop
143
+ if (!isDone) {
144
+ ac.abort();
145
+ }
137
146
  };
138
147
  });
139
148
  };
@@ -4,6 +4,7 @@ import type {
4
4
  AnyRouter,
5
5
  } from '@trpc/server/unstable-core-do-not-import';
6
6
  import { transformResult } from '@trpc/server/unstable-core-do-not-import';
7
+ import { raceAbortSignals } from '../internals/signals';
7
8
  import { TRPCClientError } from '../TRPCClientError';
8
9
  import type {
9
10
  HTTPLinkBaseOptions,
@@ -88,12 +89,13 @@ export function httpLink<TRouter extends AnyRouter = AnyRouter>(
88
89
  );
89
90
  }
90
91
 
92
+ const ac = new AbortController();
91
93
  const request = universalRequester({
92
94
  ...resolvedOpts,
93
95
  type,
94
96
  path,
95
97
  input,
96
- signal: op.signal,
98
+ signal: raceAbortSignals(op.signal, ac.signal),
97
99
  headers() {
98
100
  if (!opts.headers) {
99
101
  return {};
@@ -106,9 +108,11 @@ export function httpLink<TRouter extends AnyRouter = AnyRouter>(
106
108
  return opts.headers;
107
109
  },
108
110
  });
111
+ let isDone = false;
109
112
  let meta: HTTPResult['meta'] | undefined = undefined;
110
113
  request
111
114
  .then((res) => {
115
+ isDone = true;
112
116
  meta = res.meta;
113
117
  const transformed = transformResult(
114
118
  res.json,
@@ -130,11 +134,14 @@ export function httpLink<TRouter extends AnyRouter = AnyRouter>(
130
134
  observer.complete();
131
135
  })
132
136
  .catch((cause) => {
137
+ isDone = true;
133
138
  observer.error(TRPCClientError.from(cause, { meta }));
134
139
  });
135
140
 
136
141
  return () => {
137
- // noop
142
+ if (!isDone) {
143
+ ac.abort();
144
+ }
138
145
  };
139
146
  });
140
147
  };
@@ -1 +0,0 @@
1
- {"version":3,"file":"httpBatchLink-LhidKAPw.mjs","names":["batchLoader: BatchLoader<TKey, TValue>","pendingItems: BatchItem<TKey, TValue>[] | null","dispatchTimer: ReturnType<typeof setTimeout> | null","items: BatchItem<TKey, TValue>[]","groupedItems: BatchItem<TKey, TValue>[][]","batch: Batch<TKey, TValue>","key: TKey","item: BatchItem<TKey, TValue>","signal: AbortSignal","opts: HTTPBatchLinkOptions<TRouter['_def']['_config']['$types']>","type: ProcedureType"],"sources":["../src/internals/dataLoader.ts","../src/internals/signals.ts","../src/links/httpBatchLink.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\ntype BatchItem<TKey, TValue> = {\n aborted: boolean;\n key: TKey;\n resolve: ((value: TValue) => void) | null;\n reject: ((error: Error) => void) | null;\n batch: Batch<TKey, TValue> | null;\n};\ntype Batch<TKey, TValue> = {\n items: BatchItem<TKey, TValue>[];\n};\nexport type BatchLoader<TKey, TValue> = {\n validate: (keys: TKey[]) => boolean;\n fetch: (keys: TKey[]) => Promise<TValue[] | Promise<TValue>[]>;\n};\n\n/**\n * A function that should never be called unless we messed something up.\n */\nconst throwFatalError = () => {\n throw new Error(\n 'Something went wrong. Please submit an issue at https://github.com/trpc/trpc/issues/new',\n );\n};\n\n/**\n * Dataloader that's very inspired by https://github.com/graphql/dataloader\n * Less configuration, no caching, and allows you to cancel requests\n * When cancelling a single fetch the whole batch will be cancelled only when _all_ items are cancelled\n */\nexport function dataLoader<TKey, TValue>(\n batchLoader: BatchLoader<TKey, TValue>,\n) {\n let pendingItems: BatchItem<TKey, TValue>[] | null = null;\n let dispatchTimer: ReturnType<typeof setTimeout> | null = null;\n\n const destroyTimerAndPendingItems = () => {\n clearTimeout(dispatchTimer as any);\n dispatchTimer = null;\n pendingItems = null;\n };\n\n /**\n * Iterate through the items and split them into groups based on the `batchLoader`'s validate function\n */\n function groupItems(items: BatchItem<TKey, TValue>[]) {\n const groupedItems: BatchItem<TKey, TValue>[][] = [[]];\n let index = 0;\n while (true) {\n const item = items[index];\n if (!item) {\n // we're done\n break;\n }\n const lastGroup = groupedItems[groupedItems.length - 1]!;\n\n if (item.aborted) {\n // Item was aborted before it was dispatched\n item.reject?.(new Error('Aborted'));\n index++;\n continue;\n }\n\n const isValid = batchLoader.validate(\n lastGroup.concat(item).map((it) => it.key),\n );\n\n if (isValid) {\n lastGroup.push(item);\n index++;\n continue;\n }\n\n if (lastGroup.length === 0) {\n item.reject?.(new Error('Input is too big for a single dispatch'));\n index++;\n continue;\n }\n // Create new group, next iteration will try to add the item to that\n groupedItems.push([]);\n }\n return groupedItems;\n }\n\n function dispatch() {\n const groupedItems = groupItems(pendingItems!);\n destroyTimerAndPendingItems();\n\n // Create batches for each group of items\n for (const items of groupedItems) {\n if (!items.length) {\n continue;\n }\n const batch: Batch<TKey, TValue> = {\n items,\n };\n for (const item of items) {\n item.batch = batch;\n }\n const promise = batchLoader.fetch(batch.items.map((_item) => _item.key));\n\n promise\n .then(async (result) => {\n await Promise.all(\n result.map(async (valueOrPromise, index) => {\n const item = batch.items[index]!;\n try {\n const value = await Promise.resolve(valueOrPromise);\n\n item.resolve?.(value);\n } catch (cause) {\n item.reject?.(cause as Error);\n }\n\n item.batch = null;\n item.reject = null;\n item.resolve = null;\n }),\n );\n\n for (const item of batch.items) {\n item.reject?.(new Error('Missing result'));\n item.batch = null;\n }\n })\n .catch((cause) => {\n for (const item of batch.items) {\n item.reject?.(cause);\n item.batch = null;\n }\n });\n }\n }\n function load(key: TKey): Promise<TValue> {\n const item: BatchItem<TKey, TValue> = {\n aborted: false,\n key,\n batch: null,\n resolve: throwFatalError,\n reject: throwFatalError,\n };\n\n const promise = new Promise<TValue>((resolve, reject) => {\n item.reject = reject;\n item.resolve = resolve;\n\n pendingItems ??= [];\n pendingItems.push(item);\n });\n\n dispatchTimer ??= setTimeout(dispatch);\n\n return promise;\n }\n\n return {\n load,\n };\n}\n","import type { Maybe } from '@trpc/server/unstable-core-do-not-import';\n\n/**\n * Like `Promise.all()` but for abort signals\n * - When all signals have been aborted, the merged signal will be aborted\n * - If one signal is `null`, no signal will be aborted\n */\nexport function allAbortSignals(...signals: Maybe<AbortSignal>[]): AbortSignal {\n const ac = new AbortController();\n\n const count = signals.length;\n\n let abortedCount = 0;\n\n const onAbort = () => {\n if (++abortedCount === count) {\n ac.abort();\n }\n };\n\n for (const signal of signals) {\n if (signal?.aborted) {\n onAbort();\n } else {\n signal?.addEventListener('abort', onAbort, {\n once: true,\n });\n }\n }\n\n return ac.signal;\n}\n\n/**\n * Like `Promise.race` but for abort signals\n *\n * Basically, a ponyfill for\n * [`AbortSignal.any`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/any_static).\n */\nexport function raceAbortSignals(\n ...signals: Maybe<AbortSignal>[]\n): AbortSignal {\n const ac = new AbortController();\n\n for (const signal of signals) {\n if (signal?.aborted) {\n ac.abort();\n } else {\n signal?.addEventListener('abort', () => ac.abort(), { once: true });\n }\n }\n\n return ac.signal;\n}\n\nexport function abortSignalToPromise(signal: AbortSignal): Promise<never> {\n return new Promise((_, reject) => {\n if (signal.aborted) {\n reject(signal.reason);\n return;\n }\n signal.addEventListener(\n 'abort',\n () => {\n reject(signal.reason);\n },\n { once: true },\n );\n });\n}\n","import type { AnyRouter, ProcedureType } from '@trpc/server';\nimport { observable } from '@trpc/server/observable';\nimport { transformResult } from '@trpc/server/unstable-core-do-not-import';\nimport type { BatchLoader } from '../internals/dataLoader';\nimport { dataLoader } from '../internals/dataLoader';\nimport { allAbortSignals } from '../internals/signals';\nimport type { NonEmptyArray } from '../internals/types';\nimport { TRPCClientError } from '../TRPCClientError';\nimport type { HTTPBatchLinkOptions } from './HTTPBatchLinkOptions';\nimport type { HTTPResult } from './internals/httpUtils';\nimport {\n getUrl,\n jsonHttpRequester,\n resolveHTTPLinkOptions,\n} from './internals/httpUtils';\nimport type { Operation, TRPCLink } from './types';\n\n/**\n * @see https://trpc.io/docs/client/links/httpBatchLink\n */\nexport function httpBatchLink<TRouter extends AnyRouter>(\n opts: HTTPBatchLinkOptions<TRouter['_def']['_config']['$types']>,\n): TRPCLink<TRouter> {\n const resolvedOpts = resolveHTTPLinkOptions(opts);\n const maxURLLength = opts.maxURLLength ?? Infinity;\n const maxItems = opts.maxItems ?? Infinity;\n\n return () => {\n const batchLoader = (\n type: ProcedureType,\n ): BatchLoader<Operation, HTTPResult> => {\n return {\n validate(batchOps) {\n if (maxURLLength === Infinity && maxItems === Infinity) {\n // escape hatch for quick calcs\n return true;\n }\n if (batchOps.length > maxItems) {\n return false;\n }\n const path = batchOps.map((op) => op.path).join(',');\n const inputs = batchOps.map((op) => op.input);\n\n const url = getUrl({\n ...resolvedOpts,\n type,\n path,\n inputs,\n signal: null,\n });\n\n return url.length <= maxURLLength;\n },\n async fetch(batchOps) {\n const path = batchOps.map((op) => op.path).join(',');\n const inputs = batchOps.map((op) => op.input);\n const signal = allAbortSignals(...batchOps.map((op) => op.signal));\n\n const res = await jsonHttpRequester({\n ...resolvedOpts,\n path,\n inputs,\n type,\n headers() {\n if (!opts.headers) {\n return {};\n }\n if (typeof opts.headers === 'function') {\n return opts.headers({\n opList: batchOps as NonEmptyArray<Operation>,\n });\n }\n return opts.headers;\n },\n signal,\n });\n const resJSON = Array.isArray(res.json)\n ? res.json\n : batchOps.map(() => res.json);\n const result = resJSON.map((item) => ({\n meta: res.meta,\n json: item,\n }));\n return result;\n },\n };\n };\n\n const query = dataLoader(batchLoader('query'));\n const mutation = dataLoader(batchLoader('mutation'));\n\n const loaders = { query, mutation };\n return ({ op }) => {\n return observable((observer) => {\n /* istanbul ignore if -- @preserve */\n if (op.type === 'subscription') {\n throw new Error(\n 'Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`',\n );\n }\n const loader = loaders[op.type];\n const promise = loader.load(op);\n\n let _res = undefined as HTTPResult | undefined;\n promise\n .then((res) => {\n _res = res;\n const transformed = transformResult(\n res.json,\n resolvedOpts.transformer.output,\n );\n\n if (!transformed.ok) {\n observer.error(\n TRPCClientError.from(transformed.error, {\n meta: res.meta,\n }),\n );\n return;\n }\n observer.next({\n context: res.meta,\n result: transformed.result,\n });\n observer.complete();\n })\n .catch((err) => {\n observer.error(\n TRPCClientError.from(err, {\n meta: _res?.meta,\n }),\n );\n });\n\n return () => {\n // noop\n };\n });\n };\n };\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"httpLink-lG_6juPY.mjs","names":["input: unknown","universalRequester: Requester","opts: HTTPLinkOptions<TRouter['_def']['_config']['$types']>","meta: HTTPResult['meta'] | undefined"],"sources":["../src/links/internals/contentTypes.ts","../src/links/httpLink.ts"],"sourcesContent":["export function isOctetType(\n input: unknown,\n): input is Uint8Array<ArrayBuffer> | Blob {\n return (\n input instanceof Uint8Array ||\n // File extends from Blob but is only available in nodejs from v20\n input instanceof Blob\n );\n}\n\nexport function isFormData(input: unknown) {\n return input instanceof FormData;\n}\n\nexport function isNonJsonSerializable(input: unknown) {\n return isOctetType(input) || isFormData(input);\n}\n","import { observable } from '@trpc/server/observable';\nimport type {\n AnyClientTypes,\n AnyRouter,\n} from '@trpc/server/unstable-core-do-not-import';\nimport { transformResult } from '@trpc/server/unstable-core-do-not-import';\nimport { TRPCClientError } from '../TRPCClientError';\nimport type {\n HTTPLinkBaseOptions,\n HTTPResult,\n Requester,\n} from './internals/httpUtils';\nimport {\n getUrl,\n httpRequest,\n jsonHttpRequester,\n resolveHTTPLinkOptions,\n} from './internals/httpUtils';\nimport {\n isFormData,\n isOctetType,\n type HTTPHeaders,\n type Operation,\n type TRPCLink,\n} from './types';\n\nexport type HTTPLinkOptions<TRoot extends AnyClientTypes> =\n HTTPLinkBaseOptions<TRoot> & {\n /**\n * Headers to be set on outgoing requests or a callback that of said headers\n * @see http://trpc.io/docs/client/headers\n */\n headers?:\n | HTTPHeaders\n | ((opts: { op: Operation }) => HTTPHeaders | Promise<HTTPHeaders>);\n };\n\nconst universalRequester: Requester = (opts) => {\n if ('input' in opts) {\n const { input } = opts;\n if (isFormData(input)) {\n if (opts.type !== 'mutation' && opts.methodOverride !== 'POST') {\n throw new Error('FormData is only supported for mutations');\n }\n\n return httpRequest({\n ...opts,\n // The browser will set this automatically and include the boundary= in it\n contentTypeHeader: undefined,\n getUrl,\n getBody: () => input,\n });\n }\n\n if (isOctetType(input)) {\n if (opts.type !== 'mutation' && opts.methodOverride !== 'POST') {\n throw new Error('Octet type input is only supported for mutations');\n }\n\n return httpRequest({\n ...opts,\n contentTypeHeader: 'application/octet-stream',\n getUrl,\n getBody: () => input,\n });\n }\n }\n\n return jsonHttpRequester(opts);\n};\n\n/**\n * @see https://trpc.io/docs/client/links/httpLink\n */\nexport function httpLink<TRouter extends AnyRouter = AnyRouter>(\n opts: HTTPLinkOptions<TRouter['_def']['_config']['$types']>,\n): TRPCLink<TRouter> {\n const resolvedOpts = resolveHTTPLinkOptions(opts);\n return () => {\n return (operationOpts) => {\n const { op } = operationOpts;\n return observable((observer) => {\n const { path, input, type } = op;\n /* istanbul ignore if -- @preserve */\n if (type === 'subscription') {\n throw new Error(\n 'Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`',\n );\n }\n\n const request = universalRequester({\n ...resolvedOpts,\n type,\n path,\n input,\n signal: op.signal,\n headers() {\n if (!opts.headers) {\n return {};\n }\n if (typeof opts.headers === 'function') {\n return opts.headers({\n op,\n });\n }\n return opts.headers;\n },\n });\n let meta: HTTPResult['meta'] | undefined = undefined;\n request\n .then((res) => {\n meta = res.meta;\n const transformed = transformResult(\n res.json,\n resolvedOpts.transformer.output,\n );\n\n if (!transformed.ok) {\n observer.error(\n TRPCClientError.from(transformed.error, {\n meta,\n }),\n );\n return;\n }\n observer.next({\n context: res.meta,\n result: transformed.result,\n });\n observer.complete();\n })\n .catch((cause) => {\n observer.error(TRPCClientError.from(cause, { meta }));\n });\n\n return () => {\n // noop\n };\n });\n };\n };\n}\n"],"mappings":";;;;;;;AAAA,SAAgB,YACdA,OACyC;AACzC,QACE,iBAAiB,cAEjB,iBAAiB;AAEpB;AAED,SAAgB,WAAWA,OAAgB;AACzC,QAAO,iBAAiB;AACzB;AAED,SAAgB,sBAAsBA,OAAgB;AACpD,QAAO,YAAY,MAAM,IAAI,WAAW,MAAM;AAC/C;;;;;ACqBD,MAAMC,qBAAgC,CAAC,SAAS;AAC9C,KAAI,WAAW,MAAM;EACnB,MAAM,EAAE,OAAO,GAAG;AAClB,MAAI,WAAW,MAAM,EAAE;AACrB,OAAI,KAAK,SAAS,cAAc,KAAK,mBAAmB,OACtD,OAAM,IAAI,MAAM;AAGlB,UAAO,oFACF;IAEH;IACA;IACA,SAAS,MAAM;MACf;EACH;AAED,MAAI,YAAY,MAAM,EAAE;AACtB,OAAI,KAAK,SAAS,cAAc,KAAK,mBAAmB,OACtD,OAAM,IAAI,MAAM;AAGlB,UAAO,oFACF;IACH,mBAAmB;IACnB;IACA,SAAS,MAAM;MACf;EACH;CACF;AAED,QAAO,kBAAkB,KAAK;AAC/B;;;;AAKD,SAAgB,SACdC,MACmB;CACnB,MAAM,eAAe,uBAAuB,KAAK;AACjD,QAAO,MAAM;AACX,SAAO,CAAC,kBAAkB;GACxB,MAAM,EAAE,IAAI,GAAG;AACf,UAAO,WAAW,CAAC,aAAa;IAC9B,MAAM,EAAE,MAAM,OAAO,MAAM,GAAG;;AAE9B,QAAI,SAAS,eACX,OAAM,IAAI,MACR;IAIJ,MAAM,UAAU,2FACX;KACH;KACA;KACA;KACA,QAAQ,GAAG;KACX,UAAU;AACR,WAAK,KAAK,QACR,QAAO,CAAE;AAEX,iBAAW,KAAK,YAAY,WAC1B,QAAO,KAAK,QAAQ,EAClB,GACD,EAAC;AAEJ,aAAO,KAAK;KACb;OACD;IACF,IAAIC;AACJ,YACG,KAAK,CAAC,QAAQ;AACb,YAAO,IAAI;KACX,MAAM,cAAc,gBAClB,IAAI,MACJ,aAAa,YAAY,OAC1B;AAED,UAAK,YAAY,IAAI;AACnB,eAAS,MACP,gBAAgB,KAAK,YAAY,OAAO,EACtC,KACD,EAAC,CACH;AACD;KACD;AACD,cAAS,KAAK;MACZ,SAAS,IAAI;MACb,QAAQ,YAAY;KACrB,EAAC;AACF,cAAS,UAAU;IACpB,EAAC,CACD,MAAM,CAAC,UAAU;AAChB,cAAS,MAAM,gBAAgB,KAAK,OAAO,EAAE,KAAM,EAAC,CAAC;IACtD,EAAC;AAEJ,WAAO,MAAM,CAEZ;GACF,EAAC;EACH;CACF;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"httpUtils-pyf5RF99.mjs","names":["fn: unknown","customFetchImpl?: FetchEsque | NativeFetchEsque","opts: HTTPLinkBaseOptions<AnyClientTypes>","array: unknown[]","dict: Record<number, unknown>","opts: GetInputOptions","getUrl: GetUrl","queryParts: string[]","getBody: GetBody","jsonHttpRequester: Requester","signal: Maybe<AbortSignal>","opts: HTTPRequestOptions"],"sources":["../src/getFetch.ts","../src/links/internals/httpUtils.ts"],"sourcesContent":["import type { FetchEsque, NativeFetchEsque } from './internals/types';\n\ntype AnyFn = (...args: any[]) => unknown;\n\nconst isFunction = (fn: unknown): fn is AnyFn => typeof fn === 'function';\n\nexport function getFetch(\n customFetchImpl?: FetchEsque | NativeFetchEsque,\n): FetchEsque {\n if (customFetchImpl) {\n return customFetchImpl as FetchEsque;\n }\n\n if (typeof window !== 'undefined' && isFunction(window.fetch)) {\n return window.fetch as FetchEsque;\n }\n\n if (typeof globalThis !== 'undefined' && isFunction(globalThis.fetch)) {\n return globalThis.fetch as FetchEsque;\n }\n\n throw new Error('No fetch implementation found');\n}\n","import type {\n AnyClientTypes,\n CombinedDataTransformer,\n Maybe,\n ProcedureType,\n TRPCAcceptHeader,\n TRPCResponse,\n} from '@trpc/server/unstable-core-do-not-import';\nimport { getFetch } from '../../getFetch';\nimport type {\n FetchEsque,\n RequestInitEsque,\n ResponseEsque,\n} from '../../internals/types';\nimport type { TransformerOptions } from '../../unstable-internals';\nimport { getTransformer } from '../../unstable-internals';\nimport type { HTTPHeaders } from '../types';\n\n/**\n * @internal\n */\nexport type HTTPLinkBaseOptions<\n TRoot extends Pick<AnyClientTypes, 'transformer'>,\n> = {\n url: string | URL;\n /**\n * Add ponyfill for fetch\n */\n fetch?: FetchEsque;\n /**\n * Send all requests `as POST`s requests regardless of the procedure type\n * The HTTP handler must separately allow overriding the method. See:\n * @see https://trpc.io/docs/rpc\n */\n methodOverride?: 'POST';\n} & TransformerOptions<TRoot>;\n\nexport interface ResolvedHTTPLinkOptions {\n url: string;\n fetch?: FetchEsque;\n transformer: CombinedDataTransformer;\n methodOverride?: 'POST';\n}\n\nexport function resolveHTTPLinkOptions(\n opts: HTTPLinkBaseOptions<AnyClientTypes>,\n): ResolvedHTTPLinkOptions {\n return {\n url: opts.url.toString(),\n fetch: opts.fetch,\n transformer: getTransformer(opts.transformer),\n methodOverride: opts.methodOverride,\n };\n}\n\n// https://github.com/trpc/trpc/pull/669\nfunction arrayToDict(array: unknown[]) {\n const dict: Record<number, unknown> = {};\n for (let index = 0; index < array.length; index++) {\n const element = array[index];\n dict[index] = element;\n }\n return dict;\n}\n\nconst METHOD = {\n query: 'GET',\n mutation: 'POST',\n subscription: 'PATCH',\n} as const;\n\nexport interface HTTPResult {\n json: TRPCResponse;\n meta: {\n response: ResponseEsque;\n responseJSON?: unknown;\n };\n}\n\ntype GetInputOptions = {\n transformer: CombinedDataTransformer;\n} & ({ input: unknown } | { inputs: unknown[] });\n\nexport function getInput(opts: GetInputOptions) {\n return 'input' in opts\n ? opts.transformer.input.serialize(opts.input)\n : arrayToDict(\n opts.inputs.map((_input) => opts.transformer.input.serialize(_input)),\n );\n}\n\nexport type HTTPBaseRequestOptions = GetInputOptions &\n ResolvedHTTPLinkOptions & {\n type: ProcedureType;\n path: string;\n signal: Maybe<AbortSignal>;\n };\n\ntype GetUrl = (opts: HTTPBaseRequestOptions) => string;\ntype GetBody = (opts: HTTPBaseRequestOptions) => RequestInitEsque['body'];\n\nexport type ContentOptions = {\n trpcAcceptHeader?: TRPCAcceptHeader;\n trpcAcceptHeaderKey?: 'trpc-accept' | 'accept';\n contentTypeHeader?: string;\n getUrl: GetUrl;\n getBody: GetBody;\n};\n\nexport const getUrl: GetUrl = (opts) => {\n const parts = opts.url.split('?') as [string, string?];\n const base = parts[0].replace(/\\/$/, ''); // Remove any trailing slashes\n\n let url = base + '/' + opts.path;\n const queryParts: string[] = [];\n\n if (parts[1]) {\n queryParts.push(parts[1]);\n }\n if ('inputs' in opts) {\n queryParts.push('batch=1');\n }\n if (opts.type === 'query' || opts.type === 'subscription') {\n const input = getInput(opts);\n if (input !== undefined && opts.methodOverride !== 'POST') {\n queryParts.push(`input=${encodeURIComponent(JSON.stringify(input))}`);\n }\n }\n if (queryParts.length) {\n url += '?' + queryParts.join('&');\n }\n return url;\n};\n\nexport const getBody: GetBody = (opts) => {\n if (opts.type === 'query' && opts.methodOverride !== 'POST') {\n return undefined;\n }\n const input = getInput(opts);\n return input !== undefined ? JSON.stringify(input) : undefined;\n};\n\nexport type Requester = (\n opts: HTTPBaseRequestOptions & {\n headers: () => HTTPHeaders | Promise<HTTPHeaders>;\n },\n) => Promise<HTTPResult>;\n\nexport const jsonHttpRequester: Requester = (opts) => {\n return httpRequest({\n ...opts,\n contentTypeHeader: 'application/json',\n getUrl,\n getBody,\n });\n};\n\n/**\n * Polyfill for DOMException with AbortError name\n */\nclass AbortError extends Error {\n constructor() {\n const name = 'AbortError';\n super(name);\n this.name = name;\n this.message = name;\n }\n}\n\nexport type HTTPRequestOptions = ContentOptions &\n HTTPBaseRequestOptions & {\n headers: () => HTTPHeaders | Promise<HTTPHeaders>;\n };\n\n/**\n * Polyfill for `signal.throwIfAborted()`\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/throwIfAborted\n */\nconst throwIfAborted = (signal: Maybe<AbortSignal>) => {\n if (!signal?.aborted) {\n return;\n }\n // If available, use the native implementation\n signal.throwIfAborted?.();\n\n // If we have `DOMException`, use it\n if (typeof DOMException !== 'undefined') {\n throw new DOMException('AbortError', 'AbortError');\n }\n\n // Otherwise, use our own implementation\n throw new AbortError();\n};\n\nexport async function fetchHTTPResponse(opts: HTTPRequestOptions) {\n throwIfAborted(opts.signal);\n\n const url = opts.getUrl(opts);\n const body = opts.getBody(opts);\n const method = opts.methodOverride ?? METHOD[opts.type];\n const resolvedHeaders = await (async () => {\n const heads = await opts.headers();\n if (Symbol.iterator in heads) {\n return Object.fromEntries(heads);\n }\n return heads;\n })();\n const headers = {\n ...(opts.contentTypeHeader && method !== 'GET'\n ? { 'content-type': opts.contentTypeHeader }\n : {}),\n ...(opts.trpcAcceptHeader\n ? { [opts.trpcAcceptHeaderKey ?? 'trpc-accept']: opts.trpcAcceptHeader }\n : undefined),\n ...resolvedHeaders,\n };\n\n return getFetch(opts.fetch)(url, {\n method,\n signal: opts.signal,\n body,\n headers,\n });\n}\n\nexport async function httpRequest(\n opts: HTTPRequestOptions,\n): Promise<HTTPResult> {\n const meta = {} as HTTPResult['meta'];\n\n const res = await fetchHTTPResponse(opts);\n meta.response = res;\n\n const json = await res.json();\n\n meta.responseJSON = json;\n\n return {\n json: json as TRPCResponse,\n meta,\n };\n}\n"],"mappings":"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"}