diff --git a/bun.lockb b/bun.lockb index b59b19af..0eb9a911 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index d7c3b5cb..ebf8a1ad 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "src/email" ], "dependencies": { + "@edge-runtime/cookies": "^4.1.1", "@headlessui/react": "^1.7.17", "@react-email/render": "^0.0.10", "@supabase/ssr": "^0.3.0", diff --git a/src/pages/api/auth/confirm.ts b/src/pages/api/auth/confirm.ts index f0a7f5f6..3ec7f62a 100644 --- a/src/pages/api/auth/confirm.ts +++ b/src/pages/api/auth/confirm.ts @@ -1,7 +1,7 @@ import { type EmailOtpType } from "@supabase/supabase-js"; import type { NextApiRequest, NextApiResponse } from "next"; -import createClient from "~/utils/supabase/api"; +import { createNextClient } from "~/utils/supabase/api"; function stringOrFirstString(item: string | string[] | undefined) { return Array.isArray(item) ? item[0] : item; @@ -23,7 +23,7 @@ export default async function handler( let next = "/error"; if (token_hash && type) { - const supabase = createClient(req, res); + const supabase = createNextClient(req, res); const { error } = await supabase.auth.verifyOtp({ type: type as EmailOtpType, token_hash, @@ -37,3 +37,7 @@ export default async function handler( res.redirect(next); } + +// export const runtime = "edge"; +// export const preferredRegion = "lhr1"; +// export const dynamic = "force-dynamic"; diff --git a/src/pages/api/trpc/[trpc].ts b/src/pages/api/trpc/[trpc].ts index 7fc33a39..99293098 100644 --- a/src/pages/api/trpc/[trpc].ts +++ b/src/pages/api/trpc/[trpc].ts @@ -1,27 +1,27 @@ -import { type NextApiRequest, type NextApiResponse } from "next"; -import { createNextApiHandler } from "@trpc/server/adapters/next"; +import { type NextRequest } from "next/server"; +import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; import { env } from "~/env.mjs"; import { appRouter } from "~/server/api/root"; import { createTRPCContext } from "~/server/api/trpc"; -const nextApiHandler = createNextApiHandler({ - router: appRouter, - createContext: createTRPCContext, - onError: - env.NODE_ENV === "development" - ? ({ path, error }) => { - console.error( - `❌ tRPC failed on ${path ?? ""}: ${error.message}`, - ); - } - : undefined, -}); - -export default function handler(req: NextApiRequest, res: NextApiResponse) { - return nextApiHandler(req, res); +export default async function handler(req: NextRequest) { + return fetchRequestHandler({ + endpoint: "/api/trpc", + router: appRouter, + req, + createContext: createTRPCContext, + onError: + env.NODE_ENV === "development" + ? ({ path, error }) => { + console.error( + `❌ tRPC failed on ${path ?? ""}: ${error.message}`, + ); + } + : undefined, + }); } -// export const runtime = "edge"; -// export const preferredRegion = 'lhr1'; -// export const dynamic = 'force-dynamic' +export const runtime = "edge"; +export const preferredRegion = "lhr1"; +export const dynamic = "force-dynamic"; diff --git a/src/server/api/trpc.ts b/src/server/api/trpc.ts index 633ba5bb..ad1f8701 100644 --- a/src/server/api/trpc.ts +++ b/src/server/api/trpc.ts @@ -7,11 +7,11 @@ * need to use are documented accordingly near the end. */ import { initTRPC, TRPCError } from "@trpc/server"; -import { type CreateNextContextOptions } from "@trpc/server/adapters/next"; +import { type FetchCreateContextFnOptions } from "@trpc/server/adapters/fetch"; import superjson from "superjson"; import { ZodError } from "zod"; -import createClient from "~/utils/supabase/api"; +import { createTRPCClient } from "~/utils/supabase/api"; import { type Database } from "~/types/database.types"; import { type SupabaseClient } from "@supabase/supabase-js"; @@ -56,8 +56,11 @@ export const createInnerTRPCContext = (opts: CreateContextOptions) => { * * @see https://trpc.io/docs/context */ -export const createTRPCContext = async (_opts: CreateNextContextOptions) => { - const db = createClient(_opts.req, _opts.res); +export const createTRPCContext = async ({ + req, + resHeaders, +}: FetchCreateContextFnOptions) => { + const db = createTRPCClient(req, resHeaders); const { data: { user }, diff --git a/src/utils/supabase/api.ts b/src/utils/supabase/api.ts index 91b9e9fe..89f60fc3 100644 --- a/src/utils/supabase/api.ts +++ b/src/utils/supabase/api.ts @@ -3,13 +3,12 @@ import { type CookieOptions, serialize, } from "@supabase/ssr"; -import { type NextApiRequest, type NextApiResponse } from "next"; +import { RequestCookies } from "@edge-runtime/cookies"; import { type Database } from "~/types/database.types"; -export default function createClient( - req: NextApiRequest, - res: NextApiResponse, -) { +import { type NextApiRequest, type NextApiResponse } from "next"; + +export function createNextClient(req: NextApiRequest, res: NextApiResponse) { const supabase = createServerClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, @@ -32,3 +31,28 @@ export default function createClient( return supabase; } + +export function createTRPCClient(req: Request, resHeaders: Headers) { + const supabase = createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + get(name: string) { + const cookies = new RequestCookies(req.headers); + return cookies.get(name)?.value; + }, + set(name: string, value: string, options: CookieOptions) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call + resHeaders.set("Set-Cookie", serialize(name, value, options)); + }, + remove(name: string, options: CookieOptions) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call + resHeaders.set("Set-Cookie", serialize(name, "", options)); + }, + }, + }, + ); + + return supabase; +}