mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-10-30 00:27:43 +09:00
147 lines
4.1 KiB
TypeScript
147 lines
4.1 KiB
TypeScript
import type { AppRouter } from "~/services/trcp-router.server";
|
|
import { createTRPCProxyClient, httpBatchLink } from "@trpc/client";
|
|
import { getApiCompatibilityPayload } from "@webstudio-is/trpc-interface/api-compatibility";
|
|
|
|
import type {
|
|
AnyMutationProcedure,
|
|
AnyRouter,
|
|
inferRouterInputs,
|
|
inferRouterOutputs,
|
|
} from "@trpc/server";
|
|
import { createRecursiveProxy } from "@trpc/server/shared";
|
|
import { useMemo, useState } from "react";
|
|
import { fetch } from "~/shared/fetch.client";
|
|
|
|
export const createNativeClient = (
|
|
headers?: Record<string, string | undefined>
|
|
) =>
|
|
createTRPCProxyClient<AppRouter>({
|
|
links: [
|
|
httpBatchLink({
|
|
fetch,
|
|
headers: () => headers ?? {},
|
|
url: "/trpc",
|
|
}),
|
|
],
|
|
});
|
|
|
|
export const nativeClient = createNativeClient();
|
|
|
|
type Procedures<T> = T extends AnyRouter
|
|
? {
|
|
[Procedure in keyof T["_def"]["record"]]: T["_def"]["record"][Procedure] extends AnyMutationProcedure
|
|
? {
|
|
useMutation: () => {
|
|
send: (
|
|
input: inferRouterInputs<T>[Procedure],
|
|
onSuccess?: (data: inferRouterOutputs<T>[Procedure]) => void
|
|
) => void;
|
|
data?: inferRouterOutputs<T>[Procedure];
|
|
state: "idle" | "submitting";
|
|
error?: string | undefined;
|
|
};
|
|
}
|
|
: {
|
|
useQuery: () => {
|
|
load: (
|
|
input: inferRouterInputs<T>[Procedure],
|
|
onSuccess?: (data: inferRouterOutputs<T>[Procedure]) => void
|
|
) => void;
|
|
data?: inferRouterOutputs<T>[Procedure];
|
|
state: "idle" | "submitting";
|
|
error?: string | undefined;
|
|
};
|
|
};
|
|
}
|
|
: never;
|
|
|
|
type Client = Record<
|
|
string,
|
|
Record<
|
|
string,
|
|
{ query: (args: unknown) => unknown; mutate: (args: unknown) => unknown }
|
|
>
|
|
>;
|
|
|
|
export const trpcClient: {
|
|
[SubRoute in keyof AppRouter["_def"]["record"]]: Procedures<
|
|
AppRouter["_def"]["record"][SubRoute]
|
|
>;
|
|
} = createRecursiveProxy((options) => {
|
|
const path = [...options.path];
|
|
const hook = path.pop();
|
|
const [data, setData] = useState<unknown>(undefined);
|
|
const [state, setState] = useState<"idle" | "submitting">("idle");
|
|
const [error, setError] = useState<string | undefined>(undefined);
|
|
|
|
if (hook !== "useMutation" && hook !== "useQuery") {
|
|
throw new Error(`Invalid hook ${hook}`);
|
|
}
|
|
|
|
// const method = path.join(".");
|
|
if (path.length !== 2) {
|
|
throw new Error(`Invalid path ${path}`);
|
|
}
|
|
|
|
const [namespace, method] = path;
|
|
|
|
const submit = useMemo(() => {
|
|
let requestId = 0;
|
|
|
|
return async (input: never, onSuccess?: (data: unknown) => void) => {
|
|
requestId += 1;
|
|
const currentRequestId = requestId;
|
|
try {
|
|
setState("submitting");
|
|
|
|
// if (process.env.NODE_ENV !== "production") {
|
|
// await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
// }
|
|
|
|
const result = await (nativeClient as unknown as Client)[namespace][
|
|
method
|
|
][hook === "useMutation" ? "mutate" : "query"](input);
|
|
|
|
// Newer request has been made, ignore this one
|
|
// In the future to support optimistic updates we can call onComplete with the requestId order
|
|
if (currentRequestId !== requestId) {
|
|
return;
|
|
}
|
|
|
|
setData(result);
|
|
setError(undefined);
|
|
onSuccess?.(result);
|
|
} catch (error) {
|
|
if (currentRequestId !== requestId) {
|
|
return;
|
|
}
|
|
|
|
console.error("TRPC ERROR", error);
|
|
|
|
const payload = getApiCompatibilityPayload(error);
|
|
if (payload?.action.type === "reloadBrowser") {
|
|
setError(payload.message);
|
|
return;
|
|
}
|
|
|
|
if (error instanceof Error) {
|
|
setError(error.message);
|
|
return;
|
|
}
|
|
setError("Unknown error");
|
|
} finally {
|
|
if (currentRequestId === requestId) {
|
|
setState("idle");
|
|
}
|
|
}
|
|
};
|
|
}, [hook, namespace, method]);
|
|
|
|
return {
|
|
[hook === "useMutation" ? "send" : "load"]: submit,
|
|
data: data,
|
|
state,
|
|
error,
|
|
};
|
|
}) as never;
|