@trpc/client
Advanced tools
| import { __toESM, require_objectSpread2 } from "./objectSpread2-BvkFp-_Y.mjs"; | ||
| import { TRPCClientError } from "./TRPCClientError-apv8gw59.mjs"; | ||
| import { getUrl, jsonHttpRequester, resolveHTTPLinkOptions } from "./httpUtils-D61f8fkr.mjs"; | ||
| import { observable } from "@trpc/server/observable"; | ||
| import { transformResult } from "@trpc/server/unstable-core-do-not-import"; | ||
| //#region src/internals/dataLoader.ts | ||
| /** | ||
| * A function that should never be called unless we messed something up. | ||
| */ | ||
| const throwFatalError = () => { | ||
| throw new Error("Something went wrong. Please submit an issue at https://github.com/trpc/trpc/issues/new"); | ||
| }; | ||
| /** | ||
| * Dataloader that's very inspired by https://github.com/graphql/dataloader | ||
| * Less configuration, no caching, and allows you to cancel requests | ||
| * When cancelling a single fetch the whole batch will be cancelled only when _all_ items are cancelled | ||
| */ | ||
| function dataLoader(batchLoader) { | ||
| let pendingItems = null; | ||
| let dispatchTimer = null; | ||
| const destroyTimerAndPendingItems = () => { | ||
| clearTimeout(dispatchTimer); | ||
| dispatchTimer = null; | ||
| pendingItems = null; | ||
| }; | ||
| /** | ||
| * Iterate through the items and split them into groups based on the `batchLoader`'s validate function | ||
| */ | ||
| function groupItems(items) { | ||
| const groupedItems = [[]]; | ||
| let index = 0; | ||
| while (true) { | ||
| const item = items[index]; | ||
| if (!item) break; | ||
| const lastGroup = groupedItems[groupedItems.length - 1]; | ||
| if (item.aborted) { | ||
| var _item$reject; | ||
| (_item$reject = item.reject) === null || _item$reject === void 0 || _item$reject.call(item, new Error("Aborted")); | ||
| index++; | ||
| continue; | ||
| } | ||
| const isValid = batchLoader.validate(lastGroup.concat(item).map((it) => it.key)); | ||
| if (isValid) { | ||
| lastGroup.push(item); | ||
| index++; | ||
| continue; | ||
| } | ||
| if (lastGroup.length === 0) { | ||
| var _item$reject2; | ||
| (_item$reject2 = item.reject) === null || _item$reject2 === void 0 || _item$reject2.call(item, new Error("Input is too big for a single dispatch")); | ||
| index++; | ||
| continue; | ||
| } | ||
| groupedItems.push([]); | ||
| } | ||
| return groupedItems; | ||
| } | ||
| function dispatch() { | ||
| const groupedItems = groupItems(pendingItems); | ||
| destroyTimerAndPendingItems(); | ||
| for (const items of groupedItems) { | ||
| if (!items.length) continue; | ||
| const batch = { items }; | ||
| for (const item of items) item.batch = batch; | ||
| const promise = batchLoader.fetch(batch.items.map((_item) => _item.key)); | ||
| promise.then(async (result) => { | ||
| await Promise.all(result.map(async (valueOrPromise, index) => { | ||
| const item = batch.items[index]; | ||
| try { | ||
| var _item$resolve; | ||
| const value = await Promise.resolve(valueOrPromise); | ||
| (_item$resolve = item.resolve) === null || _item$resolve === void 0 || _item$resolve.call(item, value); | ||
| } catch (cause) { | ||
| var _item$reject3; | ||
| (_item$reject3 = item.reject) === null || _item$reject3 === void 0 || _item$reject3.call(item, cause); | ||
| } | ||
| item.batch = null; | ||
| item.reject = null; | ||
| item.resolve = null; | ||
| })); | ||
| for (const item of batch.items) { | ||
| var _item$reject4; | ||
| (_item$reject4 = item.reject) === null || _item$reject4 === void 0 || _item$reject4.call(item, new Error("Missing result")); | ||
| item.batch = null; | ||
| } | ||
| }).catch((cause) => { | ||
| for (const item of batch.items) { | ||
| var _item$reject5; | ||
| (_item$reject5 = item.reject) === null || _item$reject5 === void 0 || _item$reject5.call(item, cause); | ||
| item.batch = null; | ||
| } | ||
| }); | ||
| } | ||
| } | ||
| function load(key) { | ||
| var _dispatchTimer; | ||
| const item = { | ||
| aborted: false, | ||
| key, | ||
| batch: null, | ||
| resolve: throwFatalError, | ||
| reject: throwFatalError | ||
| }; | ||
| const promise = new Promise((resolve, reject) => { | ||
| var _pendingItems; | ||
| item.reject = reject; | ||
| item.resolve = resolve; | ||
| (_pendingItems = pendingItems) !== null && _pendingItems !== void 0 || (pendingItems = []); | ||
| pendingItems.push(item); | ||
| }); | ||
| (_dispatchTimer = dispatchTimer) !== null && _dispatchTimer !== void 0 || (dispatchTimer = setTimeout(dispatch)); | ||
| return promise; | ||
| } | ||
| return { load }; | ||
| } | ||
| //#endregion | ||
| //#region src/internals/signals.ts | ||
| /** | ||
| * Like `Promise.all()` but for abort signals | ||
| * - When all signals have been aborted, the merged signal will be aborted | ||
| * - If one signal is `null`, no signal will be aborted | ||
| */ | ||
| function allAbortSignals(...signals) { | ||
| const ac = new AbortController(); | ||
| const count = signals.length; | ||
| let abortedCount = 0; | ||
| const onAbort = () => { | ||
| if (++abortedCount === count) ac.abort(); | ||
| }; | ||
| for (const signal of signals) if (signal === null || signal === void 0 ? void 0 : signal.aborted) onAbort(); | ||
| else signal === null || signal === void 0 || signal.addEventListener("abort", onAbort, { once: true }); | ||
| return ac.signal; | ||
| } | ||
| /** | ||
| * Like `Promise.race` but for abort signals | ||
| * | ||
| * Basically, a ponyfill for | ||
| * [`AbortSignal.any`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/any_static). | ||
| */ | ||
| function raceAbortSignals(...signals) { | ||
| const ac = new AbortController(); | ||
| for (const signal of signals) if (signal === null || signal === void 0 ? void 0 : signal.aborted) ac.abort(); | ||
| else signal === null || signal === void 0 || signal.addEventListener("abort", () => ac.abort(), { once: true }); | ||
| return ac.signal; | ||
| } | ||
| function abortSignalToPromise(signal) { | ||
| return new Promise((_, reject) => { | ||
| if (signal.aborted) { | ||
| reject(signal.reason); | ||
| return; | ||
| } | ||
| signal.addEventListener("abort", () => { | ||
| reject(signal.reason); | ||
| }, { once: true }); | ||
| }); | ||
| } | ||
| //#endregion | ||
| //#region src/links/httpBatchLink.ts | ||
| var import_objectSpread2 = __toESM(require_objectSpread2(), 1); | ||
| /** | ||
| * @see https://trpc.io/docs/client/links/httpBatchLink | ||
| */ | ||
| function httpBatchLink(opts) { | ||
| var _opts$maxURLLength, _opts$maxItems; | ||
| const resolvedOpts = resolveHTTPLinkOptions(opts); | ||
| const maxURLLength = (_opts$maxURLLength = opts.maxURLLength) !== null && _opts$maxURLLength !== void 0 ? _opts$maxURLLength : Infinity; | ||
| const maxItems = (_opts$maxItems = opts.maxItems) !== null && _opts$maxItems !== void 0 ? _opts$maxItems : Infinity; | ||
| return () => { | ||
| const batchLoader = (type) => { | ||
| return { | ||
| validate(batchOps) { | ||
| if (maxURLLength === Infinity && maxItems === Infinity) return true; | ||
| if (batchOps.length > maxItems) return false; | ||
| const path = batchOps.map((op) => op.path).join(","); | ||
| const inputs = batchOps.map((op) => op.input); | ||
| const url = getUrl((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, resolvedOpts), {}, { | ||
| type, | ||
| path, | ||
| inputs, | ||
| signal: null | ||
| })); | ||
| return url.length <= maxURLLength; | ||
| }, | ||
| async fetch(batchOps) { | ||
| const path = batchOps.map((op) => op.path).join(","); | ||
| const inputs = batchOps.map((op) => op.input); | ||
| const signal = allAbortSignals(...batchOps.map((op) => op.signal)); | ||
| const res = await jsonHttpRequester((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, resolvedOpts), {}, { | ||
| path, | ||
| inputs, | ||
| type, | ||
| headers() { | ||
| if (!opts.headers) return {}; | ||
| if (typeof opts.headers === "function") return opts.headers({ opList: batchOps }); | ||
| return opts.headers; | ||
| }, | ||
| signal | ||
| })); | ||
| const resJSON = Array.isArray(res.json) ? res.json : batchOps.map(() => res.json); | ||
| const result = resJSON.map((item) => ({ | ||
| meta: res.meta, | ||
| json: item | ||
| })); | ||
| return result; | ||
| } | ||
| }; | ||
| }; | ||
| const query = dataLoader(batchLoader("query")); | ||
| const mutation = dataLoader(batchLoader("mutation")); | ||
| const loaders = { | ||
| query, | ||
| mutation | ||
| }; | ||
| return ({ op }) => { | ||
| return observable((observer) => { | ||
| /* istanbul ignore if -- @preserve */ | ||
| if (op.type === "subscription") throw new Error("Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`"); | ||
| const loader = loaders[op.type]; | ||
| const promise = loader.load(op); | ||
| let _res = void 0; | ||
| promise.then((res) => { | ||
| _res = res; | ||
| const transformed = transformResult(res.json, resolvedOpts.transformer.output); | ||
| if (!transformed.ok) { | ||
| observer.error(TRPCClientError.from(transformed.error, { meta: res.meta })); | ||
| return; | ||
| } | ||
| observer.next({ | ||
| context: res.meta, | ||
| result: transformed.result | ||
| }); | ||
| observer.complete(); | ||
| }).catch((err) => { | ||
| observer.error(TRPCClientError.from(err, { meta: _res === null || _res === void 0 ? void 0 : _res.meta })); | ||
| }); | ||
| return () => {}; | ||
| }); | ||
| }; | ||
| }; | ||
| } | ||
| //#endregion | ||
| export { abortSignalToPromise, allAbortSignals, dataLoader, httpBatchLink, raceAbortSignals }; | ||
| //# sourceMappingURL=httpBatchLink-DpOHx07Q.mjs.map |
| {"version":3,"file":"httpBatchLink-DpOHx07Q.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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"} |
| import { __toESM, require_objectSpread2 } from "./objectSpread2-BvkFp-_Y.mjs"; | ||
| import { TRPCClientError } from "./TRPCClientError-apv8gw59.mjs"; | ||
| import { getUrl, httpRequest, jsonHttpRequester, resolveHTTPLinkOptions } from "./httpUtils-D61f8fkr.mjs"; | ||
| import { observable } from "@trpc/server/observable"; | ||
| import { transformResult } from "@trpc/server/unstable-core-do-not-import"; | ||
| //#region src/links/internals/contentTypes.ts | ||
| function isOctetType(input) { | ||
| return input instanceof Uint8Array || input instanceof Blob; | ||
| } | ||
| function isFormData(input) { | ||
| return input instanceof FormData; | ||
| } | ||
| function isNonJsonSerializable(input) { | ||
| return isOctetType(input) || isFormData(input); | ||
| } | ||
| //#endregion | ||
| //#region src/links/httpLink.ts | ||
| var import_objectSpread2 = __toESM(require_objectSpread2(), 1); | ||
| const universalRequester = (opts) => { | ||
| if ("input" in opts) { | ||
| const { input } = opts; | ||
| if (isFormData(input)) { | ||
| if (opts.type !== "mutation" && opts.methodOverride !== "POST") throw new Error("FormData is only supported for mutations"); | ||
| return httpRequest((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, opts), {}, { | ||
| contentTypeHeader: void 0, | ||
| getUrl, | ||
| getBody: () => input | ||
| })); | ||
| } | ||
| if (isOctetType(input)) { | ||
| if (opts.type !== "mutation" && opts.methodOverride !== "POST") throw new Error("Octet type input is only supported for mutations"); | ||
| return httpRequest((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, opts), {}, { | ||
| contentTypeHeader: "application/octet-stream", | ||
| getUrl, | ||
| getBody: () => input | ||
| })); | ||
| } | ||
| } | ||
| return jsonHttpRequester(opts); | ||
| }; | ||
| /** | ||
| * @see https://trpc.io/docs/client/links/httpLink | ||
| */ | ||
| function httpLink(opts) { | ||
| const resolvedOpts = resolveHTTPLinkOptions(opts); | ||
| return () => { | ||
| return (operationOpts) => { | ||
| const { op } = operationOpts; | ||
| return observable((observer) => { | ||
| const { path, input, type } = op; | ||
| /* istanbul ignore if -- @preserve */ | ||
| if (type === "subscription") throw new Error("Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`"); | ||
| const request = universalRequester((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, resolvedOpts), {}, { | ||
| type, | ||
| path, | ||
| input, | ||
| signal: op.signal, | ||
| headers() { | ||
| if (!opts.headers) return {}; | ||
| if (typeof opts.headers === "function") return opts.headers({ op }); | ||
| return opts.headers; | ||
| } | ||
| })); | ||
| let meta = void 0; | ||
| request.then((res) => { | ||
| meta = res.meta; | ||
| const transformed = transformResult(res.json, resolvedOpts.transformer.output); | ||
| if (!transformed.ok) { | ||
| observer.error(TRPCClientError.from(transformed.error, { meta })); | ||
| return; | ||
| } | ||
| observer.next({ | ||
| context: res.meta, | ||
| result: transformed.result | ||
| }); | ||
| observer.complete(); | ||
| }).catch((cause) => { | ||
| observer.error(TRPCClientError.from(cause, { meta })); | ||
| }); | ||
| return () => {}; | ||
| }); | ||
| }; | ||
| }; | ||
| } | ||
| //#endregion | ||
| export { httpLink, isFormData, isNonJsonSerializable, isOctetType }; | ||
| //# sourceMappingURL=httpLink-Dd2kmq0r.mjs.map |
| {"version":3,"file":"httpLink-Dd2kmq0r.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"} |
| import { __toESM, require_objectSpread2 } from "./objectSpread2-BvkFp-_Y.mjs"; | ||
| import { getTransformer } from "./unstable-internals-Bg7n9BBj.mjs"; | ||
| //#region src/getFetch.ts | ||
| const isFunction = (fn) => typeof fn === "function"; | ||
| function getFetch(customFetchImpl) { | ||
| if (customFetchImpl) return customFetchImpl; | ||
| if (typeof window !== "undefined" && isFunction(window.fetch)) return window.fetch; | ||
| if (typeof globalThis !== "undefined" && isFunction(globalThis.fetch)) return globalThis.fetch; | ||
| throw new Error("No fetch implementation found"); | ||
| } | ||
| //#endregion | ||
| //#region src/links/internals/httpUtils.ts | ||
| var import_objectSpread2 = __toESM(require_objectSpread2()); | ||
| function resolveHTTPLinkOptions(opts) { | ||
| return { | ||
| url: opts.url.toString(), | ||
| fetch: opts.fetch, | ||
| transformer: getTransformer(opts.transformer), | ||
| methodOverride: opts.methodOverride | ||
| }; | ||
| } | ||
| function arrayToDict(array) { | ||
| const dict = {}; | ||
| for (let index = 0; index < array.length; index++) { | ||
| const element = array[index]; | ||
| dict[index] = element; | ||
| } | ||
| return dict; | ||
| } | ||
| const METHOD = { | ||
| query: "GET", | ||
| mutation: "POST", | ||
| subscription: "PATCH" | ||
| }; | ||
| function getInput(opts) { | ||
| return "input" in opts ? opts.transformer.input.serialize(opts.input) : arrayToDict(opts.inputs.map((_input) => opts.transformer.input.serialize(_input))); | ||
| } | ||
| const getUrl = (opts) => { | ||
| const parts = opts.url.split("?"); | ||
| const base = parts[0].replace(/\/$/, ""); | ||
| let url = base + "/" + opts.path; | ||
| const queryParts = []; | ||
| if (parts[1]) queryParts.push(parts[1]); | ||
| if ("inputs" in opts) queryParts.push("batch=1"); | ||
| if (opts.type === "query" || opts.type === "subscription") { | ||
| const input = getInput(opts); | ||
| if (input !== void 0 && opts.methodOverride !== "POST") queryParts.push(`input=${encodeURIComponent(JSON.stringify(input))}`); | ||
| } | ||
| if (queryParts.length) url += "?" + queryParts.join("&"); | ||
| return url; | ||
| }; | ||
| const getBody = (opts) => { | ||
| if (opts.type === "query" && opts.methodOverride !== "POST") return void 0; | ||
| const input = getInput(opts); | ||
| return input !== void 0 ? JSON.stringify(input) : void 0; | ||
| }; | ||
| const jsonHttpRequester = (opts) => { | ||
| return httpRequest((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, opts), {}, { | ||
| contentTypeHeader: "application/json", | ||
| getUrl, | ||
| getBody | ||
| })); | ||
| }; | ||
| /** | ||
| * Polyfill for DOMException with AbortError name | ||
| */ | ||
| var AbortError = class extends Error { | ||
| constructor() { | ||
| const name = "AbortError"; | ||
| super(name); | ||
| this.name = name; | ||
| this.message = name; | ||
| } | ||
| }; | ||
| /** | ||
| * Polyfill for `signal.throwIfAborted()` | ||
| * | ||
| * @see https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/throwIfAborted | ||
| */ | ||
| const throwIfAborted = (signal) => { | ||
| var _signal$throwIfAborte; | ||
| if (!(signal === null || signal === void 0 ? void 0 : signal.aborted)) return; | ||
| (_signal$throwIfAborte = signal.throwIfAborted) === null || _signal$throwIfAborte === void 0 || _signal$throwIfAborte.call(signal); | ||
| if (typeof DOMException !== "undefined") throw new DOMException("AbortError", "AbortError"); | ||
| throw new AbortError(); | ||
| }; | ||
| async function fetchHTTPResponse(opts) { | ||
| var _opts$methodOverride; | ||
| throwIfAborted(opts.signal); | ||
| const url = opts.getUrl(opts); | ||
| const body = opts.getBody(opts); | ||
| const method = (_opts$methodOverride = opts.methodOverride) !== null && _opts$methodOverride !== void 0 ? _opts$methodOverride : METHOD[opts.type]; | ||
| const resolvedHeaders = await (async () => { | ||
| const heads = await opts.headers(); | ||
| if (Symbol.iterator in heads) return Object.fromEntries(heads); | ||
| return heads; | ||
| })(); | ||
| const headers = (0, import_objectSpread2.default)((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, opts.contentTypeHeader && method !== "GET" ? { "content-type": opts.contentTypeHeader } : {}), opts.trpcAcceptHeader ? { "trpc-accept": opts.trpcAcceptHeader } : void 0), resolvedHeaders); | ||
| return getFetch(opts.fetch)(url, { | ||
| method, | ||
| signal: opts.signal, | ||
| body, | ||
| headers | ||
| }); | ||
| } | ||
| async function httpRequest(opts) { | ||
| const meta = {}; | ||
| const res = await fetchHTTPResponse(opts); | ||
| meta.response = res; | ||
| const json = await res.json(); | ||
| meta.responseJSON = json; | ||
| return { | ||
| json, | ||
| meta | ||
| }; | ||
| } | ||
| //#endregion | ||
| export { fetchHTTPResponse, getBody, getFetch, getUrl, httpRequest, jsonHttpRequester, resolveHTTPLinkOptions }; | ||
| //# sourceMappingURL=httpUtils-D61f8fkr.mjs.map |
| {"version":3,"file":"httpUtils-D61f8fkr.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 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 ? { '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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"} |
+2
-1
@@ -725,3 +725,4 @@ const require_chunk = require('./chunk-DWy1uDak.cjs'); | ||
| type: op.type, | ||
| signal | ||
| signal, | ||
| batchIndex: 0 | ||
| }); | ||
@@ -728,0 +729,0 @@ } |
+5
-4
| import { __commonJS, __toESM, require_defineProperty, require_objectSpread2 } from "./objectSpread2-BvkFp-_Y.mjs"; | ||
| import { createChain, splitLink } from "./splitLink-B7Cuf2c_.mjs"; | ||
| import { TRPCClientError, isTRPCClientError } from "./TRPCClientError-apv8gw59.mjs"; | ||
| import { fetchHTTPResponse, getBody, getFetch, getUrl, resolveHTTPLinkOptions } from "./httpUtils-Dv57hbOd.mjs"; | ||
| import { httpLink, isFormData, isNonJsonSerializable, isOctetType } from "./httpLink-Cz9h1Qgh.mjs"; | ||
| import { abortSignalToPromise, allAbortSignals, dataLoader, httpBatchLink, raceAbortSignals } from "./httpBatchLink-fQ1NAi-e.mjs"; | ||
| import { fetchHTTPResponse, getBody, getFetch, getUrl, resolveHTTPLinkOptions } from "./httpUtils-D61f8fkr.mjs"; | ||
| import { httpLink, isFormData, isNonJsonSerializable, isOctetType } from "./httpLink-Dd2kmq0r.mjs"; | ||
| import { abortSignalToPromise, allAbortSignals, dataLoader, httpBatchLink, raceAbortSignals } from "./httpBatchLink-DpOHx07Q.mjs"; | ||
| import { getTransformer } from "./unstable-internals-Bg7n9BBj.mjs"; | ||
@@ -724,3 +724,4 @@ import { loggerLink } from "./loggerLink-ineCN1PO.mjs"; | ||
| type: op.type, | ||
| signal | ||
| signal, | ||
| batchIndex: 0 | ||
| }); | ||
@@ -727,0 +728,0 @@ } |
| import "../objectSpread2-BvkFp-_Y.mjs"; | ||
| import "../TRPCClientError-apv8gw59.mjs"; | ||
| import "../httpUtils-Dv57hbOd.mjs"; | ||
| import { httpBatchLink } from "../httpBatchLink-fQ1NAi-e.mjs"; | ||
| import "../httpUtils-D61f8fkr.mjs"; | ||
| import { httpBatchLink } from "../httpBatchLink-DpOHx07Q.mjs"; | ||
| import "../unstable-internals-Bg7n9BBj.mjs"; | ||
| export { httpBatchLink }; |
| import "../objectSpread2-BvkFp-_Y.mjs"; | ||
| import "../TRPCClientError-apv8gw59.mjs"; | ||
| import "../httpUtils-Dv57hbOd.mjs"; | ||
| import { httpLink } from "../httpLink-Cz9h1Qgh.mjs"; | ||
| import "../httpUtils-D61f8fkr.mjs"; | ||
| import { httpLink } from "../httpLink-Dd2kmq0r.mjs"; | ||
| import "../unstable-internals-Bg7n9BBj.mjs"; | ||
| export { httpLink }; |
+4
-4
| { | ||
| "name": "@trpc/client", | ||
| "type": "module", | ||
| "version": "11.9.1-canary.9+d92cc45b3", | ||
| "version": "11.10.0", | ||
| "description": "The tRPC client library", | ||
@@ -115,7 +115,7 @@ "author": "KATT", | ||
| "peerDependencies": { | ||
| "@trpc/server": "11.9.1-canary.9+d92cc45b3", | ||
| "@trpc/server": "11.10.0", | ||
| "typescript": ">=5.7.2" | ||
| }, | ||
| "devDependencies": { | ||
| "@trpc/server": "11.9.1-canary.9+d92cc45b3", | ||
| "@trpc/server": "11.10.0", | ||
| "@types/isomorphic-fetch": "^0.0.39", | ||
@@ -139,3 +139,3 @@ "@types/node": "^22.13.5", | ||
| ], | ||
| "gitHead": "d92cc45b3e6edb5805474112feacbe9f386a97ee" | ||
| "gitHead": "54ee800f414841b4a34860ffb3e5a6bac5aef7da" | ||
| } |
@@ -85,2 +85,3 @@ import { | ||
| signal, | ||
| batchIndex: 0, | ||
| }); | ||
@@ -87,0 +88,0 @@ } |
| import { __toESM, require_objectSpread2 } from "./objectSpread2-BvkFp-_Y.mjs"; | ||
| import { TRPCClientError } from "./TRPCClientError-apv8gw59.mjs"; | ||
| import { getUrl, jsonHttpRequester, resolveHTTPLinkOptions } from "./httpUtils-Dv57hbOd.mjs"; | ||
| import { observable } from "@trpc/server/observable"; | ||
| import { transformResult } from "@trpc/server/unstable-core-do-not-import"; | ||
| //#region src/internals/dataLoader.ts | ||
| /** | ||
| * A function that should never be called unless we messed something up. | ||
| */ | ||
| const throwFatalError = () => { | ||
| throw new Error("Something went wrong. Please submit an issue at https://github.com/trpc/trpc/issues/new"); | ||
| }; | ||
| /** | ||
| * Dataloader that's very inspired by https://github.com/graphql/dataloader | ||
| * Less configuration, no caching, and allows you to cancel requests | ||
| * When cancelling a single fetch the whole batch will be cancelled only when _all_ items are cancelled | ||
| */ | ||
| function dataLoader(batchLoader) { | ||
| let pendingItems = null; | ||
| let dispatchTimer = null; | ||
| const destroyTimerAndPendingItems = () => { | ||
| clearTimeout(dispatchTimer); | ||
| dispatchTimer = null; | ||
| pendingItems = null; | ||
| }; | ||
| /** | ||
| * Iterate through the items and split them into groups based on the `batchLoader`'s validate function | ||
| */ | ||
| function groupItems(items) { | ||
| const groupedItems = [[]]; | ||
| let index = 0; | ||
| while (true) { | ||
| const item = items[index]; | ||
| if (!item) break; | ||
| const lastGroup = groupedItems[groupedItems.length - 1]; | ||
| if (item.aborted) { | ||
| var _item$reject; | ||
| (_item$reject = item.reject) === null || _item$reject === void 0 || _item$reject.call(item, new Error("Aborted")); | ||
| index++; | ||
| continue; | ||
| } | ||
| const isValid = batchLoader.validate(lastGroup.concat(item).map((it) => it.key)); | ||
| if (isValid) { | ||
| lastGroup.push(item); | ||
| index++; | ||
| continue; | ||
| } | ||
| if (lastGroup.length === 0) { | ||
| var _item$reject2; | ||
| (_item$reject2 = item.reject) === null || _item$reject2 === void 0 || _item$reject2.call(item, new Error("Input is too big for a single dispatch")); | ||
| index++; | ||
| continue; | ||
| } | ||
| groupedItems.push([]); | ||
| } | ||
| return groupedItems; | ||
| } | ||
| function dispatch() { | ||
| const groupedItems = groupItems(pendingItems); | ||
| destroyTimerAndPendingItems(); | ||
| for (const items of groupedItems) { | ||
| if (!items.length) continue; | ||
| const batch = { items }; | ||
| for (const item of items) item.batch = batch; | ||
| const promise = batchLoader.fetch(batch.items.map((_item) => _item.key)); | ||
| promise.then(async (result) => { | ||
| await Promise.all(result.map(async (valueOrPromise, index) => { | ||
| const item = batch.items[index]; | ||
| try { | ||
| var _item$resolve; | ||
| const value = await Promise.resolve(valueOrPromise); | ||
| (_item$resolve = item.resolve) === null || _item$resolve === void 0 || _item$resolve.call(item, value); | ||
| } catch (cause) { | ||
| var _item$reject3; | ||
| (_item$reject3 = item.reject) === null || _item$reject3 === void 0 || _item$reject3.call(item, cause); | ||
| } | ||
| item.batch = null; | ||
| item.reject = null; | ||
| item.resolve = null; | ||
| })); | ||
| for (const item of batch.items) { | ||
| var _item$reject4; | ||
| (_item$reject4 = item.reject) === null || _item$reject4 === void 0 || _item$reject4.call(item, new Error("Missing result")); | ||
| item.batch = null; | ||
| } | ||
| }).catch((cause) => { | ||
| for (const item of batch.items) { | ||
| var _item$reject5; | ||
| (_item$reject5 = item.reject) === null || _item$reject5 === void 0 || _item$reject5.call(item, cause); | ||
| item.batch = null; | ||
| } | ||
| }); | ||
| } | ||
| } | ||
| function load(key) { | ||
| var _dispatchTimer; | ||
| const item = { | ||
| aborted: false, | ||
| key, | ||
| batch: null, | ||
| resolve: throwFatalError, | ||
| reject: throwFatalError | ||
| }; | ||
| const promise = new Promise((resolve, reject) => { | ||
| var _pendingItems; | ||
| item.reject = reject; | ||
| item.resolve = resolve; | ||
| (_pendingItems = pendingItems) !== null && _pendingItems !== void 0 || (pendingItems = []); | ||
| pendingItems.push(item); | ||
| }); | ||
| (_dispatchTimer = dispatchTimer) !== null && _dispatchTimer !== void 0 || (dispatchTimer = setTimeout(dispatch)); | ||
| return promise; | ||
| } | ||
| return { load }; | ||
| } | ||
| //#endregion | ||
| //#region src/internals/signals.ts | ||
| /** | ||
| * Like `Promise.all()` but for abort signals | ||
| * - When all signals have been aborted, the merged signal will be aborted | ||
| * - If one signal is `null`, no signal will be aborted | ||
| */ | ||
| function allAbortSignals(...signals) { | ||
| const ac = new AbortController(); | ||
| const count = signals.length; | ||
| let abortedCount = 0; | ||
| const onAbort = () => { | ||
| if (++abortedCount === count) ac.abort(); | ||
| }; | ||
| for (const signal of signals) if (signal === null || signal === void 0 ? void 0 : signal.aborted) onAbort(); | ||
| else signal === null || signal === void 0 || signal.addEventListener("abort", onAbort, { once: true }); | ||
| return ac.signal; | ||
| } | ||
| /** | ||
| * Like `Promise.race` but for abort signals | ||
| * | ||
| * Basically, a ponyfill for | ||
| * [`AbortSignal.any`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/any_static). | ||
| */ | ||
| function raceAbortSignals(...signals) { | ||
| const ac = new AbortController(); | ||
| for (const signal of signals) if (signal === null || signal === void 0 ? void 0 : signal.aborted) ac.abort(); | ||
| else signal === null || signal === void 0 || signal.addEventListener("abort", () => ac.abort(), { once: true }); | ||
| return ac.signal; | ||
| } | ||
| function abortSignalToPromise(signal) { | ||
| return new Promise((_, reject) => { | ||
| if (signal.aborted) { | ||
| reject(signal.reason); | ||
| return; | ||
| } | ||
| signal.addEventListener("abort", () => { | ||
| reject(signal.reason); | ||
| }, { once: true }); | ||
| }); | ||
| } | ||
| //#endregion | ||
| //#region src/links/httpBatchLink.ts | ||
| var import_objectSpread2 = __toESM(require_objectSpread2(), 1); | ||
| /** | ||
| * @see https://trpc.io/docs/client/links/httpBatchLink | ||
| */ | ||
| function httpBatchLink(opts) { | ||
| var _opts$maxURLLength, _opts$maxItems; | ||
| const resolvedOpts = resolveHTTPLinkOptions(opts); | ||
| const maxURLLength = (_opts$maxURLLength = opts.maxURLLength) !== null && _opts$maxURLLength !== void 0 ? _opts$maxURLLength : Infinity; | ||
| const maxItems = (_opts$maxItems = opts.maxItems) !== null && _opts$maxItems !== void 0 ? _opts$maxItems : Infinity; | ||
| return () => { | ||
| const batchLoader = (type) => { | ||
| return { | ||
| validate(batchOps) { | ||
| if (maxURLLength === Infinity && maxItems === Infinity) return true; | ||
| if (batchOps.length > maxItems) return false; | ||
| const path = batchOps.map((op) => op.path).join(","); | ||
| const inputs = batchOps.map((op) => op.input); | ||
| const url = getUrl((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, resolvedOpts), {}, { | ||
| type, | ||
| path, | ||
| inputs, | ||
| signal: null | ||
| })); | ||
| return url.length <= maxURLLength; | ||
| }, | ||
| async fetch(batchOps) { | ||
| const path = batchOps.map((op) => op.path).join(","); | ||
| const inputs = batchOps.map((op) => op.input); | ||
| const signal = allAbortSignals(...batchOps.map((op) => op.signal)); | ||
| const res = await jsonHttpRequester((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, resolvedOpts), {}, { | ||
| path, | ||
| inputs, | ||
| type, | ||
| headers() { | ||
| if (!opts.headers) return {}; | ||
| if (typeof opts.headers === "function") return opts.headers({ opList: batchOps }); | ||
| return opts.headers; | ||
| }, | ||
| signal | ||
| })); | ||
| const resJSON = Array.isArray(res.json) ? res.json : batchOps.map(() => res.json); | ||
| const result = resJSON.map((item) => ({ | ||
| meta: res.meta, | ||
| json: item | ||
| })); | ||
| return result; | ||
| } | ||
| }; | ||
| }; | ||
| const query = dataLoader(batchLoader("query")); | ||
| const mutation = dataLoader(batchLoader("mutation")); | ||
| const loaders = { | ||
| query, | ||
| mutation | ||
| }; | ||
| return ({ op }) => { | ||
| return observable((observer) => { | ||
| /* istanbul ignore if -- @preserve */ | ||
| if (op.type === "subscription") throw new Error("Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`"); | ||
| const loader = loaders[op.type]; | ||
| const promise = loader.load(op); | ||
| let _res = void 0; | ||
| promise.then((res) => { | ||
| _res = res; | ||
| const transformed = transformResult(res.json, resolvedOpts.transformer.output); | ||
| if (!transformed.ok) { | ||
| observer.error(TRPCClientError.from(transformed.error, { meta: res.meta })); | ||
| return; | ||
| } | ||
| observer.next({ | ||
| context: res.meta, | ||
| result: transformed.result | ||
| }); | ||
| observer.complete(); | ||
| }).catch((err) => { | ||
| observer.error(TRPCClientError.from(err, { meta: _res === null || _res === void 0 ? void 0 : _res.meta })); | ||
| }); | ||
| return () => {}; | ||
| }); | ||
| }; | ||
| }; | ||
| } | ||
| //#endregion | ||
| export { abortSignalToPromise, allAbortSignals, dataLoader, httpBatchLink, raceAbortSignals }; | ||
| //# sourceMappingURL=httpBatchLink-fQ1NAi-e.mjs.map |
| {"version":3,"file":"httpBatchLink-fQ1NAi-e.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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"} |
| import { __toESM, require_objectSpread2 } from "./objectSpread2-BvkFp-_Y.mjs"; | ||
| import { TRPCClientError } from "./TRPCClientError-apv8gw59.mjs"; | ||
| import { getUrl, httpRequest, jsonHttpRequester, resolveHTTPLinkOptions } from "./httpUtils-Dv57hbOd.mjs"; | ||
| import { observable } from "@trpc/server/observable"; | ||
| import { transformResult } from "@trpc/server/unstable-core-do-not-import"; | ||
| //#region src/links/internals/contentTypes.ts | ||
| function isOctetType(input) { | ||
| return input instanceof Uint8Array || input instanceof Blob; | ||
| } | ||
| function isFormData(input) { | ||
| return input instanceof FormData; | ||
| } | ||
| function isNonJsonSerializable(input) { | ||
| return isOctetType(input) || isFormData(input); | ||
| } | ||
| //#endregion | ||
| //#region src/links/httpLink.ts | ||
| var import_objectSpread2 = __toESM(require_objectSpread2(), 1); | ||
| const universalRequester = (opts) => { | ||
| if ("input" in opts) { | ||
| const { input } = opts; | ||
| if (isFormData(input)) { | ||
| if (opts.type !== "mutation" && opts.methodOverride !== "POST") throw new Error("FormData is only supported for mutations"); | ||
| return httpRequest((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, opts), {}, { | ||
| contentTypeHeader: void 0, | ||
| getUrl, | ||
| getBody: () => input | ||
| })); | ||
| } | ||
| if (isOctetType(input)) { | ||
| if (opts.type !== "mutation" && opts.methodOverride !== "POST") throw new Error("Octet type input is only supported for mutations"); | ||
| return httpRequest((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, opts), {}, { | ||
| contentTypeHeader: "application/octet-stream", | ||
| getUrl, | ||
| getBody: () => input | ||
| })); | ||
| } | ||
| } | ||
| return jsonHttpRequester(opts); | ||
| }; | ||
| /** | ||
| * @see https://trpc.io/docs/client/links/httpLink | ||
| */ | ||
| function httpLink(opts) { | ||
| const resolvedOpts = resolveHTTPLinkOptions(opts); | ||
| return () => { | ||
| return (operationOpts) => { | ||
| const { op } = operationOpts; | ||
| return observable((observer) => { | ||
| const { path, input, type } = op; | ||
| /* istanbul ignore if -- @preserve */ | ||
| if (type === "subscription") throw new Error("Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`"); | ||
| const request = universalRequester((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, resolvedOpts), {}, { | ||
| type, | ||
| path, | ||
| input, | ||
| signal: op.signal, | ||
| headers() { | ||
| if (!opts.headers) return {}; | ||
| if (typeof opts.headers === "function") return opts.headers({ op }); | ||
| return opts.headers; | ||
| } | ||
| })); | ||
| let meta = void 0; | ||
| request.then((res) => { | ||
| meta = res.meta; | ||
| const transformed = transformResult(res.json, resolvedOpts.transformer.output); | ||
| if (!transformed.ok) { | ||
| observer.error(TRPCClientError.from(transformed.error, { meta })); | ||
| return; | ||
| } | ||
| observer.next({ | ||
| context: res.meta, | ||
| result: transformed.result | ||
| }); | ||
| observer.complete(); | ||
| }).catch((cause) => { | ||
| observer.error(TRPCClientError.from(cause, { meta })); | ||
| }); | ||
| return () => {}; | ||
| }); | ||
| }; | ||
| }; | ||
| } | ||
| //#endregion | ||
| export { httpLink, isFormData, isNonJsonSerializable, isOctetType }; | ||
| //# sourceMappingURL=httpLink-Cz9h1Qgh.mjs.map |
| {"version":3,"file":"httpLink-Cz9h1Qgh.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"} |
| import { __toESM, require_objectSpread2 } from "./objectSpread2-BvkFp-_Y.mjs"; | ||
| import { getTransformer } from "./unstable-internals-Bg7n9BBj.mjs"; | ||
| //#region src/getFetch.ts | ||
| const isFunction = (fn) => typeof fn === "function"; | ||
| function getFetch(customFetchImpl) { | ||
| if (customFetchImpl) return customFetchImpl; | ||
| if (typeof window !== "undefined" && isFunction(window.fetch)) return window.fetch; | ||
| if (typeof globalThis !== "undefined" && isFunction(globalThis.fetch)) return globalThis.fetch; | ||
| throw new Error("No fetch implementation found"); | ||
| } | ||
| //#endregion | ||
| //#region src/links/internals/httpUtils.ts | ||
| var import_objectSpread2 = __toESM(require_objectSpread2(), 1); | ||
| function resolveHTTPLinkOptions(opts) { | ||
| return { | ||
| url: opts.url.toString(), | ||
| fetch: opts.fetch, | ||
| transformer: getTransformer(opts.transformer), | ||
| methodOverride: opts.methodOverride | ||
| }; | ||
| } | ||
| function arrayToDict(array) { | ||
| const dict = {}; | ||
| for (let index = 0; index < array.length; index++) { | ||
| const element = array[index]; | ||
| dict[index] = element; | ||
| } | ||
| return dict; | ||
| } | ||
| const METHOD = { | ||
| query: "GET", | ||
| mutation: "POST", | ||
| subscription: "PATCH" | ||
| }; | ||
| function getInput(opts) { | ||
| return "input" in opts ? opts.transformer.input.serialize(opts.input) : arrayToDict(opts.inputs.map((_input) => opts.transformer.input.serialize(_input))); | ||
| } | ||
| const getUrl = (opts) => { | ||
| const parts = opts.url.split("?"); | ||
| const base = parts[0].replace(/\/$/, ""); | ||
| let url = base + "/" + opts.path; | ||
| const queryParts = []; | ||
| if (parts[1]) queryParts.push(parts[1]); | ||
| if ("inputs" in opts) queryParts.push("batch=1"); | ||
| if (opts.type === "query" || opts.type === "subscription") { | ||
| const input = getInput(opts); | ||
| if (input !== void 0 && opts.methodOverride !== "POST") queryParts.push(`input=${encodeURIComponent(JSON.stringify(input))}`); | ||
| } | ||
| if (queryParts.length) url += "?" + queryParts.join("&"); | ||
| return url; | ||
| }; | ||
| const getBody = (opts) => { | ||
| if (opts.type === "query" && opts.methodOverride !== "POST") return void 0; | ||
| const input = getInput(opts); | ||
| return input !== void 0 ? JSON.stringify(input) : void 0; | ||
| }; | ||
| const jsonHttpRequester = (opts) => { | ||
| return httpRequest((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, opts), {}, { | ||
| contentTypeHeader: "application/json", | ||
| getUrl, | ||
| getBody | ||
| })); | ||
| }; | ||
| /** | ||
| * Polyfill for DOMException with AbortError name | ||
| */ | ||
| var AbortError = class extends Error { | ||
| constructor() { | ||
| const name = "AbortError"; | ||
| super(name); | ||
| this.name = name; | ||
| this.message = name; | ||
| } | ||
| }; | ||
| /** | ||
| * Polyfill for `signal.throwIfAborted()` | ||
| * | ||
| * @see https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/throwIfAborted | ||
| */ | ||
| const throwIfAborted = (signal) => { | ||
| var _signal$throwIfAborte; | ||
| if (!(signal === null || signal === void 0 ? void 0 : signal.aborted)) return; | ||
| (_signal$throwIfAborte = signal.throwIfAborted) === null || _signal$throwIfAborte === void 0 || _signal$throwIfAborte.call(signal); | ||
| if (typeof DOMException !== "undefined") throw new DOMException("AbortError", "AbortError"); | ||
| throw new AbortError(); | ||
| }; | ||
| async function fetchHTTPResponse(opts) { | ||
| var _opts$methodOverride; | ||
| throwIfAborted(opts.signal); | ||
| const url = opts.getUrl(opts); | ||
| const body = opts.getBody(opts); | ||
| const method = (_opts$methodOverride = opts.methodOverride) !== null && _opts$methodOverride !== void 0 ? _opts$methodOverride : METHOD[opts.type]; | ||
| const resolvedHeaders = await (async () => { | ||
| const heads = await opts.headers(); | ||
| if (Symbol.iterator in heads) return Object.fromEntries(heads); | ||
| return heads; | ||
| })(); | ||
| const headers = (0, import_objectSpread2.default)((0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, opts.contentTypeHeader && method !== "GET" ? { "content-type": opts.contentTypeHeader } : {}), opts.trpcAcceptHeader ? { "trpc-accept": opts.trpcAcceptHeader } : void 0), resolvedHeaders); | ||
| return getFetch(opts.fetch)(url, { | ||
| method, | ||
| signal: opts.signal, | ||
| body, | ||
| headers | ||
| }); | ||
| } | ||
| async function httpRequest(opts) { | ||
| const meta = {}; | ||
| const res = await fetchHTTPResponse(opts); | ||
| meta.response = res; | ||
| const json = await res.json(); | ||
| meta.responseJSON = json; | ||
| return { | ||
| json, | ||
| meta | ||
| }; | ||
| } | ||
| //#endregion | ||
| export { fetchHTTPResponse, getBody, getFetch, getUrl, httpRequest, jsonHttpRequester, resolveHTTPLinkOptions }; | ||
| //# sourceMappingURL=httpUtils-Dv57hbOd.mjs.map |
| {"version":3,"file":"httpUtils-Dv57hbOd.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 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 ? { '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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"} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
561113
0.01%8573
0.04%0
-100%1
-50%