@trpc/tanstack-react-query
Version:
TanStack React Query Integration for tRPC
592 lines (591 loc) • 22.6 kB
JavaScript
//#region \0rolldown/runtime.js
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
key = keys[i];
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: ((k) => from[k]).bind(null, key),
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
value: mod,
enumerable: true
}) : target, mod));
//#endregion
const require_utils = require("./utils-Dc6cVb7T.cjs");
let react = require("react");
react = __toESM(react, 1);
let _trpc_client = require("@trpc/client");
let _trpc_server = require("@trpc/server");
let _tanstack_react_query = require("@tanstack/react-query");
let _trpc_server_unstable_core_do_not_import = require("@trpc/server/unstable-core-do-not-import");
//#region src/internals/infiniteQueryOptions.ts
function trpcInfiniteQueryOptions(args) {
var _opts$initialCursor;
const { input, query, path, queryKey, opts } = args;
const inputIsSkipToken = input === _tanstack_react_query.skipToken;
const queryFn = async (queryFnContext) => {
var _opts$trpc;
const actualOpts = require_utils._objectSpread2(require_utils._objectSpread2({}, opts), {}, { trpc: require_utils._objectSpread2(require_utils._objectSpread2({}, opts === null || opts === void 0 ? void 0 : opts.trpc), (opts === null || opts === void 0 || (_opts$trpc = opts.trpc) === null || _opts$trpc === void 0 ? void 0 : _opts$trpc.abortOnUnmount) ? { signal: queryFnContext.signal } : { signal: null }) });
return await query(...require_utils.getClientArgs(queryKey, actualOpts, {
direction: queryFnContext.direction,
pageParam: queryFnContext.pageParam
}));
};
return Object.assign((0, _tanstack_react_query.infiniteQueryOptions)(require_utils._objectSpread2(require_utils._objectSpread2({}, opts !== null && opts !== void 0 ? opts : {}), {}, {
queryKey,
queryFn: inputIsSkipToken ? _tanstack_react_query.skipToken : queryFn,
initialPageParam: (_opts$initialCursor = opts === null || opts === void 0 ? void 0 : opts.initialCursor) !== null && _opts$initialCursor !== void 0 ? _opts$initialCursor : input === null || input === void 0 ? void 0 : input.cursor
})), { trpc: require_utils.createTRPCOptionsResult({ path }) });
}
//#endregion
//#region src/internals/mutationOptions.ts
/**
* @internal
*/
function trpcMutationOptions(args) {
var _opts$keyPrefix, _overrides$onSuccess;
const { mutate, path, prefix, opts, overrides } = args;
const queryClient = require_utils.unwrapLazyArg(args.queryClient);
const mutationKey = require_utils.getMutationKeyInternal({
path,
prefix: (_opts$keyPrefix = opts === null || opts === void 0 ? void 0 : opts.keyPrefix) !== null && _opts$keyPrefix !== void 0 ? _opts$keyPrefix : prefix
});
const defaultOpts = queryClient.defaultMutationOptions(queryClient.getMutationDefaults(mutationKey));
const mutationSuccessOverride = (_overrides$onSuccess = overrides === null || overrides === void 0 ? void 0 : overrides.onSuccess) !== null && _overrides$onSuccess !== void 0 ? _overrides$onSuccess : ((options) => options.originalFn());
const mutationFn = async (input) => {
return await mutate(...require_utils.getClientArgs([...mutationKey, { input }], opts));
};
return require_utils._objectSpread2(require_utils._objectSpread2({}, opts), {}, {
mutationKey,
mutationFn,
onSuccess(...args) {
var _ref, _opts$meta;
const originalFn = () => {
var _opts$onSuccess, _opts$onSuccess2, _defaultOpts$onSucces;
return (_opts$onSuccess = opts === null || opts === void 0 || (_opts$onSuccess2 = opts.onSuccess) === null || _opts$onSuccess2 === void 0 ? void 0 : _opts$onSuccess2.call(opts, ...args)) !== null && _opts$onSuccess !== void 0 ? _opts$onSuccess : defaultOpts === null || defaultOpts === void 0 || (_defaultOpts$onSucces = defaultOpts.onSuccess) === null || _defaultOpts$onSucces === void 0 ? void 0 : _defaultOpts$onSucces.call(defaultOpts, ...args);
};
return mutationSuccessOverride({
originalFn,
queryClient,
meta: (_ref = (_opts$meta = opts === null || opts === void 0 ? void 0 : opts.meta) !== null && _opts$meta !== void 0 ? _opts$meta : defaultOpts === null || defaultOpts === void 0 ? void 0 : defaultOpts.meta) !== null && _ref !== void 0 ? _ref : {}
});
},
trpc: require_utils.createTRPCOptionsResult({ path })
});
}
//#endregion
//#region src/internals/queryOptions.ts
/**
* @internal
*/
function trpcQueryOptions(args) {
const { input, query, path, queryKey, opts } = args;
const queryClient = require_utils.unwrapLazyArg(args.queryClient);
const inputIsSkipToken = input === _tanstack_react_query.skipToken;
const queryFn = async (queryFnContext) => {
var _opts$trpc;
const actualOpts = require_utils._objectSpread2(require_utils._objectSpread2({}, opts), {}, { trpc: require_utils._objectSpread2(require_utils._objectSpread2({}, opts === null || opts === void 0 ? void 0 : opts.trpc), (opts === null || opts === void 0 || (_opts$trpc = opts.trpc) === null || _opts$trpc === void 0 ? void 0 : _opts$trpc.abortOnUnmount) ? { signal: queryFnContext.signal } : { signal: null }) });
const queryKey = queryFnContext.queryKey;
const result = await query(...require_utils.getClientArgs(queryKey, actualOpts));
if ((0, _trpc_server_unstable_core_do_not_import.isAsyncIterable)(result)) return require_utils.buildQueryFromAsyncIterable(result, queryClient, queryKey);
return result;
};
return Object.assign((0, _tanstack_react_query.queryOptions)(require_utils._objectSpread2(require_utils._objectSpread2({}, opts), {}, {
queryKey,
queryFn: inputIsSkipToken ? _tanstack_react_query.skipToken : queryFn
})), { trpc: require_utils.createTRPCOptionsResult({ path }) });
}
//#endregion
//#region src/internals/subscriptionOptions.ts
/**
* @internal
*/
const trpcSubscriptionOptions = (args) => {
const { subscribe, path, queryKey, input, opts = {} } = args;
const enabled = "enabled" in opts ? !!opts.enabled : input !== _tanstack_react_query.skipToken;
const _subscribe = (innerOpts) => {
return subscribe(path.join("."), input === _tanstack_react_query.skipToken ? void 0 : input, require_utils._objectSpread2(require_utils._objectSpread2({}, innerOpts), {}, { onComplete: () => {
var _innerOpts$onComplete;
return (_innerOpts$onComplete = innerOpts.onComplete) === null || _innerOpts$onComplete === void 0 ? void 0 : _innerOpts$onComplete.call(innerOpts);
} }));
};
return require_utils._objectSpread2(require_utils._objectSpread2({}, opts), {}, {
enabled,
subscribe: _subscribe,
queryKey,
trpc: require_utils.createTRPCOptionsResult({ path })
});
};
/**
* Runs a subscription while the component is mounted.
*
* @example
* ```ts
* const trpc = useTRPC();
* const sub = useSubscription(
* trpc.chat.onMessage.subscriptionOptions({ roomId }),
* );
* ```
*
* @see https://trpc.io/docs/client/tanstack-react-query/usage#subscriptionOptions
*/
function useSubscription(opts) {
const optsRef = react.useRef(opts);
optsRef.current = opts;
const trackedProps = react.useRef(/* @__PURE__ */ new Set([]));
const addTrackedProp = react.useCallback((key) => {
trackedProps.current.add(key);
}, []);
const currentSubscriptionRef = react.useRef(() => {});
const reset = react.useCallback(() => {
var _currentSubscriptionR;
(_currentSubscriptionR = currentSubscriptionRef.current) === null || _currentSubscriptionR === void 0 || _currentSubscriptionR.call(currentSubscriptionRef);
updateState(getInitialState);
if (!opts.enabled) return;
let isUnsubscribed = false;
let isEnded = false;
const setEnded = () => {
if (isEnded) return;
isEnded = true;
updateState((prev) => require_utils._objectSpread2(require_utils._objectSpread2({}, prev), {}, {
status: "idle",
data: void 0,
error: null
}));
};
const subscription = opts.subscribe({
onStarted: () => {
var _optsRef$current$onSt, _optsRef$current;
(_optsRef$current$onSt = (_optsRef$current = optsRef.current).onStarted) === null || _optsRef$current$onSt === void 0 || _optsRef$current$onSt.call(_optsRef$current);
updateState((prev) => require_utils._objectSpread2(require_utils._objectSpread2({}, prev), {}, {
status: "pending",
error: null
}));
},
onData: (data) => {
var _optsRef$current$onDa, _optsRef$current2;
(_optsRef$current$onDa = (_optsRef$current2 = optsRef.current).onData) === null || _optsRef$current$onDa === void 0 || _optsRef$current$onDa.call(_optsRef$current2, data);
updateState((prev) => require_utils._objectSpread2(require_utils._objectSpread2({}, prev), {}, {
status: "pending",
data,
error: null
}));
},
onError: (error) => {
var _optsRef$current$onEr, _optsRef$current3;
(_optsRef$current$onEr = (_optsRef$current3 = optsRef.current).onError) === null || _optsRef$current$onEr === void 0 || _optsRef$current$onEr.call(_optsRef$current3, error);
updateState((prev) => require_utils._objectSpread2(require_utils._objectSpread2({}, prev), {}, {
status: "error",
error
}));
},
onStopped: () => {
var _optsRef$current$onSt2, _optsRef$current4;
if (isUnsubscribed) return;
setEnded();
(_optsRef$current$onSt2 = (_optsRef$current4 = optsRef.current).onStopped) === null || _optsRef$current$onSt2 === void 0 || _optsRef$current$onSt2.call(_optsRef$current4);
},
onComplete: () => {
var _optsRef$current$onCo, _optsRef$current5;
if (isUnsubscribed) return;
setEnded();
(_optsRef$current$onCo = (_optsRef$current5 = optsRef.current).onComplete) === null || _optsRef$current$onCo === void 0 || _optsRef$current$onCo.call(_optsRef$current5);
},
onConnectionStateChange: (result) => {
var _optsRef$current$onCo2, _optsRef$current6;
(_optsRef$current$onCo2 = (_optsRef$current6 = optsRef.current).onConnectionStateChange) === null || _optsRef$current$onCo2 === void 0 || _optsRef$current$onCo2.call(_optsRef$current6, result);
updateState((prev) => {
switch (result.state) {
case "connecting": return require_utils._objectSpread2(require_utils._objectSpread2({}, prev), {}, {
status: "connecting",
error: result.error
});
case "pending": return prev;
case "idle": return require_utils._objectSpread2(require_utils._objectSpread2({}, prev), {}, {
status: "idle",
data: void 0,
error: null
});
}
});
}
});
currentSubscriptionRef.current = () => {
isUnsubscribed = true;
subscription.unsubscribe();
};
}, [(0, _tanstack_react_query.hashKey)(opts.queryKey), opts.enabled]);
const getInitialState = react.useCallback(() => {
return opts.enabled ? {
data: void 0,
error: null,
status: "connecting",
reset
} : {
data: void 0,
error: null,
status: "idle",
reset
};
}, [opts.enabled, reset]);
const resultRef = react.useRef(getInitialState());
const [state, setState] = react.useState(trackResult(resultRef, addTrackedProp));
state.reset = reset;
const updateState = react.useCallback((callback) => {
const prev = resultRef.current;
const next = resultRef.current = callback(prev);
let shouldUpdate = false;
for (const key of trackedProps.current) if (prev[key] !== next[key]) {
shouldUpdate = true;
break;
}
if (shouldUpdate) setState(trackResult(resultRef, addTrackedProp));
}, [addTrackedProp]);
react.useEffect(() => {
if (!opts.enabled) return;
reset();
return () => {
var _currentSubscriptionR2;
(_currentSubscriptionR2 = currentSubscriptionRef.current) === null || _currentSubscriptionR2 === void 0 || _currentSubscriptionR2.call(currentSubscriptionRef);
};
}, [reset, opts.enabled]);
return state;
}
function trackResult(result, onTrackResult) {
return new Proxy(result.current, { get(_target, prop) {
onTrackResult(prop);
return result.current[prop];
} });
}
//#endregion
//#region src/internals/createOptionsProxy.ts
/**
* Creates the options proxy without React context. Works on the server too.
*
* @example
* ```ts
* export const trpc = createTRPCOptionsProxy<AppRouter>({
* client: trpcClient,
* queryClient,
* });
* ```
*
* @see https://trpc.io/docs/client/tanstack-react-query/setup#3c-set-up-without-react-context
* @see https://trpc.io/docs/client/tanstack-react-query/server-components#5-create-a-trpc-caller-for-server-components
*/
function createTRPCOptionsProxy(opts) {
const prefix = opts.keyPrefix;
const callIt = (type) => {
return (path, input, trpcOpts) => {
if ("router" in opts) return Promise.resolve(require_utils.unwrapLazyArg(opts.ctx)).then((ctx) => (0, _trpc_server.callTRPCProcedure)({
router: opts.router,
path,
getRawInput: async () => input,
ctx,
type,
signal: void 0,
batchIndex: 0
}));
return (opts.client instanceof _trpc_client.TRPCUntypedClient ? opts.client : (0, _trpc_client.getUntypedClient)(opts.client))[type](path, input, trpcOpts);
};
};
return (0, _trpc_server.createTRPCRecursiveProxy)(({ args, path: _path }) => {
const path = [..._path];
const utilName = path.pop();
const [arg1, arg2] = args;
return {
"~types": void 0,
"~queryClient": () => require_utils.unwrapLazyArg(opts.queryClient),
pathKey: () => {
return require_utils.getQueryKeyInternal({
path,
type: "any",
prefix
});
},
pathFilter: () => {
return require_utils._objectSpread2(require_utils._objectSpread2({}, arg1), {}, { queryKey: require_utils.getQueryKeyInternal({
path,
type: "any",
prefix
}) });
},
queryOptions: () => {
return trpcQueryOptions({
input: arg1,
opts: arg2,
path,
queryClient: opts.queryClient,
queryKey: require_utils.getQueryKeyInternal({
path,
input: arg1,
type: "query",
prefix
}),
query: callIt("query")
});
},
queryKey: () => {
return require_utils.getQueryKeyInternal({
path,
input: arg1,
type: "query",
prefix
});
},
queryFilter: () => {
return require_utils._objectSpread2(require_utils._objectSpread2({}, arg2), {}, { queryKey: require_utils.getQueryKeyInternal({
path,
input: arg1,
type: "query",
prefix
}) });
},
infiniteQueryOptions: () => {
return trpcInfiniteQueryOptions({
input: arg1,
opts: arg2,
path,
queryClient: opts.queryClient,
queryKey: require_utils.getQueryKeyInternal({
path,
input: arg1,
type: "infinite",
prefix
}),
query: callIt("query")
});
},
infiniteQueryKey: () => {
return require_utils.getQueryKeyInternal({
path,
input: arg1,
type: "infinite",
prefix
});
},
infiniteQueryFilter: () => {
return require_utils._objectSpread2(require_utils._objectSpread2({}, arg2), {}, { queryKey: require_utils.getQueryKeyInternal({
path,
input: arg1,
type: "infinite",
prefix
}) });
},
mutationOptions: () => {
var _opts$overrides;
return trpcMutationOptions({
opts: arg1,
path,
prefix,
queryClient: opts.queryClient,
mutate: callIt("mutation"),
overrides: (_opts$overrides = opts.overrides) === null || _opts$overrides === void 0 ? void 0 : _opts$overrides.mutations
});
},
mutationKey: () => {
return require_utils.getMutationKeyInternal({
path,
prefix
});
},
subscriptionOptions: () => {
return trpcSubscriptionOptions({
opts: arg2,
path,
input: arg1,
queryKey: require_utils.getQueryKeyInternal({
path,
input: arg1,
type: "any",
prefix
}),
subscribe: callIt("subscription")
});
}
}[utilName]();
});
}
//#endregion
//#region src/internals/Context.tsx
/**
* Creates a `TRPCProvider` and the `useTRPC` and `useTRPCClient` hooks for
* your router.
*
* @example
* ```ts
* export const { TRPCProvider, useTRPC, useTRPCClient } =
* createTRPCContext<AppRouter>();
* ```
*
* @see https://trpc.io/docs/client/tanstack-react-query/setup#3a-set-up-the-trpc-context-provider
*/
function createTRPCContext() {
const TRPCClientContext = react.createContext(null);
const TRPCContext = react.createContext(null);
const TRPCProvider = (props) => {
const value = react.useMemo(() => createTRPCOptionsProxy({
client: props.trpcClient,
queryClient: props.queryClient,
keyPrefix: props.keyPrefix
}), [
props.trpcClient,
props.queryClient,
props.keyPrefix
]);
return /* @__PURE__ */ react.createElement(TRPCClientContext.Provider, { value: props.trpcClient }, /* @__PURE__ */ react.createElement(TRPCContext.Provider, { value }, props.children));
};
TRPCProvider.displayName = "TRPCProvider";
function useTRPC() {
const utils = react.useContext(TRPCContext);
if (!utils) throw new Error("useTRPC() can only be used inside of a <TRPCProvider>");
return utils;
}
function useTRPCClient() {
const client = react.useContext(TRPCClientContext);
if (!client) throw new Error("useTRPCClient() can only be used inside of a <TRPCProvider>");
return client;
}
return {
TRPCProvider,
useTRPC,
useTRPCClient
};
}
//#endregion
//#region src/internals/hydration.ts
/**
* Keyed by the request's `QueryClient`, so one server render's boundaries
* share it and the next request starts over.
*/
const sentByClient = /* @__PURE__ */ new WeakMap();
function sentEntries(queryClient) {
let sent = sentByClient.get(queryClient);
if (!sent) {
sent = {
queries: /* @__PURE__ */ new Map(),
mutations: /* @__PURE__ */ new WeakSet(),
watchingPending: false
};
sentByClient.set(queryClient, sent);
}
return sent;
}
/**
* A query sent pending carries its request's promise, so the data that
* request writes is already on its way. Record it once it lands: the query
* drops its promise after settling, so it can't be compared later.
*/
function watchPendingSends(queryClient, sent) {
if (sent.watchingPending) return;
sent.watchingPending = true;
queryClient.getQueryCache().subscribe((event) => {
if (event.type !== "updated" || event.action.type !== "success" || event.action.manual) return;
const entry = sent.queries.get(event.query.queryHash);
if ((entry === null || entry === void 0 ? void 0 : entry.promise) && entry.promise === event.query.promise) {
entry.dataUpdatedAt = event.query.state.dataUpdatedAt;
entry.promise = void 0;
}
});
}
function isAlreadySent(query, sent) {
return sent !== void 0 && query.state.dataUpdatedAt <= sent.dataUpdatedAt;
}
/**
* Dehydrate what the client's `dehydrate` defaults select, minus entries an
* earlier call already sent for this client with the same or newer data.
* @internal
*/
function dehydrateUnsent(queryClient) {
var _defaults$shouldDehyd, _defaults$shouldDehyd2;
const defaults = queryClient.getDefaultOptions().dehydrate;
const shouldDehydrateQuery = (_defaults$shouldDehyd = defaults === null || defaults === void 0 ? void 0 : defaults.shouldDehydrateQuery) !== null && _defaults$shouldDehyd !== void 0 ? _defaults$shouldDehyd : _tanstack_react_query.defaultShouldDehydrateQuery;
const shouldDehydrateMutation = (_defaults$shouldDehyd2 = defaults === null || defaults === void 0 ? void 0 : defaults.shouldDehydrateMutation) !== null && _defaults$shouldDehyd2 !== void 0 ? _defaults$shouldDehyd2 : _tanstack_react_query.defaultShouldDehydrateMutation;
const sent = sentEntries(queryClient);
return (0, _tanstack_react_query.dehydrate)(queryClient, {
shouldDehydrateQuery: (query) => {
if (isAlreadySent(query, sent.queries.get(query.queryHash)) || !shouldDehydrateQuery(query)) return false;
const promise = query.state.status === "pending" ? query.promise : void 0;
if (promise) watchPendingSends(queryClient, sent);
sent.queries.set(query.queryHash, {
dataUpdatedAt: query.state.dataUpdatedAt,
promise
});
return true;
},
shouldDehydrateMutation: (mutation) => {
if (sent.mutations.has(mutation) || !shouldDehydrateMutation(mutation)) return false;
sent.mutations.add(mutation);
return true;
}
});
}
//#endregion
//#region src/internals/HydrateClient.tsx
/**
* Create a `HydrateClient` server component for the request's `QueryClient`.
* It sends the queries started so far in this request to the browser,
* pending ones as promises that stream in as they settle. A query an earlier
* `HydrateClient` already sent is skipped, so nesting them is fine.
*
* React Server Components only: the package resolves to the server build
* through the `react-server` export condition.
*
* @see https://trpc.io/docs/client/tanstack-react-query/handles#hydrate-client
*/
function unstable_createHydrateClient(_queryClient) {
function HydrateClient() {
throw new Error("`HydrateClient` from `unstable_createHydrateClient()` works only in React Server Components. Render it from a server component; in client components, use TanStack Query's `HydrationBoundary`.");
}
return HydrateClient;
}
/**
* `unstable_createHydrateClient` for the `react-server` export condition.
* @internal
*/
function createHydrateClientReactServer(queryClient) {
function HydrateClient(props) {
return /* @__PURE__ */ react.createElement(_tanstack_react_query.HydrationBoundary, { state: dehydrateUnsent(require_utils.unwrapLazyArg(queryClient)) }, props.children);
}
return HydrateClient;
}
//#endregion
Object.defineProperty(exports, "createHydrateClientReactServer", {
enumerable: true,
get: function() {
return createHydrateClientReactServer;
}
});
Object.defineProperty(exports, "createTRPCContext", {
enumerable: true,
get: function() {
return createTRPCContext;
}
});
Object.defineProperty(exports, "createTRPCOptionsProxy", {
enumerable: true,
get: function() {
return createTRPCOptionsProxy;
}
});
Object.defineProperty(exports, "unstable_createHydrateClient", {
enumerable: true,
get: function() {
return unstable_createHydrateClient;
}
});
Object.defineProperty(exports, "useSubscription", {
enumerable: true,
get: function() {
return useSubscription;
}
});