feat: add trpc websocket (#205)

This commit is contained in:
Manuel
2024-03-14 18:43:47 +01:00
committed by GitHub
parent 9ae99ad06c
commit 4f375cbe6d
14 changed files with 268 additions and 32 deletions

View File

@@ -5,11 +5,21 @@ import { useState } from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { ReactQueryStreamedHydration } from "@tanstack/react-query-next-experimental";
import { loggerLink, unstable_httpBatchStreamLink } from "@trpc/client";
import {
createWSClient,
loggerLink,
unstable_httpBatchStreamLink,
wsLink,
} from "@trpc/client";
import superjson from "superjson";
import type { AppRouter } from "@homarr/api";
import { clientApi } from "@homarr/api/client";
const wsClient = createWSClient({
url: "ws://localhost:3001",
});
export function TRPCReactProvider(props: PropsWithChildren) {
const [queryClient] = useState(
() =>
@@ -22,26 +32,39 @@ export function TRPCReactProvider(props: PropsWithChildren) {
}),
);
const [trpcClient] = useState(() =>
clientApi.createClient({
const [trpcClient] = useState(() => {
return clientApi.createClient({
links: [
loggerLink({
enabled: (opts) =>
process.env.NODE_ENV === "development" ||
(opts.direction === "down" && opts.result instanceof Error),
}),
unstable_httpBatchStreamLink({
transformer: superjson,
url: getBaseUrl() + "/api/trpc",
headers() {
const headers = new Headers();
headers.set("x-trpc-source", "nextjs-react");
return headers;
},
}),
(args) => {
return ({ op, next }) => {
console.log("op", op.type, op.input, op.path, op.id);
if (op.type === "subscription") {
const link = wsLink<AppRouter>({
client: wsClient,
transformer: superjson,
});
return link(args)({ op, next });
}
return unstable_httpBatchStreamLink({
transformer: superjson,
url: `${getBaseUrl()}/api/trpc`,
headers() {
const headers = new Headers();
headers.set("x-trpc-source", "nextjs-react");
return headers;
},
})(args)({ op, next });
};
},
],
}),
);
});
});
return (
<clientApi.Provider client={trpcClient} queryClient={queryClient}>

View File

@@ -1,6 +1,8 @@
import { getScopedI18n } from "@homarr/translation/server";
import { Title } from "@homarr/ui";
import { Test } from "./test";
export async function generateMetadata() {
const t = await getScopedI18n("management");
const metaTitle = `${t("metaTitle")} • Homarr`;
@@ -24,6 +26,7 @@ export default async function ManagementPage() {
return (
<>
<Title>{t(timeOfDay, { username: "admin" })}</Title>
<Test />
</>
);
}

View File

@@ -0,0 +1,23 @@
"use client";
import { useState } from "react";
import { clientApi } from "@homarr/api/client";
import { Stack, Text } from "@homarr/ui";
export const Test = () => {
const [value, setValue] = useState<number>(0);
clientApi.user.test.useSubscription(undefined, {
onData(data) {
setValue(data);
},
onError(err) {
alert(err);
},
});
return (
<Stack>
<Text>This will change after one second: {value}</Text>
</Stack>
);
};

View File

@@ -2,6 +2,7 @@ import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
import { appRouter, createTRPCContext } from "@homarr/api";
import { auth } from "@homarr/auth";
import { logger } from "@homarr/log";
/**
* Configure basic CORS headers
@@ -29,8 +30,10 @@ const handler = auth(async (req) => {
req,
createContext: () =>
createTRPCContext({ session: req.auth, headers: req.headers }),
onError({ error, path }) {
console.error(`>>> tRPC Error on '${path}'`, error);
onError({ error, path, type }) {
logger.error(
`tRPC Error with ${type} on '${path}': (${error.code}) - ${error.message}`,
);
},
});