diff --git a/apps/landing/src/pages/_app.tsx b/apps/landing/src/pages/_app.tsx index 39929591d..56cac76fb 100644 --- a/apps/landing/src/pages/_app.tsx +++ b/apps/landing/src/pages/_app.tsx @@ -1,7 +1,6 @@ import "tailwindcss/tailwind.css"; import "../style.css"; -import { trpc, UserSession } from "@rallly/backend/next/trpc/client"; import { inject } from "@vercel/analytics"; import dayjs from "dayjs"; import localizedFormat from "dayjs/plugin/localizedFormat"; @@ -27,12 +26,8 @@ const inter = Inter({ display: "swap", }); -type PageProps = { - user?: UserSession; -}; - -type AppPropsWithLayout = AppProps & { - Component: NextPageWithLayout; +type AppPropsWithLayout = AppProps & { + Component: NextPageWithLayout; }; const MyApp: NextPage = ({ Component, pageProps }) => { @@ -112,4 +107,4 @@ const MyApp: NextPage = ({ Component, pageProps }) => { ); }; -export default trpc.withTRPC(appWithTranslation(MyApp, nextI18nNextConfig)); +export default appWithTranslation(MyApp, nextI18nNextConfig); diff --git a/apps/web/package.json b/apps/web/package.json index 7ac379b5d..6297810fb 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -32,7 +32,11 @@ "@sentry/nextjs": "^7.46.0", "@svgr/webpack": "^6.5.1", "@tailwindcss/typography": "^0.5.9", + "@tanstack/react-query": "^4.0.0", "@tanstack/react-table": "^8.9.1", + "@trpc/client": "^10.13.0", + "@trpc/next": "^10.13.0", + "@trpc/react-query": "^10.13.0", "@vercel/og": "^0.5.13", "accept-language-parser": "^1.5.0", "autoprefixer": "^10.4.13", @@ -67,7 +71,7 @@ "react-use": "^17.4.0", "smoothscroll-polyfill": "^0.4.4", "spacetime": "^7.4.7", - "superjson": "^1.12.2", + "superjson": "^2.0.0", "timezone-soft": "^1.4.1" }, "devDependencies": { diff --git a/apps/web/src/components/auth/auth-forms.tsx b/apps/web/src/components/auth/auth-forms.tsx index 50499e4b1..edad2e027 100644 --- a/apps/web/src/components/auth/auth-forms.tsx +++ b/apps/web/src/components/auth/auth-forms.tsx @@ -1,4 +1,3 @@ -import { trpc } from "@rallly/backend"; import { Button } from "@rallly/ui/button"; import Link from "next/link"; import { useRouter } from "next/router"; @@ -9,6 +8,7 @@ import { useForm } from "react-hook-form"; import { createGlobalState } from "react-use"; import { usePostHog } from "@/utils/posthog"; +import { trpc } from "@/utils/trpc/client"; import { requiredString, validEmail } from "../../utils/form-validation"; import { TextInput } from "../text-input"; diff --git a/apps/web/src/components/create-poll.tsx b/apps/web/src/components/create-poll.tsx index 3183e014a..5bb7b39db 100644 --- a/apps/web/src/components/create-poll.tsx +++ b/apps/web/src/components/create-poll.tsx @@ -1,4 +1,3 @@ -import { trpc } from "@rallly/backend"; import { Button } from "@rallly/ui/button"; import { Card, @@ -17,6 +16,7 @@ import { useUnmount } from "react-use"; import { PollSettingsForm } from "@/components/forms/poll-settings"; import { Trans } from "@/components/trans"; import { usePostHog } from "@/utils/posthog"; +import { trpc } from "@/utils/trpc/client"; import { NewEventData, PollDetailsForm, PollOptionsForm } from "./forms"; diff --git a/apps/web/src/components/discussion/discussion.tsx b/apps/web/src/components/discussion/discussion.tsx index 86b47bef2..b61a813d7 100644 --- a/apps/web/src/components/discussion/discussion.tsx +++ b/apps/web/src/components/discussion/discussion.tsx @@ -1,4 +1,3 @@ -import { trpc } from "@rallly/backend"; import { MessageCircleIcon, MoreHorizontalIcon, @@ -21,6 +20,7 @@ import { Trans } from "@/components/trans"; import { usePermissions } from "@/contexts/permissions"; import { useRole } from "@/contexts/role"; import { usePostHog } from "@/utils/posthog"; +import { trpc } from "@/utils/trpc/client"; import { requiredString } from "../../utils/form-validation"; import NameInput from "../name-input"; diff --git a/apps/web/src/components/layouts/admin-layout.tsx b/apps/web/src/components/layouts/admin-layout.tsx index ac8346308..88850360d 100644 --- a/apps/web/src/components/layouts/admin-layout.tsx +++ b/apps/web/src/components/layouts/admin-layout.tsx @@ -1,10 +1,10 @@ -import { trpc } from "@rallly/backend"; import { useRouter } from "next/router"; import React from "react"; import { StandardLayout } from "@/components/layouts/standard-layout"; import { useUser } from "@/components/user-provider"; import { NextPageWithLayout } from "@/types"; +import { trpc } from "@/utils/trpc/client"; const AdminLayout = (props: React.PropsWithChildren) => { const router = useRouter(); diff --git a/apps/web/src/components/layouts/poll-layout.tsx b/apps/web/src/components/layouts/poll-layout.tsx index bdd056a94..184623f20 100644 --- a/apps/web/src/components/layouts/poll-layout.tsx +++ b/apps/web/src/components/layouts/poll-layout.tsx @@ -1,4 +1,3 @@ -import { trpc } from "@rallly/backend"; import { ArrowLeftIcon, ArrowUpRight, @@ -48,6 +47,7 @@ import { Trans } from "@/components/trans"; import { useUser } from "@/components/user-provider"; import { usePoll } from "@/contexts/poll"; import Error404 from "@/pages/404"; +import { trpc } from "@/utils/trpc/client"; import { NextPageWithLayout } from "../../types"; diff --git a/apps/web/src/components/participant-dropdown.tsx b/apps/web/src/components/participant-dropdown.tsx index 35bc2ad3f..fd0bca988 100644 --- a/apps/web/src/components/participant-dropdown.tsx +++ b/apps/web/src/components/participant-dropdown.tsx @@ -1,4 +1,3 @@ -import { trpc } from "@rallly/backend"; import { PencilIcon, TagIcon, TrashIcon } from "@rallly/icons"; import { Button } from "@rallly/ui/button"; import { @@ -37,6 +36,7 @@ import { useDeleteParticipantMutation } from "@/components/poll/mutations"; import { Trans } from "@/components/trans"; import { useFormValidation } from "@/utils/form-validation"; import { usePostHog } from "@/utils/posthog"; +import { trpc } from "@/utils/trpc/client"; import { Participant } from ".prisma/client"; diff --git a/apps/web/src/components/participants-provider.tsx b/apps/web/src/components/participants-provider.tsx index 00cafe367..8cfddade4 100644 --- a/apps/web/src/components/participants-provider.tsx +++ b/apps/web/src/components/participants-provider.tsx @@ -1,9 +1,9 @@ -import { trpc } from "@rallly/backend"; import { Participant, VoteType } from "@rallly/database"; import * as React from "react"; import { useVisibility } from "@/components/visibility"; import { usePermissions } from "@/contexts/permissions"; +import { trpc } from "@/utils/trpc/client"; import { Vote } from "@/utils/trpc/types"; import { useRequiredContext } from "./use-required-context"; diff --git a/apps/web/src/components/poll/manage-poll/delete-poll-dialog.tsx b/apps/web/src/components/poll/manage-poll/delete-poll-dialog.tsx index 7932c5019..7326426cc 100644 --- a/apps/web/src/components/poll/manage-poll/delete-poll-dialog.tsx +++ b/apps/web/src/components/poll/manage-poll/delete-poll-dialog.tsx @@ -1,4 +1,3 @@ -import { trpc } from "@rallly/backend"; import { Button } from "@rallly/ui/button"; import { Dialog, @@ -13,6 +12,7 @@ import * as React from "react"; import { Trans } from "@/components/trans"; import { usePostHog } from "@/utils/posthog"; +import { trpc } from "@/utils/trpc/client"; export const DeletePollDialog: React.FunctionComponent<{ open: boolean; diff --git a/apps/web/src/components/poll/mutations.ts b/apps/web/src/components/poll/mutations.ts index 4177d9177..e6bfc9aaa 100644 --- a/apps/web/src/components/poll/mutations.ts +++ b/apps/web/src/components/poll/mutations.ts @@ -1,7 +1,6 @@ -import { trpc } from "@rallly/backend"; - import { usePoll } from "@/components/poll-context"; import { usePostHog } from "@/utils/posthog"; +import { trpc } from "@/utils/trpc/client"; import { ParticipantForm } from "./types"; diff --git a/apps/web/src/components/poll/notifications-toggle.tsx b/apps/web/src/components/poll/notifications-toggle.tsx index f41a69ef4..0aa5d9990 100644 --- a/apps/web/src/components/poll/notifications-toggle.tsx +++ b/apps/web/src/components/poll/notifications-toggle.tsx @@ -1,4 +1,3 @@ -import { trpc } from "@rallly/backend"; import { BellOffIcon, BellRingIcon } from "@rallly/icons"; import { Button } from "@rallly/ui/button"; import { Tooltip, TooltipContent, TooltipTrigger } from "@rallly/ui/tooltip"; @@ -10,6 +9,7 @@ import { Skeleton } from "@/components/skeleton"; import { Trans } from "@/components/trans"; import { useUser } from "@/components/user-provider"; import { usePostHog } from "@/utils/posthog"; +import { trpc } from "@/utils/trpc/client"; import { usePoll } from "../poll-context"; diff --git a/apps/web/src/components/poll/use-touch-beacon.ts b/apps/web/src/components/poll/use-touch-beacon.ts index 946d9d503..a9067f8af 100644 --- a/apps/web/src/components/poll/use-touch-beacon.ts +++ b/apps/web/src/components/poll/use-touch-beacon.ts @@ -1,6 +1,7 @@ -import { trpc } from "@rallly/backend"; import { useMount } from "react-use"; +import { trpc } from "@/utils/trpc/client"; + /** * Touching a poll updates a column with the current date. This information is used to * find polls that haven't been accessed for some time so that they can be deleted by house keeping. diff --git a/apps/web/src/components/settings/language-preference.tsx b/apps/web/src/components/settings/language-preference.tsx index da4a07bd6..8084816fb 100644 --- a/apps/web/src/components/settings/language-preference.tsx +++ b/apps/web/src/components/settings/language-preference.tsx @@ -1,4 +1,3 @@ -import { trpc } from "@rallly/backend"; import { ArrowUpRight } from "@rallly/icons"; import { Button } from "@rallly/ui/button"; import { Form, FormField, FormItem, FormLabel } from "@rallly/ui/form"; @@ -12,6 +11,7 @@ import { z } from "zod"; import { LanguageSelect } from "@/components/poll/language-selector"; import { Trans } from "@/components/trans"; import { useUser } from "@/components/user-provider"; +import { trpc } from "@/utils/trpc/client"; const formSchema = z.object({ language: z.string(), diff --git a/apps/web/src/components/user-provider.tsx b/apps/web/src/components/user-provider.tsx index a25973b54..820c37db1 100644 --- a/apps/web/src/components/user-provider.tsx +++ b/apps/web/src/components/user-provider.tsx @@ -1,4 +1,3 @@ -import { trpc } from "@rallly/backend"; import Cookies from "js-cookie"; import { Session } from "next-auth"; import { signIn, useSession } from "next-auth/react"; @@ -9,6 +8,7 @@ import { z } from "zod"; import { PostHogProvider } from "@/contexts/posthog"; import { PreferencesProvider } from "@/contexts/preferences"; import { isSelfHosted } from "@/utils/constants"; +import { trpc } from "@/utils/trpc/client"; import { useRequiredContext } from "./use-required-context"; diff --git a/apps/web/src/contexts/current-event.ts b/apps/web/src/contexts/current-event.ts index dbca64d2f..2cd05b164 100644 --- a/apps/web/src/contexts/current-event.ts +++ b/apps/web/src/contexts/current-event.ts @@ -1,7 +1,8 @@ -import { trpc } from "@rallly/backend"; import React from "react"; import { createStateContext } from "react-use"; +import { trpc } from "@/utils/trpc/client"; + export const [usePollId, PollIdProvider] = createStateContext(""); const useCurrentEventId = () => { diff --git a/apps/web/src/contexts/plan.tsx b/apps/web/src/contexts/plan.tsx index db556d205..d4c31b597 100644 --- a/apps/web/src/contexts/plan.tsx +++ b/apps/web/src/contexts/plan.tsx @@ -1,10 +1,10 @@ -import { trpc } from "@rallly/backend"; import { Badge } from "@rallly/ui/badge"; import React from "react"; import { Trans } from "@/components/trans"; import { useUser } from "@/components/user-provider"; import { isSelfHosted } from "@/utils/constants"; +import { trpc } from "@/utils/trpc/client"; export const useSubscription = () => { const { user } = useUser(); diff --git a/apps/web/src/contexts/poll.tsx b/apps/web/src/contexts/poll.tsx index a83c90944..7a2abcb56 100644 --- a/apps/web/src/contexts/poll.tsx +++ b/apps/web/src/contexts/poll.tsx @@ -1,9 +1,9 @@ -import { trpc } from "@rallly/backend"; import dayjs, { Dayjs } from "dayjs"; import { useRouter } from "next/router"; import React from "react"; import { useDayjs } from "@/utils/dayjs"; +import { trpc } from "@/utils/trpc/client"; export const usePoll = () => { const router = useRouter(); diff --git a/apps/web/src/pages/_app.tsx b/apps/web/src/pages/_app.tsx index 2f33e34ec..0b9f7eebc 100644 --- a/apps/web/src/pages/_app.tsx +++ b/apps/web/src/pages/_app.tsx @@ -2,7 +2,6 @@ import "react-big-calendar/lib/css/react-big-calendar.css"; import "tailwindcss/tailwind.css"; import "../style.css"; -import { trpc } from "@rallly/backend/next/trpc/client"; import { TooltipProvider } from "@rallly/ui/tooltip"; import { domMax, LazyMotion } from "framer-motion"; import { NextPage } from "next"; @@ -15,6 +14,7 @@ import { appWithTranslation } from "next-i18next"; import { DefaultSeo } from "next-seo"; import Maintenance from "@/components/maintenance"; +import { trpc } from "@/utils/trpc/client"; import * as nextI18nNextConfig from "../../next-i18next.config.js"; import { NextPageWithLayout } from "../types"; diff --git a/apps/web/src/pages/api/trpc/[trpc].ts b/apps/web/src/pages/api/trpc/[trpc].ts index 186df892d..406db0d82 100644 --- a/apps/web/src/pages/api/trpc/[trpc].ts +++ b/apps/web/src/pages/api/trpc/[trpc].ts @@ -1,5 +1,6 @@ -import { trpcNextApiHandler } from "@rallly/backend/next/trpc/server"; -import { NextApiRequest, NextApiResponse } from "next"; +import { createTRPCContext } from "@rallly/backend/trpc/context"; +import { AppRouter, appRouter } from "@rallly/backend/trpc/routers"; +import * as trpcNext from "@trpc/server/adapters/next"; import { absoluteUrl, shortUrl } from "@/utils/absolute-url"; import { getServerSession, isEmailBlocked } from "@/utils/auth"; @@ -12,27 +13,27 @@ export const config = { }, }; -// export API handler -export default async function handler( - req: NextApiRequest, - res: NextApiResponse, -) { - const session = await getServerSession(req, res); +export default trpcNext.createNextApiHandler({ + router: appRouter, + createContext: async (opts) => { + return createTRPCContext(opts, { + async getUser({ req, res }) { + const session = await getServerSession(req, res); - if (!session) { - res.status(401).json({ error: "Unauthorized" }); - return; - } + if (!session) { + return null; + } - return trpcNextApiHandler({ - user: { - isGuest: session.user.email === null, - id: session.user.id, - }, - emailClient, - isSelfHosted, - isEmailBlocked, - absoluteUrl, - shortUrl, - })(req, res); -} + return { + id: session.user.id, + isGuest: session.user.email === null, + }; + }, + emailClient, + isSelfHosted, + isEmailBlocked, + absoluteUrl, + shortUrl, + }); + }, +}); diff --git a/apps/web/src/pages/invite/[urlId].tsx b/apps/web/src/pages/invite/[urlId].tsx index 12cb2c87a..2c3845de6 100644 --- a/apps/web/src/pages/invite/[urlId].tsx +++ b/apps/web/src/pages/invite/[urlId].tsx @@ -1,4 +1,3 @@ -import { trpc } from "@rallly/backend"; import { prisma } from "@rallly/database"; import { ArrowUpLeftIcon } from "@rallly/icons"; import { Button } from "@rallly/ui/button"; @@ -20,6 +19,7 @@ import { PermissionsContext } from "@/contexts/permissions"; import { usePoll } from "@/contexts/poll"; import { absoluteUrl } from "@/utils/absolute-url"; import { ConnectedDayjsProvider } from "@/utils/dayjs"; +import { trpc } from "@/utils/trpc/client"; import { getStaticTranslations } from "@/utils/with-page-translations"; import Error404 from "../404"; diff --git a/apps/web/src/pages/poll/[urlId]/duplicate.tsx b/apps/web/src/pages/poll/[urlId]/duplicate.tsx index 63c6ed44d..fa6c7cde8 100644 --- a/apps/web/src/pages/poll/[urlId]/duplicate.tsx +++ b/apps/web/src/pages/poll/[urlId]/duplicate.tsx @@ -1,5 +1,4 @@ import { zodResolver } from "@hookform/resolvers/zod"; -import { trpc } from "@rallly/backend"; import { Button } from "@rallly/ui/button"; import { Card, @@ -28,6 +27,7 @@ import { usePoll } from "@/components/poll-context"; import { Trans } from "@/components/trans"; import { NextPageWithLayout } from "@/types"; import { usePostHog } from "@/utils/posthog"; +import { trpc } from "@/utils/trpc/client"; import { getStaticTranslations } from "@/utils/with-page-translations"; const formSchema = z.object({ diff --git a/apps/web/src/pages/poll/[urlId]/finalize.tsx b/apps/web/src/pages/poll/[urlId]/finalize.tsx index da828f0be..f56cd94f8 100644 --- a/apps/web/src/pages/poll/[urlId]/finalize.tsx +++ b/apps/web/src/pages/poll/[urlId]/finalize.tsx @@ -1,4 +1,3 @@ -import { trpc } from "@rallly/backend"; import { Button } from "@rallly/ui/button"; import { CardContent, @@ -18,6 +17,7 @@ import { usePlan } from "@/contexts/plan"; import { usePoll } from "@/contexts/poll"; import { NextPageWithLayout } from "@/types"; import { usePostHog } from "@/utils/posthog"; +import { trpc } from "@/utils/trpc/client"; import { getStaticTranslations } from "@/utils/with-page-translations"; const FinalizationForm = () => { diff --git a/apps/web/src/pages/polls.tsx b/apps/web/src/pages/polls.tsx index 75af7945c..9eff9a6f4 100644 --- a/apps/web/src/pages/polls.tsx +++ b/apps/web/src/pages/polls.tsx @@ -1,4 +1,3 @@ -import { trpc } from "@rallly/backend"; import { InboxIcon, PauseCircleIcon, @@ -25,6 +24,7 @@ import { Skeleton } from "@/components/skeleton"; import { Trans } from "@/components/trans"; import { NextPageWithLayout } from "@/types"; import { useDayjs } from "@/utils/dayjs"; +import { trpc } from "@/utils/trpc/client"; import { getStaticTranslations } from "@/utils/with-page-translations"; const EmptyState = () => { @@ -94,7 +94,7 @@ const Page: NextPageWithLayout = () => { key={poll.id} className="flex overflow-hidden rounded-md border shadow-sm" > -
+
{poll.event ? ( diff --git a/apps/web/src/pages/register.tsx b/apps/web/src/pages/register.tsx index b03eb4f62..e51af6794 100644 --- a/apps/web/src/pages/register.tsx +++ b/apps/web/src/pages/register.tsx @@ -1,4 +1,3 @@ -import { trpc } from "@rallly/backend"; import { Button } from "@rallly/ui/button"; import Head from "next/head"; import Link from "next/link"; @@ -15,6 +14,7 @@ import { TextInput } from "@/components/text-input"; import { NextPageWithLayout } from "@/types"; import { useDayjs } from "@/utils/dayjs"; import { requiredString, validEmail } from "@/utils/form-validation"; +import { trpc } from "@/utils/trpc/client"; import { AuthLayout } from "../components/auth/auth-layout"; import { getStaticTranslations } from "../utils/with-page-translations"; diff --git a/apps/web/src/pages/settings/billing.tsx b/apps/web/src/pages/settings/billing.tsx index 50442af97..0f27e59ff 100644 --- a/apps/web/src/pages/settings/billing.tsx +++ b/apps/web/src/pages/settings/billing.tsx @@ -1,4 +1,3 @@ -import { trpc } from "@rallly/backend"; import { ArrowUpRight, CreditCardIcon, SendIcon } from "@rallly/icons"; import { Button } from "@rallly/ui/button"; import { Card } from "@rallly/ui/card"; @@ -20,6 +19,7 @@ import { import { Trans } from "@/components/trans"; import { useSubscription } from "@/contexts/plan"; import { isSelfHosted } from "@/utils/constants"; +import { trpc } from "@/utils/trpc/client"; import { NextPageWithLayout } from "../../types"; import { getStaticTranslations } from "../../utils/with-page-translations"; diff --git a/apps/web/src/utils/auth.ts b/apps/web/src/utils/auth.ts index 5ed9f700f..5b009c33e 100644 --- a/apps/web/src/utils/auth.ts +++ b/apps/web/src/utils/auth.ts @@ -187,7 +187,7 @@ const authOptions = { }, } satisfies NextAuthOptions; -export function getServerSession( +export async function getServerSession( ...args: | [GetServerSidePropsContext["req"], GetServerSidePropsContext["res"]] | [NextApiRequest, NextApiResponse] diff --git a/packages/backend/next/trpc/client.ts b/apps/web/src/utils/trpc/client.ts similarity index 80% rename from packages/backend/next/trpc/client.ts rename to apps/web/src/utils/trpc/client.ts index bb76ab925..5223f7e35 100644 --- a/packages/backend/next/trpc/client.ts +++ b/apps/web/src/utils/trpc/client.ts @@ -1,19 +1,17 @@ +import { AppRouter } from "@rallly/backend/trpc/routers"; +import * as Sentry from "@sentry/browser"; import { MutationCache } from "@tanstack/react-query"; import { httpBatchLink } from "@trpc/client"; import { createTRPCNext } from "@trpc/next"; import toast from "react-hot-toast"; import superjson from "superjson"; -import { AppRouter } from "../../trpc/routers"; - -export * from "../../trpc/types"; - export const trpc = createTRPCNext({ config() { return { links: [ httpBatchLink({ - url: `/api/trpc`, + url: "/api/trpc", }), ], transformer: superjson, @@ -21,20 +19,19 @@ export const trpc = createTRPCNext({ defaultOptions: { queries: { retry: false, - networkMode: "always", cacheTime: Infinity, staleTime: 1000 * 60, }, }, mutationCache: new MutationCache({ - onError: () => { + onError: (error) => { toast.error( "Uh oh! Something went wrong. The issue has been logged and we'll fix it as soon as possible. Please try again later.", ); + Sentry.captureException(error); }, }), }, }; }, - ssr: false, }); diff --git a/packages/backend/index.ts b/packages/backend/index.ts index 752261b2b..b2dc61224 100644 --- a/packages/backend/index.ts +++ b/packages/backend/index.ts @@ -1 +1 @@ -export * from "./next/trpc/client"; +export * from "./trpc/types"; diff --git a/packages/backend/next/trpc/server.ts b/packages/backend/next/trpc/server.ts deleted file mode 100644 index ad5c52035..000000000 --- a/packages/backend/next/trpc/server.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { EmailClient } from "@rallly/emails"; -import * as trpcNext from "@trpc/server/adapters/next"; - -import { appRouter } from "../../trpc/routers"; - -export interface TRPCContext { - user: { id: string; isGuest: boolean }; - emailClient: EmailClient; - isSelfHosted: boolean; - isEmailBlocked?: (email: string) => boolean; - /** - * Takes a relative path and returns an absolute URL to the app - * @param path - * @returns absolute URL - */ - absoluteUrl: (path?: string) => string; - shortUrl: (path?: string) => string; -} - -export const trpcNextApiHandler = (context: TRPCContext) => { - return trpcNext.createNextApiHandler({ - router: appRouter, - createContext: async () => { - return context; - }, - }); -}; diff --git a/packages/backend/package.json b/packages/backend/package.json index 088421bb4..5a3880ccc 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -12,15 +12,10 @@ "@rallly/database": "*", "@rallly/emails": "*", "@rallly/utils": "*", - "@tanstack/react-query": "^4.22.0", - "@trpc/client": "^10.13.0", - "@trpc/next": "^10.13.0", - "@trpc/react-query": "^10.13.0", "@trpc/server": "^10.13.0", "iron-session": "^6.3.1", "spacetime": "^7.4.7", "stripe": "^13.2.0", - "superjson": "^1.12.2", "timezone-soft": "^1.4.1" } } diff --git a/packages/backend/trpc/context.ts b/packages/backend/trpc/context.ts new file mode 100644 index 000000000..9d155a7a4 --- /dev/null +++ b/packages/backend/trpc/context.ts @@ -0,0 +1,43 @@ +import { EmailClient } from "@rallly/emails"; +import { inferAsyncReturnType, TRPCError } from "@trpc/server"; +import { CreateNextContextOptions } from "@trpc/server/adapters/next"; + +export type GetUserFn = (opts: CreateNextContextOptions) => Promise<{ + id: string; + isGuest: boolean; +} | null>; + +export interface TRPCContextParams { + getUser: GetUserFn; + emailClient: EmailClient; + isSelfHosted: boolean; + isEmailBlocked?: (email: string) => boolean; + /** + * Takes a relative path and returns an absolute URL to the app + * @param path + * @returns absolute URL + */ + absoluteUrl: (path?: string) => string; + shortUrl: (path?: string) => string; +} + +export const createTRPCContext = async ( + opts: CreateNextContextOptions, + { getUser, ...params }: TRPCContextParams, +) => { + const user = await getUser(opts); + + if (!user) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Request has no session", + }); + } + + return { + user, + ...params, + }; +}; + +export type TRPCContext = inferAsyncReturnType; diff --git a/packages/backend/trpc/trpc.ts b/packages/backend/trpc/trpc.ts index f7005c4f2..44056987f 100644 --- a/packages/backend/trpc/trpc.ts +++ b/packages/backend/trpc/trpc.ts @@ -1,8 +1,8 @@ import { initTRPC, TRPCError } from "@trpc/server"; import superjson from "superjson"; -import { TRPCContext } from "../next/trpc/server"; import { getSubscriptionStatus } from "../utils/auth"; +import { TRPCContext } from "./context"; const t = initTRPC.context().create({ transformer: superjson, diff --git a/yarn.lock b/yarn.lock index f8441b80d..7b3d1d3e4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3710,17 +3710,17 @@ lodash.merge "^4.6.2" postcss-selector-parser "6.0.10" -"@tanstack/query-core@4.24.10": - version "4.24.10" - resolved "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.24.10.tgz" - integrity sha512-2QywqXEAGBIUoTdgn1lAB4/C8QEqwXHj2jrCLeYTk2xVGtLiPEUD8jcMoeB2noclbiW2mMt4+Fq7fZStuz3wAQ== +"@tanstack/query-core@4.36.1": + version "4.36.1" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.36.1.tgz#79f8c1a539d47c83104210be2388813a7af2e524" + integrity sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA== -"@tanstack/react-query@^4.22.0": - version "4.24.10" - resolved "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.24.10.tgz" - integrity sha512-FY1DixytOcNNCydPQXLxuKEV7VSST32CAuJ55BjhDNqASnMLZn+6c30yQBMrODjmWMNwzfjMZnq0Vw7C62Fwow== +"@tanstack/react-query@^4.0.0": + version "4.36.1" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.36.1.tgz#acb589fab4085060e2e78013164868c9c785e5d2" + integrity sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw== dependencies: - "@tanstack/query-core" "4.24.10" + "@tanstack/query-core" "4.36.1" use-sync-external-store "^1.2.0" "@tanstack/react-table@^8.9.1": @@ -3736,21 +3736,21 @@ integrity sha512-2+R83n8vMZND0q3W1lSiF7co9nFbeWbjAErFf27xwbeA9E0wtUu5ZDfgj+TZ6JzdAEQAgfxkk/QNFAKiS8E4MA== "@trpc/client@^10.13.0": - version "10.13.2" - resolved "https://registry.npmjs.org/@trpc/client/-/client-10.13.2.tgz" - integrity sha512-iEZOAYS/Ak5T6j2lrN2NCYYLb8YY9sbj4JJR9VgxDL8Cz1dRFpFZ2BA4VwNW6xoh0G+MRdSGvivTYdggbJ4BBg== + version "10.41.0" + resolved "https://registry.yarnpkg.com/@trpc/client/-/client-10.41.0.tgz#8abde2ae72fe33cb762ccbc8ba03f39d51c91cd5" + integrity sha512-W4lYULb7//2yXkULCKim49slXsBwiBq48rfge1yOWXdq0Ed8VxzXvZt8+uWOkxmHbQAw4lq8G5fCNYFB+Za6vQ== "@trpc/next@^10.13.0": - version "10.13.2" - resolved "https://registry.npmjs.org/@trpc/next/-/next-10.13.2.tgz" - integrity sha512-0GV9JanTY6PqWVd4W/OWIy8SI4qQD0F2ak4OgxLLothqB+ARzHpYkoZO+E3Y13/O+NV5RhWF6sIXXXX6doNghQ== + version "10.41.0" + resolved "https://registry.yarnpkg.com/@trpc/next/-/next-10.41.0.tgz#1d29d418cc333f5cb3e1c1f11647d74c7950a288" + integrity sha512-QwvZrvDjRFEzErmLZ4hMdYfX13nsH0SpijjuTNPIlSIyFISCIfDCqmBvWC07O6fCG/swh+XM19FhJN6RMqTlKQ== dependencies: react-ssr-prepass "^1.5.0" "@trpc/react-query@^10.13.0": - version "10.13.2" - resolved "https://registry.npmjs.org/@trpc/react-query/-/react-query-10.13.2.tgz" - integrity sha512-wLNDZKe5yQ2AYs/uoymxyRn5jNdYNpbOX17tHirnDDPKDRJojooGuL6uIDS1kvm70QJiNR/UKjKfwLDgZdGcqw== + version "10.41.0" + resolved "https://registry.yarnpkg.com/@trpc/react-query/-/react-query-10.41.0.tgz#eb07732df29b58861b583eff249a7ef6dadef5d7" + integrity sha512-pCLZfIgcnneq1AocPLvstALawZYWS/sbhujd4mwUwA3UXFBWC/D31ysPlbz7R1dhjxhhPaIM+C6pz8vmr2ctpw== "@trpc/server@^10.13.0": version "10.13.2" @@ -10585,10 +10585,10 @@ sucrase@^3.32.0: pirates "^4.0.1" ts-interface-checker "^0.1.9" -superjson@^1.12.2: - version "1.12.2" - resolved "https://registry.npmjs.org/superjson/-/superjson-1.12.2.tgz" - integrity sha512-ugvUo9/WmvWOjstornQhsN/sR9mnGtWGYeTxFuqLb4AiT4QdUavjGFRALCPKWWnAiUJ4HTpytj5e0t5HoMRkXg== +superjson@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/superjson/-/superjson-2.0.0.tgz#7abcbe6c1badc2e689ea62c375ca257666a68282" + integrity sha512-W3n+NJ7TFjaLle8ihIIvsr/bbuKpnxeatsyjmhy7iSkom+/cshaHziCQAWXrHGWJVQSQFDOuES6C3nSEvcbrQg== dependencies: copy-anything "^3.0.2" @@ -11211,7 +11211,7 @@ use-sidecar@^1.1.2: use-sync-external-store@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: