diff --git a/apps/web/app/(use-page-wrapper)/(main-nav)/event-types/page.tsx b/apps/web/app/(use-page-wrapper)/(main-nav)/event-types/page.tsx
index b54b052147..8a11ed2452 100644
--- a/apps/web/app/(use-page-wrapper)/(main-nav)/event-types/page.tsx
+++ b/apps/web/app/(use-page-wrapper)/(main-nav)/event-types/page.tsx
@@ -8,8 +8,6 @@ import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
-import { ssrInit } from "@server/lib/ssr";
-
import EventTypes, { EventTypesCTA } from "~/event-types/views/event-types-listing-view";
export const generateMetadata = async () =>
@@ -26,7 +24,6 @@ const Page = async ({ params, searchParams }: PageProps) => {
redirect("/auth/login");
}
- await ssrInit(context);
const t = await getTranslate();
return (
diff --git a/apps/web/app/(use-page-wrapper)/auth/logout/page.tsx b/apps/web/app/(use-page-wrapper)/auth/logout/page.tsx
index f95c2e1957..f949498dfb 100644
--- a/apps/web/app/(use-page-wrapper)/auth/logout/page.tsx
+++ b/apps/web/app/(use-page-wrapper)/auth/logout/page.tsx
@@ -4,8 +4,6 @@ import { cookies, headers } from "next/headers";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
-import { ssrInit } from "@server/lib/ssr";
-
import Logout from "~/auth/logout-view";
export const generateMetadata = async () => {
@@ -19,7 +17,6 @@ const Page = async ({ params, searchParams }: PageProps) => {
// cookie will be cleared in `/apps/web/middleware.ts`
const h = await headers();
const context = buildLegacyCtx(h, await cookies(), await params, await searchParams);
- await ssrInit(context);
return ;
};
diff --git a/apps/web/app/_trpc/HydrateClient.tsx b/apps/web/app/_trpc/HydrateClient.tsx
deleted file mode 100644
index 16cbeb6b9a..0000000000
--- a/apps/web/app/_trpc/HydrateClient.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-"use client";
-
-import { createHydrateClient } from "app/_trpc/createHydrateClient";
-import superjson from "superjson";
-
-export const HydrateClient = createHydrateClient({
- transformer: superjson,
-});
diff --git a/apps/web/app/_trpc/createHydrateClient.tsx b/apps/web/app/_trpc/createHydrateClient.tsx
deleted file mode 100644
index 6751a02162..0000000000
--- a/apps/web/app/_trpc/createHydrateClient.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-"use client";
-
-import { type DehydratedState, HydrationBoundary } from "@tanstack/react-query";
-import { useMemo } from "react";
-
-type DataTransformer = {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- serialize: (data: any) => any;
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- deserialize: (data: any) => any;
-};
-
-export function createHydrateClient(opts: { transformer: DataTransformer }) {
- return function HydrateClient(props: { children: React.ReactNode; state: DehydratedState }) {
- const { state, children } = props;
-
- const transformedState: DehydratedState = useMemo(() => {
- if (opts.transformer) {
- return opts.transformer.deserialize(state);
- }
- return state;
- }, [state]);
-
- return {children};
- };
-}
diff --git a/apps/web/app/_trpc/query-client.ts b/apps/web/app/_trpc/query-client.ts
new file mode 100644
index 0000000000..369953c8f5
--- /dev/null
+++ b/apps/web/app/_trpc/query-client.ts
@@ -0,0 +1,37 @@
+"use client";
+
+import { QueryClient } from "@tanstack/react-query";
+
+import { TRPCClientError } from "@trpc/client";
+
+const MAX_QUERY_RETRIES = 3;
+
+const isTRPCClientError = (cause: unknown): cause is TRPCClientError => {
+ return cause instanceof TRPCClientError;
+};
+
+export const queryClient = new QueryClient({
+ // these configurations are copied from "packages/trpc/react/trpc.ts"
+ defaultOptions: {
+ queries: {
+ /**
+ * 1s should be enough to just keep identical query waterfalls low
+ * @example if one page components uses a query that is also used further down the tree
+ */
+ staleTime: 1000,
+ /**
+ * Retry `useQuery()` calls depending on this function
+ */
+ retry(failureCount, error) {
+ if (isTRPCClientError(error) && error.data) {
+ const { code } = error.data;
+ if (code === "BAD_REQUEST" || code === "FORBIDDEN" || code === "UNAUTHORIZED") {
+ // if input data is wrong or you're not authorized there's no point retrying a query
+ return false;
+ }
+ }
+ return failureCount < MAX_QUERY_RETRIES;
+ },
+ },
+ },
+});
diff --git a/apps/web/app/_trpc/serverClient.ts b/apps/web/app/_trpc/serverClient.ts
deleted file mode 100644
index e4b7d577f0..0000000000
--- a/apps/web/app/_trpc/serverClient.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import type { TRPCContext } from "@calcom/trpc/server/createContext";
-import { appRouter } from "@calcom/trpc/server/routers/_app";
-
-export const getServerCaller = (ctx: TRPCContext) => appRouter.createCaller(ctx);
diff --git a/apps/web/app/_trpc/trpc-client.ts b/apps/web/app/_trpc/trpc-client.ts
new file mode 100644
index 0000000000..3519c7b909
--- /dev/null
+++ b/apps/web/app/_trpc/trpc-client.ts
@@ -0,0 +1,80 @@
+"use client";
+
+import superjson from "superjson";
+
+import { ENDPOINTS } from "@calcom/trpc/react/shared";
+
+import { httpBatchLink, httpLink, loggerLink, splitLink } from "@trpc/client";
+
+import { trpc } from "./trpc";
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+const resolveEndpoint = (links: any) => {
+ // TODO: Update our trpc routes so they are more clear.
+ // This function parses paths like the following and maps them
+ // to the correct API endpoints.
+ // - viewer.me - 2 segment paths like this are for logged in requests
+ // - viewer.public.i18n - 3 segments paths can be public or authed
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ return (ctx: any) => {
+ const parts = ctx.op.path.split(".");
+ let endpoint;
+ let path = "";
+ if (parts.length == 2) {
+ endpoint = parts[0] as keyof typeof links;
+ path = parts[1];
+ } else {
+ endpoint = parts[1] as keyof typeof links;
+ path = parts.splice(2, parts.length - 2).join(".");
+ }
+ return links[endpoint]({ ...ctx, op: { ...ctx.op, path } });
+ };
+};
+
+const url =
+ typeof window !== "undefined"
+ ? "/api/trpc"
+ : process.env.VERCEL_URL
+ ? `https://${process.env.VERCEL_URL}/api/trpc`
+ : `${process.env.NEXT_PUBLIC_WEBAPP_URL}/api/trpc`;
+
+export const trpcClient = trpc.createClient({
+ links: [
+ // adds pretty logs to your console in development and logs errors in production
+ loggerLink({
+ enabled: (opts) =>
+ (typeof process.env.NEXT_PUBLIC_LOGGER_LEVEL === "number" &&
+ process.env.NEXT_PUBLIC_LOGGER_LEVEL >= 0) ||
+ (opts.direction === "down" && opts.result instanceof Error),
+ }),
+ splitLink({
+ // check for context property `skipBatch`
+ condition: (op) => !!op.context.skipBatch,
+ // when condition is true, use normal request
+ true: (runtime) => {
+ const links = Object.fromEntries(
+ ENDPOINTS.map((endpoint) => [
+ endpoint,
+ httpLink({
+ url: `${url}/${endpoint}`,
+ })(runtime),
+ ])
+ );
+ return resolveEndpoint(links);
+ },
+ // when condition is false, use batch request
+ false: (runtime) => {
+ const links = Object.fromEntries(
+ ENDPOINTS.map((endpoint) => [
+ endpoint,
+ httpBatchLink({
+ url: `${url}/${endpoint}`,
+ })(runtime),
+ ])
+ );
+ return resolveEndpoint(links);
+ },
+ }),
+ ],
+ transformer: superjson,
+});
diff --git a/apps/web/app/_trpc/trpc-provider.tsx b/apps/web/app/_trpc/trpc-provider.tsx
index 9c0cbcd048..1c4af7b072 100644
--- a/apps/web/app/_trpc/trpc-provider.tsx
+++ b/apps/web/app/_trpc/trpc-provider.tsx
@@ -1,137 +1,19 @@
"use client";
-import { type DehydratedState, QueryClient, QueryClientProvider } from "@tanstack/react-query";
-import { HydrateClient } from "app/_trpc/HydrateClient";
-import { trpc } from "app/_trpc/client";
-import { useState } from "react";
-import superjson from "superjson";
+import { QueryClientProvider } from "@tanstack/react-query";
-import { ENDPOINTS } from "@calcom/trpc/react/shared";
-import type { AppRouter } from "@calcom/trpc/types/server/routers/_app";
-
-import { httpBatchLink, httpLink, loggerLink, splitLink, TRPCClientError } from "@trpc/client";
-
-export type Endpoint = (typeof ENDPOINTS)[number];
-
-const MAX_QUERY_RETRIES = 3;
-
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-const resolveEndpoint = (links: any) => {
- // TODO: Update our trpc routes so they are more clear.
- // This function parses paths like the following and maps them
- // to the correct API endpoints.
- // - viewer.me - 2 segment paths like this are for logged in requests
- // - viewer.public.i18n - 3 segments paths can be public or authed
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- return (ctx: any) => {
- const parts = ctx.op.path.split(".");
- let endpoint;
- let path = "";
- if (parts.length == 2) {
- endpoint = parts[0] as keyof typeof links;
- path = parts[1];
- } else {
- endpoint = parts[1] as keyof typeof links;
- path = parts.splice(2, parts.length - 2).join(".");
- }
- return links[endpoint]({ ...ctx, op: { ...ctx.op, path } });
- };
-};
-
-const isTRPCClientError = (cause: unknown): cause is TRPCClientError => {
- return cause instanceof TRPCClientError;
-};
+import { queryClient } from "./query-client";
+import { trpc } from "./trpc";
+import { trpcClient } from "./trpc-client";
type Props = {
children: React.ReactNode;
- dehydratedState: DehydratedState;
};
-export const TrpcProvider = ({ children, dehydratedState }: Props) => {
- const [queryClient] = useState(
- () =>
- new QueryClient({
- // these configurations are copied from "packages/trpc/react/trpc.ts"
- defaultOptions: {
- queries: {
- /**
- * 1s should be enough to just keep identical query waterfalls low
- * @example if one page components uses a query that is also used further down the tree
- */
- staleTime: 1000,
- /**
- * Retry `useQuery()` calls depending on this function
- */
- retry(failureCount, error) {
- if (isTRPCClientError(error) && error.data) {
- const { code } = error.data;
- if (code === "BAD_REQUEST" || code === "FORBIDDEN" || code === "UNAUTHORIZED") {
- // if input data is wrong or you're not authorized there's no point retrying a query
- return false;
- }
- }
- return failureCount < MAX_QUERY_RETRIES;
- },
- },
- },
- })
- );
-
- const url =
- typeof window !== "undefined"
- ? "/api/trpc"
- : process.env.VERCEL_URL
- ? `https://${process.env.VERCEL_URL}/api/trpc`
- : `${process.env.NEXT_PUBLIC_WEBAPP_URL}/api/trpc`;
-
- const [trpcClient] = useState(() =>
- trpc.createClient({
- links: [
- // adds pretty logs to your console in development and logs errors in production
- loggerLink({
- enabled: (opts) =>
- (typeof process.env.NEXT_PUBLIC_LOGGER_LEVEL === "number" &&
- process.env.NEXT_PUBLIC_LOGGER_LEVEL >= 0) ||
- (opts.direction === "down" && opts.result instanceof Error),
- }),
- splitLink({
- // check for context property `skipBatch`
- condition: (op) => !!op.context.skipBatch,
- // when condition is true, use normal request
- true: (runtime) => {
- const links = Object.fromEntries(
- ENDPOINTS.map((endpoint) => [
- endpoint,
- httpLink({
- url: `${url}/${endpoint}`,
- })(runtime),
- ])
- );
- return resolveEndpoint(links);
- },
- // when condition is false, use batch request
- false: (runtime) => {
- const links = Object.fromEntries(
- ENDPOINTS.map((endpoint) => [
- endpoint,
- httpBatchLink({
- url: `${url}/${endpoint}`,
- })(runtime),
- ])
- );
- return resolveEndpoint(links);
- },
- }),
- ],
- transformer: superjson,
- })
- );
-
+export const TrpcProvider = ({ children }: Props) => {
return (
-
- {children}
-
+ {children}
);
};
diff --git a/apps/web/app/_trpc/client.ts b/apps/web/app/_trpc/trpc.ts
similarity index 92%
rename from apps/web/app/_trpc/client.ts
rename to apps/web/app/_trpc/trpc.ts
index 978570ed05..c7a27cbef7 100644
--- a/apps/web/app/_trpc/client.ts
+++ b/apps/web/app/_trpc/trpc.ts
@@ -1,3 +1,5 @@
+"use client";
+
import type { AppRouter } from "@calcom/trpc/types/server/routers/_app";
import { createTRPCReact } from "@trpc/react-query";
diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx
index 6707cc6e69..965588fb92 100644
--- a/apps/web/app/layout.tsx
+++ b/apps/web/app/layout.tsx
@@ -8,10 +8,6 @@ import { getLocale } from "@calcom/features/auth/lib/getLocale";
import { IconSprites } from "@calcom/ui/components/icon";
import { NotificationSoundHandler } from "@calcom/web/components/notification-sound-handler";
-import { buildLegacyCtx } from "@lib/buildLegacyCtx";
-
-import { ssrInit } from "@server/lib/ssr";
-
import "../styles/globals.css";
import { SpeculationRules } from "./SpeculationRules";
import { Providers } from "./providers";
@@ -112,7 +108,6 @@ export default async function RootLayout({ children }: { children: React.ReactNo
? getFallbackProps()
: await getInitialProps(fullUrl);
- const ssr = await ssrInit(buildLegacyCtx(h, await cookies(), {}, {}));
return (
- {children}
+ {children}
{!isEmbed && }
diff --git a/apps/web/app/providers.tsx b/apps/web/app/providers.tsx
index 2b3a5caad2..aaca3b3dc6 100644
--- a/apps/web/app/providers.tsx
+++ b/apps/web/app/providers.tsx
@@ -1,6 +1,5 @@
"use client";
-import { type DehydratedState } from "@tanstack/react-query";
import { TrpcProvider } from "app/_trpc/trpc-provider";
import { SessionProvider } from "next-auth/react";
import CacheProvider from "react-inlinesvg/provider";
@@ -12,14 +11,13 @@ import PlainChat from "@lib/plain/dynamicProvider";
type ProvidersProps = {
children: React.ReactNode;
- dehydratedState: DehydratedState;
};
-export function Providers({ children, dehydratedState }: ProvidersProps) {
+export function Providers({ children }: ProvidersProps) {
const isBookingPage = useIsBookingPage();
return (
-
+
{!isBookingPage ? : null}
{/* @ts-expect-error FIXME remove this comment when upgrading typescript to v5 */}
diff --git a/apps/web/lib/apps/categories/getServerSideProps.tsx b/apps/web/lib/apps/categories/getServerSideProps.tsx
index db3f86519c..b8d9a058de 100644
--- a/apps/web/lib/apps/categories/getServerSideProps.tsx
+++ b/apps/web/lib/apps/categories/getServerSideProps.tsx
@@ -3,13 +3,9 @@ import type { GetServerSidePropsContext } from "next";
import { getAppRegistry, getAppRegistryWithCredentials } from "@calcom/app-store/_appRegistry";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
-import { ssrInit } from "@server/lib/ssr";
-
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
const { req } = context;
- const ssr = await ssrInit(context);
-
const session = await getServerSession({ req });
let appStore;
@@ -29,7 +25,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
return {
props: {
categories: Object.entries(categories).map(([name, count]) => ({ name, count })),
- trpcState: ssr.dehydrate(),
+ trpcState: undefined,
},
};
};
diff --git a/apps/web/lib/apps/getServerSideProps.tsx b/apps/web/lib/apps/getServerSideProps.tsx
index 7288401ee7..bf2cffa4c5 100644
--- a/apps/web/lib/apps/getServerSideProps.tsx
+++ b/apps/web/lib/apps/getServerSideProps.tsx
@@ -5,13 +5,9 @@ import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { UserRepository } from "@calcom/lib/server/repository/user";
import type { AppCategories } from "@calcom/prisma/enums";
-import { ssrInit } from "@server/lib/ssr";
-
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
const { req } = context;
- const ssr = await ssrInit(context);
-
const session = await getServerSession({ req });
let appStore, userAdminTeamsIds: number[];
@@ -46,7 +42,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
}),
appStore,
userAdminTeams: userAdminTeamsIds,
- trpcState: ssr.dehydrate(),
+ trpcState: undefined,
},
};
};
diff --git a/apps/web/server/lib/ssg.ts b/apps/web/server/lib/ssg.ts
deleted file mode 100644
index 1d1fa30467..0000000000
--- a/apps/web/server/lib/ssg.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import type { GetStaticPropsContext } from "next";
-import { serverSideTranslations } from "next-i18next/serverSideTranslations";
-import superjson from "superjson";
-
-import { CALCOM_VERSION } from "@calcom/lib/constants";
-import prisma, { readonlyPrisma } from "@calcom/prisma";
-import { appRouter } from "@calcom/trpc/server/routers/_app";
-
-import { createServerSideHelpers } from "@trpc/react-query/server";
-
-// eslint-disable-next-line @typescript-eslint/no-var-requires
-const { i18n } = require("@calcom/config/next-i18next.config");
-
-/**
- * Initialize static site rendering tRPC helpers.
- * Provides a method to prefetch tRPC-queries in a `getStaticProps`-function.
- * Automatically prefetches i18n based on the passed in `context`-object to prevent i18n-flickering.
- * Make sure to `return { props: { trpcState: ssr.dehydrate() } }` at the end.
- */
-export async function ssgInit(opts: GetStaticPropsContext) {
- const requestedLocale = opts.params?.locale || opts.locale || i18n.defaultLocale;
- const isSupportedLocale = i18n.locales.includes(requestedLocale);
- if (!isSupportedLocale) {
- console.warn(`Requested unsupported locale "${requestedLocale}"`);
- }
- const locale = isSupportedLocale ? requestedLocale : i18n.defaultLocale;
-
- const _i18n = await serverSideTranslations(locale, ["common"]);
-
- const ssg = createServerSideHelpers({
- router: appRouter,
- transformer: superjson,
- ctx: {
- prisma,
- insightsDb: readonlyPrisma,
- session: null,
- locale,
- i18n: _i18n,
- },
- });
-
- // i18n translations are already retrieved from serverSideTranslations call, there is no need to run a i18n.fetch
- // we can set query data directly to the queryClient
- const queryKey = [
- ["viewer", "public", "i18n"],
- { input: { locale, CalComVersion: CALCOM_VERSION }, type: "query" },
- ];
-
- ssg.queryClient.setQueryData(queryKey, { i18n: _i18n });
-
- return ssg;
-}