rc inital
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# Solid tRPC - v10 - RC
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
I recommend using [Create JD App](https://github.com/OrJDev/create-jd-app) but if you want to create a project from scratch, you can follow the steps below:
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @trpc/client@10.0.0-rc.2 @trpc/server@10.0.0-rc.2 solid-trpc@next @tanstack/solid-query
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating A Client
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// utils/trpc.ts
|
||||||
|
import { IAppRouter } from "@/whereMyRouterAt"; // your router type
|
||||||
|
import { createTRPCSolid } from "solid-trpc";
|
||||||
|
import { httpBatchLink } from "@trpc/client";
|
||||||
|
import { QueryClient } from "@tanstack/solid-query";
|
||||||
|
|
||||||
|
export const trpc = createTRPCSolid<IAppRouter>();
|
||||||
|
export const client = trpc.createClient({
|
||||||
|
links: [
|
||||||
|
httpBatchLink({
|
||||||
|
url: "/api/trpc",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
export const queryClient = new QueryClient();
|
||||||
|
```
|
||||||
|
|
||||||
|
### TRPC Provider
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// App.tsx
|
||||||
|
import { Component } from "solid-js";
|
||||||
|
import { client, trpc, queryClient } from "./utils/trpc"; // the client we created above
|
||||||
|
import Home from "./pages/Home"; // page for instance
|
||||||
|
|
||||||
|
interface IAppProps {}
|
||||||
|
|
||||||
|
const App: Component<IAppProps> = ({}) => {
|
||||||
|
return (
|
||||||
|
<trpc.Provider client={client} queryClient={queryClient}>
|
||||||
|
<Home />
|
||||||
|
</trpc.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
||||||
|
```
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
module.exports = {
|
||||||
|
env: {
|
||||||
|
test: {
|
||||||
|
presets: [
|
||||||
|
['@babel/preset-env', { targets: { node: 'current' } }],
|
||||||
|
'@babel/preset-typescript'
|
||||||
|
],
|
||||||
|
plugins: ['babel-plugin-jsx-dom-expressions']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
Generated
+1948
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"name": "solid-trpc",
|
||||||
|
"description": "SolidJS tRPC",
|
||||||
|
"author": "OrJDev",
|
||||||
|
"license": "MIT",
|
||||||
|
"version": "0.0.1-rc.1",
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public",
|
||||||
|
"tag": "next"
|
||||||
|
},
|
||||||
|
"type": "module",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"solid": "./dist/index.jsx",
|
||||||
|
"default": "./dist/index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"sideEffects": false,
|
||||||
|
"scripts": {
|
||||||
|
"build": "rm -rf dist && tsc && rollup -c && node scripts/cp"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.18.13",
|
||||||
|
"@babel/preset-typescript": "^7.18.6",
|
||||||
|
"@rollup/plugin-babel": "5.3.1",
|
||||||
|
"@rollup/plugin-node-resolve": "13.3.0",
|
||||||
|
"@tanstack/solid-query": "^4.6.1",
|
||||||
|
"@trpc/client": "10.0.0-rc.2",
|
||||||
|
"@trpc/server": "10.0.0-rc.2",
|
||||||
|
"@types/node": "^18.7.14",
|
||||||
|
"babel-preset-solid": "^1.5.3",
|
||||||
|
"rollup": "^2.79.0",
|
||||||
|
"solid-js": "^1.5.3",
|
||||||
|
"typescript": "^4.8.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@tanstack/solid-query": "^4.6.1",
|
||||||
|
"@trpc/client": "10.0.0-rc.2",
|
||||||
|
"@trpc/server": "10.0.0-rc.2",
|
||||||
|
"solid-js": "^1.5.3"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"solidjs",
|
||||||
|
"trpc"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/OrJDev/solid-trpc.git"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/OrJDev/solid-trpc/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/OrJDev/solid-trpc#readme"
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import babel from "@rollup/plugin-babel";
|
||||||
|
import nodeResolve from "@rollup/plugin-node-resolve";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
input: "src/index.tsx",
|
||||||
|
output: [
|
||||||
|
{
|
||||||
|
file: "dist/index.js",
|
||||||
|
format: "es",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
external: ["solid-js", "solid-js/web"],
|
||||||
|
plugins: [
|
||||||
|
nodeResolve({
|
||||||
|
extensions: [".js", ".ts", ".tsx"],
|
||||||
|
}),
|
||||||
|
babel({
|
||||||
|
extensions: [".js", ".ts", ".tsx"],
|
||||||
|
babelHelpers: "bundled",
|
||||||
|
presets: ["solid", "@babel/preset-typescript"],
|
||||||
|
exclude: "node_modules/**",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { existsSync } from "fs";
|
||||||
|
import fs from "fs/promises";
|
||||||
|
import path from "path";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
|
||||||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
if (!existsSync(path.join(__dirname, "../dist"))) {
|
||||||
|
await fs.mkdir(path.join(__dirname, "../dist"));
|
||||||
|
}
|
||||||
|
await fs.copyFile(
|
||||||
|
path.join(__dirname, "../README.MD"),
|
||||||
|
path.join(__dirname, "../dist/README.MD")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
main().catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
});
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
import { TRPCClientErrorLike } from "@trpc/client";
|
||||||
|
import {
|
||||||
|
AnyMutationProcedure,
|
||||||
|
AnyProcedure,
|
||||||
|
AnyQueryProcedure,
|
||||||
|
AnyRouter,
|
||||||
|
AnySubscriptionProcedure,
|
||||||
|
ProcedureRouterRecord,
|
||||||
|
inferProcedureInput,
|
||||||
|
inferProcedureOutput,
|
||||||
|
} from "@trpc/server";
|
||||||
|
import { inferObservableValue } from "@trpc/server/observable";
|
||||||
|
import { createFlatProxy } from "@trpc/server/shared";
|
||||||
|
import {
|
||||||
|
CreateReactUtilsProxy,
|
||||||
|
createReactProxyDecoration,
|
||||||
|
createReactQueryUtilsProxy,
|
||||||
|
} from "./shared";
|
||||||
|
import {
|
||||||
|
CreateClient,
|
||||||
|
CreateReactQueryHooks,
|
||||||
|
TRPCProvider,
|
||||||
|
UseDehydratedState,
|
||||||
|
UseTRPCInfiniteQueryOptions,
|
||||||
|
UseTRPCInfiniteQueryResult,
|
||||||
|
UseTRPCMutationOptions,
|
||||||
|
UseTRPCMutationResult,
|
||||||
|
UseTRPCQueryOptions,
|
||||||
|
UseTRPCQueryResult,
|
||||||
|
UseTRPCSubscriptionOptions,
|
||||||
|
createHooksInternal,
|
||||||
|
} from "./shared/hooks/createHooksInternal";
|
||||||
|
import { CreateTRPCSolidOptions } from "./shared/types";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export type DecorateProcedure<
|
||||||
|
TProcedure extends AnyProcedure,
|
||||||
|
TPath extends string
|
||||||
|
> = TProcedure extends AnyQueryProcedure
|
||||||
|
? {
|
||||||
|
useQuery: <
|
||||||
|
TQueryFnData = inferProcedureOutput<TProcedure>,
|
||||||
|
TData = inferProcedureOutput<TProcedure>
|
||||||
|
>(
|
||||||
|
input: inferProcedureInput<TProcedure>,
|
||||||
|
opts?: UseTRPCQueryOptions<
|
||||||
|
TPath,
|
||||||
|
inferProcedureInput<TProcedure>,
|
||||||
|
TQueryFnData,
|
||||||
|
TData,
|
||||||
|
TRPCClientErrorLike<TProcedure>
|
||||||
|
>
|
||||||
|
) => UseTRPCQueryResult<TData, TRPCClientErrorLike<TProcedure>>;
|
||||||
|
} & (inferProcedureInput<TProcedure> extends { cursor?: any }
|
||||||
|
? {
|
||||||
|
useInfiniteQuery: <
|
||||||
|
_TQueryFnData = inferProcedureOutput<TProcedure>,
|
||||||
|
TData = inferProcedureOutput<TProcedure>
|
||||||
|
>(
|
||||||
|
input: Omit<inferProcedureInput<TProcedure>, "cursor">,
|
||||||
|
opts?: UseTRPCInfiniteQueryOptions<
|
||||||
|
TPath,
|
||||||
|
inferProcedureInput<TProcedure>,
|
||||||
|
TData,
|
||||||
|
TRPCClientErrorLike<TProcedure>
|
||||||
|
>
|
||||||
|
) => UseTRPCInfiniteQueryResult<
|
||||||
|
TData,
|
||||||
|
TRPCClientErrorLike<TProcedure>
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
: {})
|
||||||
|
: TProcedure extends AnyMutationProcedure
|
||||||
|
? {
|
||||||
|
useMutation: <TContext = unknown>(
|
||||||
|
opts?: UseTRPCMutationOptions<
|
||||||
|
inferProcedureInput<TProcedure>,
|
||||||
|
TRPCClientErrorLike<TProcedure>,
|
||||||
|
inferProcedureOutput<TProcedure>,
|
||||||
|
TContext
|
||||||
|
>
|
||||||
|
) => UseTRPCMutationResult<
|
||||||
|
inferProcedureOutput<TProcedure>,
|
||||||
|
TRPCClientErrorLike<TProcedure>,
|
||||||
|
inferProcedureInput<TProcedure>,
|
||||||
|
TContext
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
: TProcedure extends AnySubscriptionProcedure
|
||||||
|
? {
|
||||||
|
useSubscription: (
|
||||||
|
input: inferProcedureInput<TProcedure>,
|
||||||
|
opts?: UseTRPCSubscriptionOptions<
|
||||||
|
inferObservableValue<inferProcedureOutput<TProcedure>>,
|
||||||
|
TRPCClientErrorLike<TProcedure>
|
||||||
|
>
|
||||||
|
) => void;
|
||||||
|
}
|
||||||
|
: never;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export type DecoratedProcedureRecord<
|
||||||
|
TProcedures extends ProcedureRouterRecord,
|
||||||
|
TPath extends string = ""
|
||||||
|
> = {
|
||||||
|
[TKey in keyof TProcedures]: TProcedures[TKey] extends AnyRouter
|
||||||
|
? DecoratedProcedureRecord<
|
||||||
|
TProcedures[TKey]["_def"]["record"],
|
||||||
|
`${TPath}${TKey & string}.`
|
||||||
|
>
|
||||||
|
: TProcedures[TKey] extends AnyProcedure
|
||||||
|
? DecorateProcedure<TProcedures[TKey], `${TPath}${TKey & string}`>
|
||||||
|
: never;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreateTRPCSolid<TRouter extends AnyRouter, TSSRContext> = {
|
||||||
|
useContext(): CreateReactUtilsProxy<TRouter, TSSRContext>;
|
||||||
|
Provider: TRPCProvider<TRouter, TSSRContext>;
|
||||||
|
createClient: CreateClient<TRouter>;
|
||||||
|
useDehydratedState: UseDehydratedState<TRouter>;
|
||||||
|
} & DecoratedProcedureRecord<TRouter["_def"]["record"]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export function createHooksInternalProxy<
|
||||||
|
TRouter extends AnyRouter,
|
||||||
|
TSSRContext = unknown
|
||||||
|
>(trpc: CreateReactQueryHooks<TRouter, TSSRContext>) {
|
||||||
|
type CreateHooksInternalProxy = CreateTRPCSolid<TRouter, TSSRContext>;
|
||||||
|
|
||||||
|
return createFlatProxy<CreateHooksInternalProxy>((key) => {
|
||||||
|
if (key === "useContext") {
|
||||||
|
return () => {
|
||||||
|
const context = trpc.useContext();
|
||||||
|
// create a stable reference of the utils context
|
||||||
|
return (createReactQueryUtilsProxy as any)(context as any);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((key as string) in trpc) {
|
||||||
|
return (trpc as any)[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return createReactProxyDecoration(key as string, trpc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createTRPCSolid<
|
||||||
|
TRouter extends AnyRouter,
|
||||||
|
TSSRContext = unknown
|
||||||
|
>(opts?: CreateTRPCSolidOptions<TRouter>) {
|
||||||
|
const hooks = createHooksInternal<TRouter, TSSRContext>(opts);
|
||||||
|
const proxy = createHooksInternalProxy<TRouter, TSSRContext>(hooks);
|
||||||
|
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export * from "@trpc/client";
|
||||||
|
|
||||||
|
export { createTRPCSolid, type CreateTRPCSolid } from "./createTRPCSolid";
|
||||||
|
export { createReactQueryHooks } from "./interop";
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
import {
|
||||||
|
CancelOptions,
|
||||||
|
FetchInfiniteQueryOptions,
|
||||||
|
FetchQueryOptions,
|
||||||
|
InfiniteData,
|
||||||
|
InvalidateOptions,
|
||||||
|
InvalidateQueryFilters,
|
||||||
|
QueryClient,
|
||||||
|
RefetchOptions,
|
||||||
|
RefetchQueryFilters,
|
||||||
|
SetDataOptions,
|
||||||
|
Updater,
|
||||||
|
} from "@tanstack/solid-query";
|
||||||
|
import { TRPCClient, TRPCClientError, TRPCRequestOptions } from "@trpc/client";
|
||||||
|
import type {
|
||||||
|
AnyRouter,
|
||||||
|
inferHandlerInput,
|
||||||
|
inferProcedureInput,
|
||||||
|
inferProcedureOutput,
|
||||||
|
} from "@trpc/server";
|
||||||
|
import { createContext } from "solid-js";
|
||||||
|
|
||||||
|
export interface TRPCFetchQueryOptions<TInput, TError, TOutput>
|
||||||
|
extends FetchQueryOptions<TInput, TError, TOutput>,
|
||||||
|
TRPCRequestOptions {}
|
||||||
|
|
||||||
|
export interface TRPCFetchInfiniteQueryOptions<TInput, TError, TOutput>
|
||||||
|
extends FetchInfiniteQueryOptions<TInput, TError, TOutput>,
|
||||||
|
TRPCRequestOptions {}
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
export type SSRState = false | "prepass" | "mounting" | "mounted";
|
||||||
|
|
||||||
|
export interface ProxyTRPCContextProps<TRouter extends AnyRouter, TSSRContext> {
|
||||||
|
/**
|
||||||
|
* The `TRPCClient`
|
||||||
|
*/
|
||||||
|
client: TRPCClient<TRouter>;
|
||||||
|
/**
|
||||||
|
* The SSR context when server-side rendering
|
||||||
|
* @default null
|
||||||
|
*/
|
||||||
|
ssrContext?: TSSRContext | null;
|
||||||
|
/**
|
||||||
|
* State of SSR hydration.
|
||||||
|
* - `false` if not using SSR.
|
||||||
|
* - `prepass` when doing a prepass to fetch queries' data
|
||||||
|
* - `mounting` before TRPCProvider has been rendered on the client
|
||||||
|
* - `mounted` when the TRPCProvider has been rendered on the client
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
ssrState?: SSRState;
|
||||||
|
/**
|
||||||
|
* Abort loading query calls when unmounting a component - usually when navigating to a new page
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
abortOnUnmount?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TRPCContextProps<TRouter extends AnyRouter, TSSRContext>
|
||||||
|
extends ProxyTRPCContextProps<TRouter, TSSRContext> {
|
||||||
|
/**
|
||||||
|
* The react-query `QueryClient`
|
||||||
|
*/
|
||||||
|
queryClient: QueryClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const contextProps: (keyof ProxyTRPCContextProps<any, any>)[] = [
|
||||||
|
"client",
|
||||||
|
"ssrContext",
|
||||||
|
"ssrState",
|
||||||
|
"abortOnUnmount",
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
export interface TRPCContextState<
|
||||||
|
TRouter extends AnyRouter,
|
||||||
|
TSSRContext = undefined
|
||||||
|
> extends Required<TRPCContextProps<TRouter, TSSRContext>> {
|
||||||
|
/**
|
||||||
|
* @link https://tanstack.com/query/v4/docs/reference/QueryClient#queryclientfetchquery
|
||||||
|
*/
|
||||||
|
fetchQuery<
|
||||||
|
TPath extends keyof TRouter["_def"]["queries"] & string,
|
||||||
|
TProcedure extends TRouter["_def"]["queries"][TPath],
|
||||||
|
TOutput extends inferProcedureOutput<TProcedure>,
|
||||||
|
TInput extends inferProcedureInput<TProcedure>
|
||||||
|
>(
|
||||||
|
pathAndInput: [path: TPath, ...args: inferHandlerInput<TProcedure>],
|
||||||
|
opts?: TRPCFetchQueryOptions<TInput, TRPCClientError<TRouter>, TOutput>
|
||||||
|
): Promise<TOutput>;
|
||||||
|
/**
|
||||||
|
* @link https://tanstack.com/query/v4/docs/reference/QueryClient#queryclientfetchinfinitequery
|
||||||
|
*/
|
||||||
|
fetchInfiniteQuery<
|
||||||
|
TPath extends keyof TRouter["_def"]["queries"] & string,
|
||||||
|
TProcedure extends TRouter["_def"]["queries"][TPath],
|
||||||
|
TOutput extends inferProcedureOutput<TProcedure>,
|
||||||
|
TInput extends inferProcedureInput<TProcedure>
|
||||||
|
>(
|
||||||
|
pathAndInput: [path: TPath, ...args: inferHandlerInput<TProcedure>],
|
||||||
|
opts?: TRPCFetchInfiniteQueryOptions<
|
||||||
|
TInput,
|
||||||
|
TRPCClientError<TRouter>,
|
||||||
|
TOutput
|
||||||
|
>
|
||||||
|
): Promise<InfiniteData<TOutput>>;
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/guides/prefetching
|
||||||
|
*/
|
||||||
|
prefetchQuery<
|
||||||
|
TPath extends keyof TRouter["_def"]["queries"] & string,
|
||||||
|
TProcedure extends TRouter["_def"]["queries"][TPath],
|
||||||
|
TOutput extends inferProcedureOutput<TProcedure>,
|
||||||
|
TInput extends inferProcedureInput<TProcedure>
|
||||||
|
>(
|
||||||
|
pathAndInput: [path: TPath, ...args: inferHandlerInput<TProcedure>],
|
||||||
|
opts?: TRPCFetchQueryOptions<TInput, TRPCClientError<TRouter>, TOutput>
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @link https://tanstack.com/query/v4/docs/reference/QueryClient#queryclientprefetchinfinitequery
|
||||||
|
*/
|
||||||
|
prefetchInfiniteQuery<
|
||||||
|
TPath extends keyof TRouter["_def"]["queries"] & string,
|
||||||
|
TProcedure extends TRouter["_def"]["queries"][TPath],
|
||||||
|
TOutput extends inferProcedureOutput<TProcedure>,
|
||||||
|
TInput extends inferProcedureInput<TProcedure>
|
||||||
|
>(
|
||||||
|
pathAndInput: [path: TPath, ...args: inferHandlerInput<TProcedure>],
|
||||||
|
opts?: TRPCFetchInfiniteQueryOptions<
|
||||||
|
TInput,
|
||||||
|
TRPCClientError<TRouter>,
|
||||||
|
TOutput
|
||||||
|
>
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/guides/query-invalidation
|
||||||
|
*/
|
||||||
|
invalidateQueries<
|
||||||
|
TPath extends keyof TRouter["_def"]["queries"] & string,
|
||||||
|
TInput extends inferProcedureInput<TRouter["_def"]["queries"][TPath]>
|
||||||
|
>(
|
||||||
|
pathAndInput?: [TPath, TInput?] | TPath,
|
||||||
|
filters?: InvalidateQueryFilters,
|
||||||
|
options?: InvalidateOptions
|
||||||
|
): Promise<void>;
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/guides/query-invalidation
|
||||||
|
*/
|
||||||
|
invalidateQueries(
|
||||||
|
filters?: InvalidateQueryFilters,
|
||||||
|
options?: InvalidateOptions
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/reference/QueryClient#queryclientrefetchqueries
|
||||||
|
*/
|
||||||
|
refetchQueries<
|
||||||
|
TPath extends keyof TRouter["_def"]["queries"] & string,
|
||||||
|
TInput extends inferProcedureInput<TRouter["_def"]["queries"][TPath]>
|
||||||
|
>(
|
||||||
|
pathAndInput: [TPath, TInput?],
|
||||||
|
filters?: RefetchQueryFilters,
|
||||||
|
options?: RefetchOptions
|
||||||
|
): Promise<void>;
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/reference/QueryClient#queryclientrefetchqueries
|
||||||
|
*/
|
||||||
|
refetchQueries(
|
||||||
|
filters?: RefetchQueryFilters,
|
||||||
|
options?: RefetchOptions
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/guides/query-cancellation
|
||||||
|
*/
|
||||||
|
cancelQuery<
|
||||||
|
TPath extends keyof TRouter["_def"]["queries"] & string,
|
||||||
|
TInput extends inferProcedureInput<TRouter["_def"]["queries"][TPath]>
|
||||||
|
>(
|
||||||
|
pathAndInput: [TPath, TInput?],
|
||||||
|
options?: CancelOptions
|
||||||
|
): Promise<void>;
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/reference/QueryClient#queryclientsetquerydata
|
||||||
|
*/
|
||||||
|
setQueryData<
|
||||||
|
TPath extends keyof TRouter["_def"]["queries"] & string,
|
||||||
|
TInput extends inferProcedureInput<TRouter["_def"]["queries"][TPath]>,
|
||||||
|
TOutput extends inferProcedureOutput<TRouter["_def"]["queries"][TPath]>
|
||||||
|
>(
|
||||||
|
pathAndInput: [TPath, TInput?],
|
||||||
|
updater: Updater<TOutput | undefined, TOutput | undefined>,
|
||||||
|
options?: SetDataOptions
|
||||||
|
): void;
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/reference/QueryClient#queryclientgetquerydata
|
||||||
|
*/
|
||||||
|
getQueryData<
|
||||||
|
TPath extends keyof TRouter["_def"]["queries"] & string,
|
||||||
|
TInput extends inferProcedureInput<TRouter["_def"]["queries"][TPath]>,
|
||||||
|
TOutput extends inferProcedureOutput<TRouter["_def"]["queries"][TPath]>
|
||||||
|
>(
|
||||||
|
pathAndInput: [TPath, TInput?]
|
||||||
|
): TOutput | undefined;
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/reference/QueryClient#queryclientsetquerydata
|
||||||
|
*/
|
||||||
|
setInfiniteQueryData<
|
||||||
|
TPath extends keyof TRouter["_def"]["queries"] & string,
|
||||||
|
TInput extends inferProcedureInput<TRouter["_def"]["queries"][TPath]>,
|
||||||
|
TOutput extends inferProcedureOutput<TRouter["_def"]["queries"][TPath]>
|
||||||
|
>(
|
||||||
|
pathAndInput: [TPath, TInput?],
|
||||||
|
updater: Updater<
|
||||||
|
InfiniteData<TOutput> | undefined,
|
||||||
|
InfiniteData<TOutput> | undefined
|
||||||
|
>,
|
||||||
|
options?: SetDataOptions
|
||||||
|
): void;
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/reference/QueryClient#queryclientgetquerydata
|
||||||
|
*/
|
||||||
|
getInfiniteQueryData<
|
||||||
|
TPath extends keyof TRouter["_def"]["queries"] & string,
|
||||||
|
TInput extends inferProcedureInput<TRouter["_def"]["queries"][TPath]>,
|
||||||
|
TOutput extends inferProcedureOutput<TRouter["_def"]["queries"][TPath]>
|
||||||
|
>(
|
||||||
|
pathAndInput: [TPath, TInput?]
|
||||||
|
): InfiniteData<TOutput> | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TRPCContext = createContext(null as any);
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* To allow easy interactions with groups of related queries, such as
|
||||||
|
* invalidating all queries of a router, we use an array as the path when
|
||||||
|
* storing in tanstack query. This function converts from the `.` separated
|
||||||
|
* path passed around internally by both the legacy and proxy implementation.
|
||||||
|
* https://github.com/trpc/trpc/issues/2611
|
||||||
|
*/
|
||||||
|
export function getArrayQueryKey(
|
||||||
|
queryKey: string | [string] | [string, ...unknown[]] | unknown[],
|
||||||
|
): [string[]] | [string[], ...unknown[]] | [] {
|
||||||
|
const queryKeyArrayed = Array.isArray(queryKey) ? queryKey : [queryKey];
|
||||||
|
const [path, ...input] = queryKeyArrayed;
|
||||||
|
|
||||||
|
const arrayPath =
|
||||||
|
typeof path !== 'string' || path === '' ? [] : path.split('.');
|
||||||
|
|
||||||
|
return [arrayPath, ...input];
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* We treat `undefined` as an input the same as omitting an `input`
|
||||||
|
* https://github.com/trpc/trpc/issues/2290
|
||||||
|
*/
|
||||||
|
export function getQueryKey(
|
||||||
|
path: string,
|
||||||
|
input: unknown,
|
||||||
|
): [string] | [string, unknown] {
|
||||||
|
return input === undefined ? [path] : [path, input];
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// interop:
|
||||||
|
import { AnyRouter } from "@trpc/server";
|
||||||
|
import { CreateTRPCSolid, createHooksInternalProxy } from "./createTRPCSolid";
|
||||||
|
import { CreateTRPCSolidOptions } from "./shared";
|
||||||
|
import {
|
||||||
|
CreateReactQueryHooks,
|
||||||
|
createHooksInternal,
|
||||||
|
} from "./shared/hooks/createHooksInternal";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use `createTRPCSolid` instead
|
||||||
|
*/
|
||||||
|
export function createReactQueryHooks<
|
||||||
|
TRouter extends AnyRouter,
|
||||||
|
TSSRContext = unknown
|
||||||
|
>(
|
||||||
|
opts?: CreateTRPCSolidOptions<TRouter>
|
||||||
|
): CreateReactQueryHooks<TRouter, TSSRContext> & {
|
||||||
|
proxy: CreateTRPCSolid<TRouter, TSSRContext>;
|
||||||
|
} {
|
||||||
|
const trpc = createHooksInternal<TRouter, TSSRContext>(opts);
|
||||||
|
const proxy = createHooksInternalProxy<TRouter, TSSRContext>(trpc);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...trpc,
|
||||||
|
proxy,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,653 @@
|
|||||||
|
import {
|
||||||
|
DehydratedState,
|
||||||
|
QueryClient,
|
||||||
|
CreateInfiniteQueryOptions,
|
||||||
|
CreateInfiniteQueryResult,
|
||||||
|
CreateMutationOptions,
|
||||||
|
CreateMutationResult,
|
||||||
|
CreateQueryOptions,
|
||||||
|
CreateQueryResult,
|
||||||
|
createInfiniteQuery as __useInfiniteQuery,
|
||||||
|
createMutation as __useMutation,
|
||||||
|
createQuery as __useQuery,
|
||||||
|
hashQueryKey,
|
||||||
|
useQueryClient,
|
||||||
|
QueryClientProviderProps,
|
||||||
|
QueryClientProvider,
|
||||||
|
} from "@tanstack/solid-query";
|
||||||
|
import {
|
||||||
|
CreateTRPCClientOptions,
|
||||||
|
TRPCClient,
|
||||||
|
TRPCClientErrorLike,
|
||||||
|
TRPCRequestOptions,
|
||||||
|
createTRPCClient,
|
||||||
|
} from "@trpc/client";
|
||||||
|
import type {
|
||||||
|
AnyRouter,
|
||||||
|
ProcedureRecord,
|
||||||
|
inferHandlerInput,
|
||||||
|
inferProcedureClientError,
|
||||||
|
inferProcedureInput,
|
||||||
|
inferProcedureOutput,
|
||||||
|
inferSubscriptionOutput,
|
||||||
|
} from "@trpc/server";
|
||||||
|
import { inferObservableValue } from "@trpc/server/observable";
|
||||||
|
import {
|
||||||
|
Accessor,
|
||||||
|
Context,
|
||||||
|
createEffect,
|
||||||
|
createMemo,
|
||||||
|
createSignal,
|
||||||
|
JSX,
|
||||||
|
onCleanup,
|
||||||
|
onMount,
|
||||||
|
useContext as __useContext,
|
||||||
|
} from "solid-js";
|
||||||
|
import {
|
||||||
|
SSRState,
|
||||||
|
TRPCContext,
|
||||||
|
TRPCContextProps,
|
||||||
|
TRPCContextState,
|
||||||
|
} from "../../internals/context";
|
||||||
|
import { getArrayQueryKey } from "../../internals/getArrayQueryKey";
|
||||||
|
import { CreateTRPCSolidOptions, UseMutationOverride } from "../types";
|
||||||
|
|
||||||
|
export type OutputWithCursor<TData, TCursor = any> = {
|
||||||
|
cursor: TCursor | null;
|
||||||
|
data: TData;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface TRPCReactRequestOptions
|
||||||
|
// For RQ, we use their internal AbortSignals instead of letting the user pass their own
|
||||||
|
extends Omit<TRPCRequestOptions, "signal"> {
|
||||||
|
/**
|
||||||
|
* Opt out of SSR for this query by passing `ssr: false`
|
||||||
|
*/
|
||||||
|
ssr?: boolean;
|
||||||
|
/**
|
||||||
|
* Opt out or into aborting request on unmount
|
||||||
|
*/
|
||||||
|
abortOnUnmount?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TRPCUseQueryBaseOptions {
|
||||||
|
/**
|
||||||
|
* tRPC-related options
|
||||||
|
*/
|
||||||
|
trpc?: TRPCReactRequestOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type { TRPCContext, TRPCContextState } from "../../internals/context";
|
||||||
|
|
||||||
|
export interface UseTRPCQueryOptions<TPath, TInput, TOutput, TData, TError>
|
||||||
|
extends CreateQueryOptions<TOutput, TError, TData, () => [TPath, TInput]>,
|
||||||
|
TRPCUseQueryBaseOptions {}
|
||||||
|
|
||||||
|
export interface UseTRPCInfiniteQueryOptions<TPath, TInput, TOutput, TError>
|
||||||
|
extends CreateInfiniteQueryOptions<
|
||||||
|
TOutput,
|
||||||
|
TError,
|
||||||
|
TOutput,
|
||||||
|
TOutput,
|
||||||
|
() => [TPath, TInput]
|
||||||
|
>,
|
||||||
|
TRPCUseQueryBaseOptions {}
|
||||||
|
|
||||||
|
export interface UseTRPCMutationOptions<
|
||||||
|
TInput,
|
||||||
|
TError,
|
||||||
|
TOutput,
|
||||||
|
TContext = unknown
|
||||||
|
> extends CreateMutationOptions<TOutput, TError, TInput, TContext>,
|
||||||
|
TRPCUseQueryBaseOptions {}
|
||||||
|
|
||||||
|
export interface UseTRPCSubscriptionOptions<TOutput, TError> {
|
||||||
|
enabled?: boolean;
|
||||||
|
onStarted?: () => void;
|
||||||
|
onData: (data: TOutput) => void;
|
||||||
|
onError?: (err: TError) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getClientArgs<TPathAndInput extends unknown[], TOptions>(
|
||||||
|
pathAndInput: TPathAndInput,
|
||||||
|
opts: TOptions
|
||||||
|
) {
|
||||||
|
const [path, input] = pathAndInput;
|
||||||
|
return [path, input, (opts as any)?.trpc] as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
type inferInfiniteQueryNames<TObj extends ProcedureRecord> = {
|
||||||
|
[TPath in keyof TObj]: inferProcedureInput<TObj[TPath]> extends {
|
||||||
|
cursor?: any;
|
||||||
|
}
|
||||||
|
? TPath
|
||||||
|
: never;
|
||||||
|
}[keyof TObj];
|
||||||
|
|
||||||
|
type inferProcedures<TObj extends ProcedureRecord> = {
|
||||||
|
[TPath in keyof TObj]: {
|
||||||
|
input: inferProcedureInput<TObj[TPath]>;
|
||||||
|
output: inferProcedureOutput<TObj[TPath]>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface TRPCProviderProps<TRouter extends AnyRouter, TSSRContext>
|
||||||
|
extends TRPCContextProps<TRouter, TSSRContext> {
|
||||||
|
children: JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TRPCProvider<TRouter extends AnyRouter, TSSRContext> = (
|
||||||
|
props: TRPCProviderProps<TRouter, TSSRContext> & {
|
||||||
|
queryClientOpts?: Omit<QueryClientProviderProps, "client">;
|
||||||
|
}
|
||||||
|
) => JSX.Element;
|
||||||
|
|
||||||
|
export type UseDehydratedState<TRouter extends AnyRouter> = (
|
||||||
|
client: TRPCClient<TRouter>,
|
||||||
|
trpcState: DehydratedState | undefined
|
||||||
|
) => Accessor<DehydratedState | undefined>;
|
||||||
|
|
||||||
|
export type CreateClient<TRouter extends AnyRouter> = (
|
||||||
|
opts: CreateTRPCClientOptions<TRouter>
|
||||||
|
) => TRPCClient<TRouter>;
|
||||||
|
|
||||||
|
interface TRPCHookResult {
|
||||||
|
trpc: {
|
||||||
|
path: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export type UseTRPCQueryResult<TData, TError> = CreateQueryResult<
|
||||||
|
TData,
|
||||||
|
TError
|
||||||
|
> &
|
||||||
|
TRPCHookResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export type UseTRPCInfiniteQueryResult<TData, TError> =
|
||||||
|
CreateInfiniteQueryResult<TData, TError> & TRPCHookResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export type UseTRPCMutationResult<TData, TError, TVariables, TContext> =
|
||||||
|
CreateMutationResult<TData, TError, TVariables, TContext> & TRPCHookResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a stable reference of the `trpc` prop
|
||||||
|
*/
|
||||||
|
function useHookResult(value: TRPCHookResult["trpc"]): TRPCHookResult["trpc"] {
|
||||||
|
const ref = { current: value };
|
||||||
|
ref.current.path = value.path;
|
||||||
|
return ref.current;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Create strongly typed react hooks
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export function createHooksInternal<
|
||||||
|
TRouter extends AnyRouter,
|
||||||
|
TSSRContext = unknown
|
||||||
|
>(config?: CreateTRPCSolidOptions<TRouter>) {
|
||||||
|
const mutationSuccessOverride: UseMutationOverride["onSuccess"] =
|
||||||
|
config?.unstable_overrides?.useMutation?.onSuccess ??
|
||||||
|
((options) => options.originalFn());
|
||||||
|
|
||||||
|
type TQueries = TRouter["_def"]["queries"];
|
||||||
|
type TSubscriptions = TRouter["_def"]["subscriptions"];
|
||||||
|
type TMutations = TRouter["_def"]["mutations"];
|
||||||
|
|
||||||
|
type TError = TRPCClientErrorLike<TRouter>;
|
||||||
|
type TInfiniteQueryNames = inferInfiniteQueryNames<TQueries>;
|
||||||
|
|
||||||
|
type TQueryValues = inferProcedures<TQueries>;
|
||||||
|
type TMutationValues = inferProcedures<TMutations>;
|
||||||
|
|
||||||
|
type ProviderContext = Omit<
|
||||||
|
TRPCContextState<TRouter, TSSRContext>,
|
||||||
|
"ssrState"
|
||||||
|
> & {
|
||||||
|
ssrState: Accessor<TRPCContextState<TRouter, TSSRContext>["ssrState"]>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Context = (config?.context ?? TRPCContext) as Context<ProviderContext>;
|
||||||
|
const SolidQueryContext = config?.solidQueryContext as Context<
|
||||||
|
QueryClient | undefined
|
||||||
|
>;
|
||||||
|
|
||||||
|
const createClient: CreateClient<TRouter> = (opts) => {
|
||||||
|
return createTRPCClient(opts);
|
||||||
|
};
|
||||||
|
|
||||||
|
const TRPCProvider: TRPCProvider<TRouter, TSSRContext> = (props) => {
|
||||||
|
const { abortOnUnmount = false, client, queryClient, ssrContext } = props;
|
||||||
|
const [ssrState, setSSRState] = createSignal<SSRState>(
|
||||||
|
props.ssrState ?? false
|
||||||
|
);
|
||||||
|
onMount(() => {
|
||||||
|
// Only updating state to `mounted` if we are using SSR.
|
||||||
|
// This makes it so we don't have an unnecessary re-render when opting out of SSR.
|
||||||
|
setSSRState((state) => (state ? "mounted" : false));
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<Context.Provider
|
||||||
|
value={{
|
||||||
|
abortOnUnmount,
|
||||||
|
queryClient,
|
||||||
|
client,
|
||||||
|
ssrContext: ssrContext || null,
|
||||||
|
ssrState,
|
||||||
|
fetchQuery: (pathAndInput, opts) => {
|
||||||
|
return queryClient.fetchQuery(
|
||||||
|
getArrayQueryKey(pathAndInput),
|
||||||
|
() => (client as any).query(...getClientArgs(pathAndInput, opts)),
|
||||||
|
opts
|
||||||
|
);
|
||||||
|
},
|
||||||
|
fetchInfiniteQuery: (pathAndInput, opts) => {
|
||||||
|
return queryClient.fetchInfiniteQuery(
|
||||||
|
getArrayQueryKey(pathAndInput),
|
||||||
|
({ pageParam }) => {
|
||||||
|
const [path, input] = pathAndInput;
|
||||||
|
const actualInput = { ...(input as any), cursor: pageParam };
|
||||||
|
return (client as any).query(
|
||||||
|
...getClientArgs([path, actualInput], opts)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
opts
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
prefetchQuery: (pathAndInput, opts) => {
|
||||||
|
return queryClient.prefetchQuery(
|
||||||
|
getArrayQueryKey(pathAndInput),
|
||||||
|
() => (client as any).query(...getClientArgs(pathAndInput, opts)),
|
||||||
|
opts
|
||||||
|
);
|
||||||
|
},
|
||||||
|
prefetchInfiniteQuery: (pathAndInput, opts) => {
|
||||||
|
return queryClient.prefetchInfiniteQuery(
|
||||||
|
getArrayQueryKey(pathAndInput),
|
||||||
|
({ pageParam }) => {
|
||||||
|
const [path, input] = pathAndInput;
|
||||||
|
const actualInput = { ...(input as any), cursor: pageParam };
|
||||||
|
return (client as any).query(
|
||||||
|
...getClientArgs([path, actualInput], opts)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
opts
|
||||||
|
);
|
||||||
|
},
|
||||||
|
invalidateQueries: (...args: any[]) => {
|
||||||
|
const [queryKey, ...rest] = args;
|
||||||
|
return queryClient.invalidateQueries(
|
||||||
|
getArrayQueryKey(queryKey),
|
||||||
|
...rest
|
||||||
|
);
|
||||||
|
},
|
||||||
|
refetchQueries: (...args: any[]) => {
|
||||||
|
const [queryKey, ...rest] = args;
|
||||||
|
|
||||||
|
return queryClient.refetchQueries(
|
||||||
|
getArrayQueryKey(queryKey),
|
||||||
|
...rest
|
||||||
|
);
|
||||||
|
},
|
||||||
|
cancelQuery: (pathAndInput) => {
|
||||||
|
return queryClient.cancelQueries(getArrayQueryKey(pathAndInput));
|
||||||
|
},
|
||||||
|
setQueryData: (...args) => {
|
||||||
|
const [queryKey, ...rest] = args;
|
||||||
|
return queryClient.setQueryData(
|
||||||
|
getArrayQueryKey(queryKey),
|
||||||
|
...rest
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getQueryData: (...args) => {
|
||||||
|
const [queryKey, ...rest] = args;
|
||||||
|
|
||||||
|
return queryClient.getQueryData(
|
||||||
|
getArrayQueryKey(queryKey),
|
||||||
|
...rest
|
||||||
|
);
|
||||||
|
},
|
||||||
|
setInfiniteQueryData: (...args) => {
|
||||||
|
const [queryKey, ...rest] = args;
|
||||||
|
|
||||||
|
return queryClient.setQueryData(
|
||||||
|
getArrayQueryKey(queryKey),
|
||||||
|
...rest
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getInfiniteQueryData: (...args) => {
|
||||||
|
const [queryKey, ...rest] = args;
|
||||||
|
|
||||||
|
return queryClient.getQueryData(
|
||||||
|
getArrayQueryKey(queryKey),
|
||||||
|
...rest
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<QueryClientProvider
|
||||||
|
client={queryClient}
|
||||||
|
{...((props.queryClientOpts ?? {}) as any)}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</QueryClientProvider>
|
||||||
|
</Context.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
function useContext() {
|
||||||
|
return __useContext(Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hack to make sure errors return `status`='error` when doing SSR
|
||||||
|
* @link https://github.com/trpc/trpc/pull/1645
|
||||||
|
*/
|
||||||
|
function useSSRQueryOptionsIfNeeded<
|
||||||
|
TOptions extends { retryOnMount?: boolean } | undefined
|
||||||
|
>(pathAndInput: unknown[], opts: TOptions): TOptions {
|
||||||
|
const { queryClient, ssrState } = useContext();
|
||||||
|
return ssrState() &&
|
||||||
|
ssrState() !== "mounted" &&
|
||||||
|
queryClient.getQueryCache().find(getArrayQueryKey(pathAndInput))?.state
|
||||||
|
.status === "error"
|
||||||
|
? {
|
||||||
|
retryOnMount: false,
|
||||||
|
...opts,
|
||||||
|
}
|
||||||
|
: opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
function useQuery<
|
||||||
|
TPath extends keyof TQueryValues & string,
|
||||||
|
TQueryFnData = TQueryValues[TPath]["output"],
|
||||||
|
TData = TQueryValues[TPath]["output"]
|
||||||
|
>(
|
||||||
|
pathAndInput: [path: TPath, ...args: inferHandlerInput<TQueries[TPath]>],
|
||||||
|
opts?: UseTRPCQueryOptions<
|
||||||
|
TPath,
|
||||||
|
TQueryValues[TPath]["input"],
|
||||||
|
TQueryFnData,
|
||||||
|
TData,
|
||||||
|
TError
|
||||||
|
>
|
||||||
|
): UseTRPCQueryResult<TData, TError> {
|
||||||
|
const ctx = useContext();
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof window === "undefined" &&
|
||||||
|
ctx.ssrState() === "prepass" &&
|
||||||
|
opts?.trpc?.ssr !== false &&
|
||||||
|
opts?.enabled !== false &&
|
||||||
|
!ctx.queryClient.getQueryCache().find(getArrayQueryKey(pathAndInput))
|
||||||
|
) {
|
||||||
|
void ctx.prefetchQuery(pathAndInput as any, opts as any);
|
||||||
|
}
|
||||||
|
const ssrOpts = useSSRQueryOptionsIfNeeded(pathAndInput, opts);
|
||||||
|
// request option should take priority over global
|
||||||
|
const shouldAbortOnUnmount =
|
||||||
|
opts?.trpc?.abortOnUnmount ?? ctx?.abortOnUnmount ?? false;
|
||||||
|
|
||||||
|
const hook = __useQuery(
|
||||||
|
() => getArrayQueryKey(pathAndInput),
|
||||||
|
(queryFunctionContext) => {
|
||||||
|
const actualOpts = {
|
||||||
|
...ssrOpts,
|
||||||
|
trpc: {
|
||||||
|
...ssrOpts?.trpc,
|
||||||
|
...(shouldAbortOnUnmount
|
||||||
|
? { signal: queryFunctionContext.signal }
|
||||||
|
: {}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return (ctx.client as any).query(
|
||||||
|
...getClientArgs(pathAndInput, actualOpts)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{ context: SolidQueryContext, ...ssrOpts } as any
|
||||||
|
) as UseTRPCQueryResult<TData, TError>;
|
||||||
|
hook.trpc = useHookResult({
|
||||||
|
path: pathAndInput[0],
|
||||||
|
});
|
||||||
|
|
||||||
|
return hook;
|
||||||
|
}
|
||||||
|
|
||||||
|
function useMutation<
|
||||||
|
TPath extends keyof TMutationValues & string,
|
||||||
|
TContext = unknown
|
||||||
|
>(
|
||||||
|
path: TPath | [TPath],
|
||||||
|
opts?: UseTRPCMutationOptions<
|
||||||
|
TMutationValues[TPath]["input"],
|
||||||
|
TError,
|
||||||
|
TMutationValues[TPath]["output"],
|
||||||
|
TContext
|
||||||
|
>
|
||||||
|
): UseTRPCMutationResult<
|
||||||
|
TMutationValues[TPath]["output"],
|
||||||
|
TError,
|
||||||
|
TMutationValues[TPath]["input"],
|
||||||
|
TContext
|
||||||
|
> {
|
||||||
|
const ctx = useContext();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
const hook = __useMutation(
|
||||||
|
(input) => {
|
||||||
|
const actualPath = Array.isArray(path) ? path[0] : path;
|
||||||
|
|
||||||
|
return (ctx.client.mutation as any)(
|
||||||
|
...getClientArgs([actualPath, input], opts)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
context: SolidQueryContext,
|
||||||
|
...opts,
|
||||||
|
onSuccess(...args) {
|
||||||
|
const originalFn = () => opts?.onSuccess?.(...args);
|
||||||
|
return mutationSuccessOverride({ originalFn, queryClient });
|
||||||
|
},
|
||||||
|
}
|
||||||
|
) as UseTRPCMutationResult<
|
||||||
|
TMutationValues[TPath]["output"],
|
||||||
|
TError,
|
||||||
|
TMutationValues[TPath]["input"],
|
||||||
|
TContext
|
||||||
|
>;
|
||||||
|
|
||||||
|
hook.trpc = useHookResult({
|
||||||
|
path: Array.isArray(path) ? path[0] : path,
|
||||||
|
});
|
||||||
|
|
||||||
|
return hook;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
/**
|
||||||
|
* ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️
|
||||||
|
* **Experimental.** API might change without major version bump
|
||||||
|
* ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠
|
||||||
|
*/
|
||||||
|
function useSubscription<
|
||||||
|
TPath extends keyof TSubscriptions & string,
|
||||||
|
TOutput extends inferSubscriptionOutput<TRouter, TPath>
|
||||||
|
>(
|
||||||
|
pathAndInput: [
|
||||||
|
path: TPath,
|
||||||
|
...args: inferHandlerInput<TSubscriptions[TPath]>
|
||||||
|
],
|
||||||
|
opts: UseTRPCSubscriptionOptions<
|
||||||
|
inferObservableValue<inferProcedureOutput<TSubscriptions[TPath]>>,
|
||||||
|
inferProcedureClientError<TSubscriptions[TPath]>
|
||||||
|
>
|
||||||
|
) {
|
||||||
|
const enabled = opts?.enabled ?? true;
|
||||||
|
const ctx = useContext();
|
||||||
|
|
||||||
|
return createEffect(() => {
|
||||||
|
if (!enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// noop
|
||||||
|
(() => {
|
||||||
|
return hashQueryKey(pathAndInput);
|
||||||
|
})();
|
||||||
|
const [path, input] = pathAndInput;
|
||||||
|
let isStopped = false;
|
||||||
|
const subscription = ctx.client.subscription<
|
||||||
|
TRouter["_def"]["subscriptions"],
|
||||||
|
TPath,
|
||||||
|
TOutput,
|
||||||
|
inferProcedureInput<TRouter["_def"]["subscriptions"][TPath]>
|
||||||
|
>(path, (input ?? undefined) as any, {
|
||||||
|
onStarted: () => {
|
||||||
|
if (!isStopped) {
|
||||||
|
opts.onStarted?.();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onData: (data) => {
|
||||||
|
if (!isStopped) {
|
||||||
|
opts.onData(data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: (err) => {
|
||||||
|
if (!isStopped) {
|
||||||
|
opts.onError?.(err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
onCleanup(() => {
|
||||||
|
isStopped = true;
|
||||||
|
subscription.unsubscribe();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function useInfiniteQuery<TPath extends TInfiniteQueryNames & string>(
|
||||||
|
pathAndInput: [
|
||||||
|
path: TPath,
|
||||||
|
input: Omit<TQueryValues[TPath]["input"], "cursor">
|
||||||
|
],
|
||||||
|
opts?: UseTRPCInfiniteQueryOptions<
|
||||||
|
TPath,
|
||||||
|
Omit<TQueryValues[TPath]["input"], "cursor">,
|
||||||
|
TQueryValues[TPath]["output"],
|
||||||
|
TError
|
||||||
|
>
|
||||||
|
): UseTRPCInfiniteQueryResult<TQueryValues[TPath]["output"], TError> {
|
||||||
|
const [path, input] = pathAndInput;
|
||||||
|
const ctx = useContext();
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof window === "undefined" &&
|
||||||
|
ctx.ssrState() === "prepass" &&
|
||||||
|
opts?.trpc?.ssr !== false &&
|
||||||
|
opts?.enabled !== false &&
|
||||||
|
!ctx.queryClient.getQueryCache().find(getArrayQueryKey(pathAndInput))
|
||||||
|
) {
|
||||||
|
void ctx.prefetchInfiniteQuery(pathAndInput as any, opts as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ssrOpts = useSSRQueryOptionsIfNeeded(pathAndInput, opts);
|
||||||
|
|
||||||
|
// request option should take priority over global
|
||||||
|
const shouldAbortOnUnmount =
|
||||||
|
opts?.trpc?.abortOnUnmount ?? ctx?.abortOnUnmount ?? false;
|
||||||
|
|
||||||
|
const hook = __useInfiniteQuery(
|
||||||
|
() => getArrayQueryKey(pathAndInput),
|
||||||
|
(queryFunctionContext) => {
|
||||||
|
const actualOpts = {
|
||||||
|
...ssrOpts,
|
||||||
|
trpc: {
|
||||||
|
...ssrOpts?.trpc,
|
||||||
|
...(shouldAbortOnUnmount
|
||||||
|
? { signal: queryFunctionContext.signal }
|
||||||
|
: {}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const actualInput = {
|
||||||
|
...((input as any) ?? {}),
|
||||||
|
cursor: queryFunctionContext.pageParam,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (ctx.client as any).query(
|
||||||
|
...getClientArgs([path, actualInput], actualOpts)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{ context: SolidQueryContext, ...ssrOpts } as any
|
||||||
|
) as UseTRPCInfiniteQueryResult<TQueryValues[TPath]["output"], TError>;
|
||||||
|
|
||||||
|
hook.trpc = useHookResult({
|
||||||
|
path,
|
||||||
|
});
|
||||||
|
return hook;
|
||||||
|
}
|
||||||
|
const useDehydratedState: UseDehydratedState<TRouter> = (
|
||||||
|
client,
|
||||||
|
trpcState
|
||||||
|
) => {
|
||||||
|
const transformed: Accessor<DehydratedState | undefined> = createMemo(
|
||||||
|
() => {
|
||||||
|
if (!trpcState) {
|
||||||
|
return trpcState;
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.runtime.transformer.deserialize(trpcState);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return transformed;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
Provider: TRPCProvider,
|
||||||
|
createClient,
|
||||||
|
useContext,
|
||||||
|
useQuery,
|
||||||
|
useMutation,
|
||||||
|
useSubscription,
|
||||||
|
useDehydratedState,
|
||||||
|
useInfiniteQuery,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hack to infer the type of `createReactQueryHooks`
|
||||||
|
* @link https://stackoverflow.com/a/59072991
|
||||||
|
*/
|
||||||
|
class GnClass<TRouter extends AnyRouter, TSSRContext = unknown> {
|
||||||
|
fn() {
|
||||||
|
return createHooksInternal<TRouter, TSSRContext>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type returnTypeInferer<TType> = TType extends (
|
||||||
|
a: Record<string, string>
|
||||||
|
) => infer U
|
||||||
|
? U
|
||||||
|
: never;
|
||||||
|
type fooType<TRouter extends AnyRouter, TSSRContext = unknown> = GnClass<
|
||||||
|
TRouter,
|
||||||
|
TSSRContext
|
||||||
|
>["fn"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Infer the type of a `createReactQueryHooks` function
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export type CreateReactQueryHooks<
|
||||||
|
TRouter extends AnyRouter,
|
||||||
|
TSSRContext = unknown
|
||||||
|
> = returnTypeInferer<fooType<TRouter, TSSRContext>>;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
export * from "./proxy/decorationProxy";
|
||||||
|
export * from "./proxy/utilsProxy";
|
||||||
|
export type {
|
||||||
|
DecoratedProcedureRecord,
|
||||||
|
DecorateProcedure,
|
||||||
|
} from "../createTRPCSolid";
|
||||||
|
export * from "./hooks/createHooksInternal";
|
||||||
|
export * from "./queryClient";
|
||||||
|
export * from "./types";
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { AnyRouter } from "@trpc/server";
|
||||||
|
import { createRecursiveProxy } from "@trpc/server/shared";
|
||||||
|
import { getQueryKey } from "../../internals/getQueryKey";
|
||||||
|
import { CreateReactQueryHooks } from "../hooks/createHooksInternal";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create proxy for decorating procedures
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export function createReactProxyDecoration<
|
||||||
|
TRouter extends AnyRouter,
|
||||||
|
TSSRContext = unknown
|
||||||
|
>(name: string, hooks: CreateReactQueryHooks<TRouter, TSSRContext>) {
|
||||||
|
return createRecursiveProxy((opts) => {
|
||||||
|
const args = opts.args;
|
||||||
|
|
||||||
|
const pathCopy = [name, ...opts.path];
|
||||||
|
|
||||||
|
// The last arg is for instance `.useMutation` or `.useQuery()`
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
const lastArg = pathCopy.pop()!;
|
||||||
|
|
||||||
|
// The `path` ends up being something like `post.byId`
|
||||||
|
const path = pathCopy.join(".");
|
||||||
|
if (lastArg === "useMutation") {
|
||||||
|
return (hooks as any)[lastArg](path, ...args);
|
||||||
|
}
|
||||||
|
const [input, ...rest] = args;
|
||||||
|
|
||||||
|
const queryKey = getQueryKey(path, input);
|
||||||
|
return (hooks as any)[lastArg](queryKey, ...rest);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
import {
|
||||||
|
CancelOptions,
|
||||||
|
InfiniteData,
|
||||||
|
InvalidateOptions,
|
||||||
|
InvalidateQueryFilters,
|
||||||
|
RefetchOptions,
|
||||||
|
RefetchQueryFilters,
|
||||||
|
SetDataOptions,
|
||||||
|
Updater,
|
||||||
|
} from "@tanstack/solid-query";
|
||||||
|
import { TRPCClientError } from "@trpc/client";
|
||||||
|
import {
|
||||||
|
AnyQueryProcedure,
|
||||||
|
AnyRouter,
|
||||||
|
Filter,
|
||||||
|
ProcedureOptions,
|
||||||
|
inferProcedureInput,
|
||||||
|
inferProcedureOutput,
|
||||||
|
} from "@trpc/server";
|
||||||
|
import { createFlatProxy, createRecursiveProxy } from "@trpc/server/shared";
|
||||||
|
import {
|
||||||
|
ProxyTRPCContextProps,
|
||||||
|
TRPCContextState,
|
||||||
|
TRPCFetchInfiniteQueryOptions,
|
||||||
|
TRPCFetchQueryOptions,
|
||||||
|
contextProps,
|
||||||
|
} from "../../internals/context";
|
||||||
|
import { getQueryKey } from "../../internals/getQueryKey";
|
||||||
|
|
||||||
|
type DecorateProcedure<
|
||||||
|
TRouter extends AnyRouter,
|
||||||
|
TProcedure extends AnyQueryProcedure
|
||||||
|
> = {
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/guides/prefetching
|
||||||
|
*/
|
||||||
|
fetch(
|
||||||
|
input: inferProcedureInput<TProcedure>,
|
||||||
|
opts?: TRPCFetchQueryOptions<
|
||||||
|
inferProcedureInput<TProcedure>,
|
||||||
|
TRPCClientError<TRouter>,
|
||||||
|
inferProcedureOutput<TProcedure>
|
||||||
|
>
|
||||||
|
): Promise<inferProcedureOutput<TProcedure>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/guides/prefetching
|
||||||
|
*/
|
||||||
|
fetchInfinite(
|
||||||
|
input: inferProcedureInput<TProcedure>,
|
||||||
|
opts?: TRPCFetchInfiniteQueryOptions<
|
||||||
|
inferProcedureInput<TProcedure>,
|
||||||
|
TRPCClientError<TRouter>,
|
||||||
|
inferProcedureOutput<TProcedure>
|
||||||
|
>
|
||||||
|
): Promise<InfiniteData<inferProcedureOutput<TProcedure>>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/guides/prefetching
|
||||||
|
*/
|
||||||
|
prefetch(
|
||||||
|
input: inferProcedureInput<TProcedure>,
|
||||||
|
opts?: TRPCFetchQueryOptions<
|
||||||
|
inferProcedureInput<TProcedure>,
|
||||||
|
TRPCClientError<TRouter>,
|
||||||
|
inferProcedureOutput<TProcedure>
|
||||||
|
>
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/guides/prefetching
|
||||||
|
*/
|
||||||
|
prefetchInfinite(
|
||||||
|
input: inferProcedureInput<TProcedure>,
|
||||||
|
procedureOpts?: ProcedureOptions,
|
||||||
|
opts?: TRPCFetchInfiniteQueryOptions<
|
||||||
|
inferProcedureInput<TProcedure>,
|
||||||
|
TRPCClientError<TRouter>,
|
||||||
|
inferProcedureOutput<TProcedure>
|
||||||
|
>
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/guides/query-invalidation
|
||||||
|
*/
|
||||||
|
invalidate(
|
||||||
|
input?: inferProcedureInput<TProcedure>,
|
||||||
|
filters?: InvalidateQueryFilters,
|
||||||
|
options?: InvalidateOptions
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/reference/QueryClient#queryclientrefetchqueries
|
||||||
|
*/
|
||||||
|
refetch(
|
||||||
|
input?: inferProcedureInput<TProcedure>,
|
||||||
|
filters?: RefetchQueryFilters,
|
||||||
|
options?: RefetchOptions
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/guides/query-cancellation
|
||||||
|
*/
|
||||||
|
cancel(
|
||||||
|
input?: inferProcedureInput<TProcedure>,
|
||||||
|
options?: CancelOptions
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/reference/QueryClient#queryclientsetquerydata
|
||||||
|
*/
|
||||||
|
setData(
|
||||||
|
updater: Updater<
|
||||||
|
inferProcedureOutput<TProcedure> | undefined,
|
||||||
|
inferProcedureOutput<TProcedure> | undefined
|
||||||
|
>,
|
||||||
|
input?: inferProcedureInput<TProcedure>,
|
||||||
|
options?: SetDataOptions
|
||||||
|
): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/reference/QueryClient#queryclientgetquerydata
|
||||||
|
*/
|
||||||
|
setInfiniteData(
|
||||||
|
updater: Updater<
|
||||||
|
InfiniteData<inferProcedureOutput<TProcedure>> | undefined,
|
||||||
|
InfiniteData<inferProcedureOutput<TProcedure>> | undefined
|
||||||
|
>,
|
||||||
|
input?: inferProcedureInput<TProcedure>,
|
||||||
|
options?: SetDataOptions
|
||||||
|
): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/reference/QueryClient#queryclientgetquerydata
|
||||||
|
*/
|
||||||
|
getData(
|
||||||
|
input?: inferProcedureInput<TProcedure>
|
||||||
|
): inferProcedureOutput<TProcedure> | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/reference/QueryClient#queryclientgetquerydata
|
||||||
|
*/
|
||||||
|
getInfiniteData(
|
||||||
|
input?: inferProcedureInput<TProcedure>
|
||||||
|
): InfiniteData<inferProcedureOutput<TProcedure>> | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type that will traverse all procedures and sub routers of a given router to create a union of
|
||||||
|
* their possible input types
|
||||||
|
*/
|
||||||
|
type InferAllRouterQueryInputTypes<TRouter extends AnyRouter> = {
|
||||||
|
[TKey in keyof Filter<
|
||||||
|
TRouter["_def"]["record"],
|
||||||
|
AnyRouter | AnyQueryProcedure
|
||||||
|
>]: TRouter["_def"]["record"][TKey] extends AnyQueryProcedure
|
||||||
|
? inferProcedureInput<TRouter["_def"]["record"][TKey]>
|
||||||
|
: InferAllRouterQueryInputTypes<TRouter["_def"]["record"][TKey]>; // Recurse as we have a sub router!
|
||||||
|
}[keyof Filter<TRouter["_def"]["record"], AnyRouter | AnyQueryProcedure>]; // This flattens results into a big union
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this is the type that is used to add in procedures that can be used on
|
||||||
|
* an entire router
|
||||||
|
*/
|
||||||
|
type DecorateRouterProcedure<TRouter extends AnyRouter> = {
|
||||||
|
/**
|
||||||
|
* @link https://react-query.tanstack.com/guides/query-invalidation
|
||||||
|
*/
|
||||||
|
invalidate(
|
||||||
|
input?: Partial<InferAllRouterQueryInputTypes<TRouter>>,
|
||||||
|
filters?: InvalidateQueryFilters,
|
||||||
|
options?: InvalidateOptions
|
||||||
|
): Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export type DecoratedProcedureUtilsRecord<TRouter extends AnyRouter> = {
|
||||||
|
[TKey in keyof Filter<
|
||||||
|
TRouter["_def"]["record"],
|
||||||
|
AnyRouter | AnyQueryProcedure
|
||||||
|
>]: TRouter["_def"]["record"][TKey] extends AnyRouter
|
||||||
|
? DecoratedProcedureUtilsRecord<TRouter["_def"]["record"][TKey]> &
|
||||||
|
DecorateRouterProcedure<TRouter["_def"]["record"][TKey]>
|
||||||
|
: // utils only apply to queries
|
||||||
|
DecorateProcedure<TRouter, TRouter["_def"]["record"][TKey]>;
|
||||||
|
} & DecorateRouterProcedure<TRouter>; // Add functions that should be available at utils root
|
||||||
|
|
||||||
|
type AnyDecoratedProcedure = DecorateProcedure<any, any>;
|
||||||
|
|
||||||
|
export type CreateReactUtilsProxy<
|
||||||
|
TRouter extends AnyRouter,
|
||||||
|
TSSRContext
|
||||||
|
> = DecoratedProcedureUtilsRecord<TRouter> &
|
||||||
|
ProxyTRPCContextProps<TRouter, TSSRContext>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export function createReactQueryUtilsProxy<
|
||||||
|
TRouter extends AnyRouter,
|
||||||
|
TSSRContext
|
||||||
|
>(context: TRPCContextState<AnyRouter, unknown>) {
|
||||||
|
type CreateReactUtilsProxyReturnType = CreateReactUtilsProxy<
|
||||||
|
TRouter,
|
||||||
|
TSSRContext
|
||||||
|
>;
|
||||||
|
|
||||||
|
return createFlatProxy<CreateReactUtilsProxyReturnType>((key) => {
|
||||||
|
const contextName = key as typeof contextProps[number];
|
||||||
|
if (contextProps.includes(contextName)) {
|
||||||
|
return context[contextName];
|
||||||
|
}
|
||||||
|
|
||||||
|
return createRecursiveProxy(({ path, args }) => {
|
||||||
|
const pathCopy = [key, ...path];
|
||||||
|
const utilName = pathCopy.pop() as keyof AnyDecoratedProcedure;
|
||||||
|
|
||||||
|
const fullPath = pathCopy.join(".");
|
||||||
|
|
||||||
|
const getOpts = (name: typeof utilName) => {
|
||||||
|
if (["setData", "setInfiniteData"].includes(name)) {
|
||||||
|
const [updater, input, ...rest] = args as Parameters<
|
||||||
|
AnyDecoratedProcedure[typeof utilName]
|
||||||
|
>;
|
||||||
|
const queryKey = getQueryKey(fullPath, input);
|
||||||
|
return {
|
||||||
|
queryKey,
|
||||||
|
updater,
|
||||||
|
rest,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const [input, ...rest] = args as Parameters<
|
||||||
|
AnyDecoratedProcedure[typeof utilName]
|
||||||
|
>;
|
||||||
|
const queryKey = getQueryKey(fullPath, input);
|
||||||
|
return {
|
||||||
|
queryKey,
|
||||||
|
rest,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const { queryKey, rest, updater } = getOpts(utilName);
|
||||||
|
|
||||||
|
const contextMap: Record<keyof AnyDecoratedProcedure, () => unknown> = {
|
||||||
|
fetch: () => context.fetchQuery(queryKey, ...rest),
|
||||||
|
fetchInfinite: () => context.fetchInfiniteQuery(queryKey, ...rest),
|
||||||
|
prefetch: () => context.prefetchQuery(queryKey, ...rest),
|
||||||
|
prefetchInfinite: () =>
|
||||||
|
context.prefetchInfiniteQuery(queryKey, ...rest),
|
||||||
|
invalidate: () => context.invalidateQueries(queryKey, ...rest),
|
||||||
|
refetch: () => context.refetchQueries(queryKey, ...rest),
|
||||||
|
cancel: () => context.cancelQuery(queryKey, ...rest),
|
||||||
|
setData: () => context.setQueryData(queryKey, updater, ...rest),
|
||||||
|
setInfiniteData: () =>
|
||||||
|
context.setInfiniteQueryData(queryKey, updater, ...rest),
|
||||||
|
getData: () => context.getQueryData(queryKey),
|
||||||
|
getInfiniteData: () => context.getInfiniteQueryData(queryKey),
|
||||||
|
};
|
||||||
|
|
||||||
|
return contextMap[utilName]();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { QueryClient, QueryClientConfig } from "@tanstack/solid-query";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export type CreateTRPCReactQueryClientConfig =
|
||||||
|
| {
|
||||||
|
queryClient?: QueryClient;
|
||||||
|
queryClientConfig?: never;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
queryClientConfig?: QueryClientConfig;
|
||||||
|
queryClient?: never;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export const getQueryClient = (config: CreateTRPCReactQueryClientConfig) =>
|
||||||
|
config.queryClient ?? new QueryClient(config.queryClientConfig);
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { QueryClient } from "@tanstack/solid-query";
|
||||||
|
import { AnyRouter, MaybePromise } from "@trpc/server";
|
||||||
|
import Solid from "solid-js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export interface UseMutationOverride {
|
||||||
|
onSuccess: (opts: {
|
||||||
|
/**
|
||||||
|
* Calls the original function that was defined in the query's `onSuccess` option
|
||||||
|
*/
|
||||||
|
originalFn: () => MaybePromise<unknown>;
|
||||||
|
queryClient: QueryClient;
|
||||||
|
}) => MaybePromise<unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export interface CreateTRPCSolidOptions<_TRouter extends AnyRouter> {
|
||||||
|
/**
|
||||||
|
* Override behaviors of the built-in hooks
|
||||||
|
*/
|
||||||
|
unstable_overrides?: {
|
||||||
|
useMutation?: Partial<UseMutationOverride>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override the default context provider
|
||||||
|
* @default undefined
|
||||||
|
*/
|
||||||
|
context?: Solid.Context<any>;
|
||||||
|
/**
|
||||||
|
* Override the default React Query context
|
||||||
|
* @default undefined
|
||||||
|
*/
|
||||||
|
solidQueryContext?: Solid.Context<QueryClient | undefined>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"declaration": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"target": "esnext",
|
||||||
|
"newLine": "LF",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"allowUnreachableCode": false,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"jsxImportSource": "solid-js",
|
||||||
|
"outDir": "./dist",
|
||||||
|
"module": "esnext"
|
||||||
|
},
|
||||||
|
"include": ["./src"],
|
||||||
|
"exclude": ["node_modules", "dist"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user