diff --git a/app/entry.server.tsx b/app/entry.server.tsx index ed4e4b815..364ea5249 100644 --- a/app/entry.server.tsx +++ b/app/entry.server.tsx @@ -15,7 +15,7 @@ import { getInstanceInfo } from './utils/litefs.server.ts' import { NonceProvider } from './utils/nonce-provider.ts' import { makeTimings } from './utils/timing.server.ts' -const ABORT_DELAY = 5000 +export const streamTimeout = 5000 init() global.ENV = getEnv() @@ -53,7 +53,7 @@ export default async function handleRequest(...args: DocRequestArgs) { const { pipe, abort } = renderToPipeableStream( - + , { [callbackName]: () => { @@ -78,7 +78,7 @@ export default async function handleRequest(...args: DocRequestArgs) { }, ) - setTimeout(abort, ABORT_DELAY) + setTimeout(abort, streamTimeout + 5000) }) } diff --git a/app/root.tsx b/app/root.tsx index a4d555477..aa936bd85 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -1,5 +1,5 @@ import { - json, + data, type LoaderFunctionArgs, type HeadersFunction, type LinksFunction, @@ -121,7 +121,7 @@ export async function loader({ request }: LoaderFunctionArgs) { const { toast, headers: toastHeaders } = await getToast(request) const honeyProps = honeypot.getInputProps() - return json( + return data( { user, requestInfo: { @@ -161,7 +161,8 @@ function Document({ children: React.ReactNode nonce: string theme?: Theme - env?: Record + env?: Record + allowIndexing?: boolean }) { const allowIndexing = ENV.ALLOW_INDEXING !== 'false' return ( diff --git a/app/routes/_auth+/auth.$provider.ts b/app/routes/_auth+/auth_.$provider.ts similarity index 100% rename from app/routes/_auth+/auth.$provider.ts rename to app/routes/_auth+/auth_.$provider.ts diff --git a/app/routes/_auth+/forgot-password.tsx b/app/routes/_auth+/forgot-password.tsx index f863eeb00..285f1fa87 100644 --- a/app/routes/_auth+/forgot-password.tsx +++ b/app/routes/_auth+/forgot-password.tsx @@ -3,7 +3,7 @@ import { getZodConstraint, parseWithZod } from '@conform-to/zod' import { type SEOHandle } from '@nasa-gcn/remix-seo' import * as E from '@react-email/components' import { - json, + data, redirect, type ActionFunctionArgs, type MetaFunction, @@ -54,7 +54,7 @@ export async function action({ request }: ActionFunctionArgs) { async: true, }) if (submission.status !== 'success') { - return json( + return data( { result: submission.reply() }, { status: submission.status === 'error' ? 400 : 200 }, ) @@ -84,7 +84,7 @@ export async function action({ request }: ActionFunctionArgs) { if (response.status === 'success') { return redirect(redirectTo.toString()) } else { - return json( + return data( { result: submission.reply({ formErrors: [response.error.message] }) }, { status: 500 }, ) diff --git a/app/routes/_auth+/login.tsx b/app/routes/_auth+/login.tsx index e15d84b72..14810f633 100644 --- a/app/routes/_auth+/login.tsx +++ b/app/routes/_auth+/login.tsx @@ -2,7 +2,7 @@ import { getFormProps, getInputProps, useForm } from '@conform-to/react' import { getZodConstraint, parseWithZod } from '@conform-to/zod' import { type SEOHandle } from '@nasa-gcn/remix-seo' import { - json, + data, type ActionFunctionArgs, type LoaderFunctionArgs, type MetaFunction, @@ -37,7 +37,7 @@ const LoginFormSchema = z.object({ export async function loader({ request }: LoaderFunctionArgs) { await requireAnonymous(request) - return json({}) + return {} } export async function action({ request }: ActionFunctionArgs) { @@ -64,7 +64,7 @@ export async function action({ request }: ActionFunctionArgs) { }) if (submission.status !== 'success' || !submission.value.session) { - return json( + return data( { result: submission.reply({ hideFields: ['password'] }) }, { status: submission.status === 'error' ? 400 : 200 }, ) diff --git a/app/routes/_auth+/onboarding.tsx b/app/routes/_auth+/onboarding.tsx index 042476141..a087363f0 100644 --- a/app/routes/_auth+/onboarding.tsx +++ b/app/routes/_auth+/onboarding.tsx @@ -1,7 +1,7 @@ import { getFormProps, getInputProps, useForm } from '@conform-to/react' import { getZodConstraint, parseWithZod } from '@conform-to/zod' import { - json, + data, redirect, type LoaderFunctionArgs, type ActionFunctionArgs, @@ -61,7 +61,7 @@ async function requireOnboardingEmail(request: Request) { export async function loader({ request }: LoaderFunctionArgs) { const email = await requireOnboardingEmail(request) - return json({ email }) + return { email } } export async function action({ request }: ActionFunctionArgs) { @@ -93,7 +93,7 @@ export async function action({ request }: ActionFunctionArgs) { }) if (submission.status !== 'success' || !submission.value.session) { - return json( + return data( { result: submission.reply() }, { status: submission.status === 'error' ? 400 : 200 }, ) diff --git a/app/routes/_auth+/onboarding_.$provider.tsx b/app/routes/_auth+/onboarding_.$provider.tsx index 9cbdc51a2..46f5cc981 100644 --- a/app/routes/_auth+/onboarding_.$provider.tsx +++ b/app/routes/_auth+/onboarding_.$provider.tsx @@ -7,7 +7,7 @@ import { import { getZodConstraint, parseWithZod } from '@conform-to/zod' import { redirect, - json, + data, type ActionFunctionArgs, type LoaderFunctionArgs, type MetaFunction, @@ -95,7 +95,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) { const formError = connectionSession.get(authenticator.sessionErrorKey) const hasError = typeof formError === 'string' - return json({ + return { email, status: 'idle', submission: { @@ -103,7 +103,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) { initialValue: prefilledProfile ?? {}, error: { '': hasError ? [formError] : [] }, } as SubmissionResult, - }) + } } export async function action({ request, params }: ActionFunctionArgs) { @@ -143,7 +143,7 @@ export async function action({ request, params }: ActionFunctionArgs) { }) if (submission.status !== 'success') { - return json( + return data( { result: submission.reply() }, { status: submission.status === 'error' ? 400 : 200 }, ) diff --git a/app/routes/_auth+/reset-password.server.ts b/app/routes/_auth+/reset-password.server.ts index 1c25b4dc5..39c4caa85 100644 --- a/app/routes/_auth+/reset-password.server.ts +++ b/app/routes/_auth+/reset-password.server.ts @@ -1,5 +1,5 @@ import { invariant } from '@epic-web/invariant' -import { json, redirect } from '@remix-run/node' +import { data, redirect } from '@remix-run/node' import { prisma } from '#app/utils/db.server.ts' import { verifySessionStorage } from '#app/utils/verification.server.ts' import { resetPasswordUsernameSessionKey } from './reset-password.tsx' @@ -18,7 +18,7 @@ export async function handleVerification({ submission }: VerifyFunctionArgs) { // we don't want to say the user is not found if the email is not found // because that would allow an attacker to check if an email is registered if (!user) { - return json( + return data( { result: submission.reply({ fieldErrors: { code: ['Invalid code'] } }) }, { status: 400 }, ) diff --git a/app/routes/_auth+/reset-password.tsx b/app/routes/_auth+/reset-password.tsx index 38e4763a2..a78e3057e 100644 --- a/app/routes/_auth+/reset-password.tsx +++ b/app/routes/_auth+/reset-password.tsx @@ -2,7 +2,7 @@ import { getFormProps, getInputProps, useForm } from '@conform-to/react' import { getZodConstraint, parseWithZod } from '@conform-to/zod' import { type SEOHandle } from '@nasa-gcn/remix-seo' import { - json, + data, redirect, type ActionFunctionArgs, type LoaderFunctionArgs, @@ -41,7 +41,7 @@ async function requireResetPasswordUsername(request: Request) { export async function loader({ request }: LoaderFunctionArgs) { const resetPasswordUsername = await requireResetPasswordUsername(request) - return json({ resetPasswordUsername }) + return { resetPasswordUsername } } export async function action({ request }: ActionFunctionArgs) { @@ -51,7 +51,7 @@ export async function action({ request }: ActionFunctionArgs) { schema: ResetPasswordSchema, }) if (submission.status !== 'success') { - return json( + return data( { result: submission.reply() }, { status: submission.status === 'error' ? 400 : 200 }, ) diff --git a/app/routes/_auth+/signup.tsx b/app/routes/_auth+/signup.tsx index 6d475a3d2..ea65f5596 100644 --- a/app/routes/_auth+/signup.tsx +++ b/app/routes/_auth+/signup.tsx @@ -3,7 +3,7 @@ import { getZodConstraint, parseWithZod } from '@conform-to/zod' import { type SEOHandle } from '@nasa-gcn/remix-seo' import * as E from '@react-email/components' import { - json, + data, redirect, type ActionFunctionArgs, type MetaFunction, @@ -56,7 +56,7 @@ export async function action({ request }: ActionFunctionArgs) { async: true, }) if (submission.status !== 'success') { - return json( + return data( { result: submission.reply() }, { status: submission.status === 'error' ? 400 : 200 }, ) @@ -78,7 +78,7 @@ export async function action({ request }: ActionFunctionArgs) { if (response.status === 'success') { return redirect(redirectTo.toString()) } else { - return json( + return data( { result: submission.reply({ formErrors: [response.error.message] }), }, diff --git a/app/routes/_auth+/verify.server.ts b/app/routes/_auth+/verify.server.ts index 35de6647c..c4d07cb35 100644 --- a/app/routes/_auth+/verify.server.ts +++ b/app/routes/_auth+/verify.server.ts @@ -1,6 +1,6 @@ import { type Submission } from '@conform-to/react' import { parseWithZod } from '@conform-to/zod' -import { json } from '@remix-run/node' +import { data } from '@remix-run/node' import { z } from 'zod' import { handleVerification as handleChangeEmailVerification } from '#app/routes/settings+/profile.change-email.server.tsx' import { twoFAVerificationType } from '#app/routes/settings+/profile.two-factor.tsx' @@ -161,7 +161,7 @@ export async function validateRequest( }) if (submission.status !== 'success') { - return json( + return data( { result: submission.reply() }, { status: submission.status === 'error' ? 400 : 200 }, ) diff --git a/app/routes/admin+/cache.tsx b/app/routes/admin+/cache.tsx index 741e85849..6ccdd0462 100644 --- a/app/routes/admin+/cache.tsx +++ b/app/routes/admin+/cache.tsx @@ -1,7 +1,6 @@ import { invariantResponse } from '@epic-web/invariant' import { type SEOHandle } from '@nasa-gcn/remix-seo' import { - json, redirect, type LoaderFunctionArgs, type ActionFunctionArgs, @@ -58,7 +57,7 @@ export async function loader({ request }: LoaderFunctionArgs) { } else { cacheKeys = await getAllCacheKeys(limit) } - return json({ cacheKeys, instance, instances, currentInstanceInfo }) + return { cacheKeys, instance, instances, currentInstanceInfo } } export async function action({ request }: ActionFunctionArgs) { @@ -87,7 +86,7 @@ export async function action({ request }: ActionFunctionArgs) { throw new Error(`Unknown cache type: ${type}`) } } - return json({ success: true }) + return { success: true } } export default function CacheAdminRoute() { diff --git a/app/routes/admin+/cache_.lru.$cacheKey.ts b/app/routes/admin+/cache_.lru.$cacheKey.ts index 2b793d094..b3a15f0e5 100644 --- a/app/routes/admin+/cache_.lru.$cacheKey.ts +++ b/app/routes/admin+/cache_.lru.$cacheKey.ts @@ -1,5 +1,5 @@ import { invariantResponse } from '@epic-web/invariant' -import { json, type LoaderFunctionArgs } from '@remix-run/node' +import { type LoaderFunctionArgs } from '@remix-run/node' import { lruCache } from '#app/utils/cache.server.ts' import { getAllInstances, @@ -19,7 +19,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) { const { cacheKey } = params invariantResponse(cacheKey, 'cacheKey is required') - return json({ + return { instance: { hostname: instance, region: allInstances[instance], @@ -27,5 +27,5 @@ export async function loader({ request, params }: LoaderFunctionArgs) { }, cacheKey, value: lruCache.get(cacheKey), - }) + } } diff --git a/app/routes/admin+/cache_.sqlite.$cacheKey.ts b/app/routes/admin+/cache_.sqlite.$cacheKey.ts index 39bcb0776..c59cf5fc9 100644 --- a/app/routes/admin+/cache_.sqlite.$cacheKey.ts +++ b/app/routes/admin+/cache_.sqlite.$cacheKey.ts @@ -1,5 +1,5 @@ import { invariantResponse } from '@epic-web/invariant' -import { json, type LoaderFunctionArgs } from '@remix-run/node' +import { type LoaderFunctionArgs } from '@remix-run/node' import { cache } from '#app/utils/cache.server.ts' import { getAllInstances, @@ -19,7 +19,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) { const { cacheKey } = params invariantResponse(cacheKey, 'cacheKey is required') - return json({ + return { instance: { hostname: instance, region: allInstances[instance], @@ -27,5 +27,5 @@ export async function loader({ request, params }: LoaderFunctionArgs) { }, cacheKey, value: cache.get(cacheKey), - }) + } } diff --git a/app/routes/admin+/cache_.sqlite.server.ts b/app/routes/admin+/cache_.sqlite.server.ts index a9c8f80eb..026ef7068 100644 --- a/app/routes/admin+/cache_.sqlite.server.ts +++ b/app/routes/admin+/cache_.sqlite.server.ts @@ -1,4 +1,4 @@ -import { json, redirect, type ActionFunctionArgs } from '@remix-run/node' +import { redirect, type ActionFunctionArgs } from '@remix-run/node' import { z } from 'zod' import { cache } from '#app/utils/cache.server.ts' import { @@ -54,5 +54,5 @@ export async function action({ request }: ActionFunctionArgs) { // @ts-expect-error - we don't reliably know the type of cacheValue await cache.set(key, cacheValue) } - return json({ success: true }) + return { success: true } } diff --git a/app/routes/resources+/theme-switch.tsx b/app/routes/resources+/theme-switch.tsx index 9c2f9d633..ac4da2612 100644 --- a/app/routes/resources+/theme-switch.tsx +++ b/app/routes/resources+/theme-switch.tsx @@ -1,7 +1,7 @@ import { useForm, getFormProps } from '@conform-to/react' import { parseWithZod } from '@conform-to/zod' import { invariantResponse } from '@epic-web/invariant' -import { json, type ActionFunctionArgs } from '@remix-run/node' +import { data, type ActionFunctionArgs } from '@remix-run/node' import { redirect, useFetcher, useFetchers } from '@remix-run/react' import { ServerOnly } from 'remix-utils/server-only' import { z } from 'zod' @@ -35,7 +35,7 @@ export async function action({ request }: ActionFunctionArgs) { if (redirectTo) { return redirect(redirectTo, responseInit) } else { - return json({ result: submission.reply() }, responseInit) + return data({ result: submission.reply() }, responseInit) } } diff --git a/app/routes/settings+/profile.change-email.server.tsx b/app/routes/settings+/profile.change-email.server.tsx index 0a0eebc0a..675cc617b 100644 --- a/app/routes/settings+/profile.change-email.server.tsx +++ b/app/routes/settings+/profile.change-email.server.tsx @@ -1,6 +1,6 @@ import { invariant } from '@epic-web/invariant' import * as E from '@react-email/components' -import { json } from '@remix-run/node' +import { data } from '@remix-run/node' import { requireRecentVerification, type VerifyFunctionArgs, @@ -26,7 +26,7 @@ export async function handleVerification({ ) const newEmail = verifySession.get(newEmailAddressSessionKey) if (!newEmail) { - return json( + return data( { result: submission.reply({ formErrors: [ diff --git a/app/routes/settings+/profile.change-email.tsx b/app/routes/settings+/profile.change-email.tsx index e68758873..00893a936 100644 --- a/app/routes/settings+/profile.change-email.tsx +++ b/app/routes/settings+/profile.change-email.tsx @@ -2,7 +2,7 @@ import { getFormProps, getInputProps, useForm } from '@conform-to/react' import { getZodConstraint, parseWithZod } from '@conform-to/zod' import { type SEOHandle } from '@nasa-gcn/remix-seo' import { - json, + data, redirect, type ActionFunctionArgs, type LoaderFunctionArgs, @@ -47,7 +47,7 @@ export async function loader({ request }: LoaderFunctionArgs) { const params = new URLSearchParams({ redirectTo: request.url }) throw redirect(`/login?${params}`) } - return json({ user }) + return { user } } export async function action({ request }: ActionFunctionArgs) { @@ -70,7 +70,7 @@ export async function action({ request }: ActionFunctionArgs) { }) if (submission.status !== 'success') { - return json( + return data( { result: submission.reply() }, { status: submission.status === 'error' ? 400 : 200 }, ) @@ -97,7 +97,7 @@ export async function action({ request }: ActionFunctionArgs) { }, }) } else { - return json( + return data( { result: submission.reply({ formErrors: [response.error.message] }) }, { status: 500 }, ) diff --git a/app/routes/settings+/profile.connections.tsx b/app/routes/settings+/profile.connections.tsx index 91c479563..d0f48ef52 100644 --- a/app/routes/settings+/profile.connections.tsx +++ b/app/routes/settings+/profile.connections.tsx @@ -1,7 +1,7 @@ import { invariantResponse } from '@epic-web/invariant' import { type SEOHandle } from '@nasa-gcn/remix-seo' import { - json, + data, type LoaderFunctionArgs, type ActionFunctionArgs, type SerializeFrom, @@ -81,7 +81,7 @@ export async function loader({ request }: LoaderFunctionArgs) { }) } - return json( + return data( { connections, canDeleteConnections: await userCanDeleteConnections(userId), @@ -120,7 +120,7 @@ export async function action({ request }: ActionFunctionArgs) { title: 'Deleted', description: 'Your connection has been deleted.', }) - return json({ status: 'success' } as const, { headers: toastHeaders }) + return data({ status: 'success' } as const, { headers: toastHeaders }) } export default function Connections() { diff --git a/app/routes/settings+/profile.index.tsx b/app/routes/settings+/profile.index.tsx index 380cfa226..65eafda82 100644 --- a/app/routes/settings+/profile.index.tsx +++ b/app/routes/settings+/profile.index.tsx @@ -3,7 +3,7 @@ import { getZodConstraint, parseWithZod } from '@conform-to/zod' import { invariantResponse } from '@epic-web/invariant' import { type SEOHandle } from '@nasa-gcn/remix-seo' import { - json, + data, type LoaderFunctionArgs, type ActionFunctionArgs, } from '@remix-run/node' @@ -64,11 +64,11 @@ export async function loader({ request }: LoaderFunctionArgs) { where: { userId }, }) - return json({ + return { user, hasPassword: Boolean(password), isTwoFactorEnabled: Boolean(twoFactorVerification), - }) + } } type ProfileActionArgs = { @@ -194,26 +194,26 @@ async function profileUpdateAction({ userId, formData }: ProfileActionArgs) { }), }) if (submission.status !== 'success') { - return json( + return data( { result: submission.reply() }, { status: submission.status === 'error' ? 400 : 200 }, ) } - const data = submission.value + const { username, name } = submission.value await prisma.user.update({ select: { username: true }, where: { id: userId }, data: { - name: data.name, - username: data.username, + name: name, + username: username, }, }) - return json({ + return { result: submission.reply(), - }) + } } function UpdateProfile() { @@ -288,7 +288,7 @@ async function signOutOfSessionsAction({ request, userId }: ProfileActionArgs) { id: { not: sessionId }, }, }) - return json({ status: 'success' } as const) + return { status: 'success' } as const } function SignOutOfSessions() { diff --git a/app/routes/settings+/profile.password.tsx b/app/routes/settings+/profile.password.tsx index afdf7af9e..f239936a2 100644 --- a/app/routes/settings+/profile.password.tsx +++ b/app/routes/settings+/profile.password.tsx @@ -2,7 +2,7 @@ import { getFormProps, getInputProps, useForm } from '@conform-to/react' import { getZodConstraint, parseWithZod } from '@conform-to/zod' import { type SEOHandle } from '@nasa-gcn/remix-seo' import { - json, + data, redirect, type LoaderFunctionArgs, type ActionFunctionArgs, @@ -58,7 +58,7 @@ async function requirePassword(userId: string) { export async function loader({ request }: LoaderFunctionArgs) { const userId = await requireUserId(request) await requirePassword(userId) - return json({}) + return {} } export async function action({ request }: ActionFunctionArgs) { @@ -83,7 +83,7 @@ export async function action({ request }: ActionFunctionArgs) { ), }) if (submission.status !== 'success') { - return json( + return data( { result: submission.reply({ hideFields: ['currentPassword', 'newPassword', 'confirmNewPassword'], diff --git a/app/routes/settings+/profile.password_.create.tsx b/app/routes/settings+/profile.password_.create.tsx index 24770f815..ff4bba618 100644 --- a/app/routes/settings+/profile.password_.create.tsx +++ b/app/routes/settings+/profile.password_.create.tsx @@ -2,7 +2,7 @@ import { getFormProps, getInputProps, useForm } from '@conform-to/react' import { getZodConstraint, parseWithZod } from '@conform-to/zod' import { type SEOHandle } from '@nasa-gcn/remix-seo' import { - json, + data, redirect, type LoaderFunctionArgs, type ActionFunctionArgs, @@ -38,7 +38,7 @@ async function requireNoPassword(userId: string) { export async function loader({ request }: LoaderFunctionArgs) { const userId = await requireUserId(request) await requireNoPassword(userId) - return json({}) + return {} } export async function action({ request }: ActionFunctionArgs) { @@ -50,7 +50,7 @@ export async function action({ request }: ActionFunctionArgs) { schema: CreatePasswordForm, }) if (submission.status !== 'success') { - return json( + return data( { result: submission.reply({ hideFields: ['password', 'confirmPassword'], diff --git a/app/routes/settings+/profile.photo.tsx b/app/routes/settings+/profile.photo.tsx index 5a9718bbe..8b0839811 100644 --- a/app/routes/settings+/profile.photo.tsx +++ b/app/routes/settings+/profile.photo.tsx @@ -3,7 +3,7 @@ import { getZodConstraint, parseWithZod } from '@conform-to/zod' import { invariantResponse } from '@epic-web/invariant' import { type SEOHandle } from '@nasa-gcn/remix-seo' import { - json, + data, redirect, unstable_createMemoryUploadHandler, unstable_parseMultipartFormData, @@ -70,7 +70,7 @@ export async function loader({ request }: LoaderFunctionArgs) { }, }) invariantResponse(user, 'User not found', { status: 404 }) - return json({ user }) + return { user } } export async function action({ request }: ActionFunctionArgs) { @@ -96,7 +96,7 @@ export async function action({ request }: ActionFunctionArgs) { }) if (submission.status !== 'success') { - return json( + return data( { result: submission.reply() }, { status: submission.status === 'error' ? 400 : 200 }, ) diff --git a/app/routes/settings+/profile.tsx b/app/routes/settings+/profile.tsx index 711aa90b6..81af9f204 100644 --- a/app/routes/settings+/profile.tsx +++ b/app/routes/settings+/profile.tsx @@ -1,6 +1,6 @@ import { invariantResponse } from '@epic-web/invariant' import { type SEOHandle } from '@nasa-gcn/remix-seo' -import { json, type LoaderFunctionArgs } from '@remix-run/node' +import { type LoaderFunctionArgs } from '@remix-run/node' import { Link, Outlet, useMatches } from '@remix-run/react' import { z } from 'zod' import { Spacer } from '#app/components/spacer.tsx' @@ -25,7 +25,7 @@ export async function loader({ request }: LoaderFunctionArgs) { select: { username: true }, }) invariantResponse(user, 'User not found', { status: 404 }) - return json({}) + return {} } const BreadcrumbHandleMatch = z.object({ diff --git a/app/routes/settings+/profile.two-factor.disable.tsx b/app/routes/settings+/profile.two-factor.disable.tsx index f1530991e..0d012969c 100644 --- a/app/routes/settings+/profile.two-factor.disable.tsx +++ b/app/routes/settings+/profile.two-factor.disable.tsx @@ -1,6 +1,5 @@ import { type SEOHandle } from '@nasa-gcn/remix-seo' import { - json, type LoaderFunctionArgs, type ActionFunctionArgs, } from '@remix-run/node' @@ -22,7 +21,7 @@ export const handle: BreadcrumbHandle & SEOHandle = { export async function loader({ request }: LoaderFunctionArgs) { await requireRecentVerification(request) - return json({}) + return {} } export async function action({ request }: ActionFunctionArgs) { diff --git a/app/routes/settings+/profile.two-factor.index.tsx b/app/routes/settings+/profile.two-factor.index.tsx index b08a29bdf..0f2c55c66 100644 --- a/app/routes/settings+/profile.two-factor.index.tsx +++ b/app/routes/settings+/profile.two-factor.index.tsx @@ -1,6 +1,5 @@ import { type SEOHandle } from '@nasa-gcn/remix-seo' import { - json, redirect, type LoaderFunctionArgs, type ActionFunctionArgs, @@ -24,7 +23,7 @@ export async function loader({ request }: LoaderFunctionArgs) { where: { target_type: { type: twoFAVerificationType, target: userId } }, select: { id: true }, }) - return json({ is2FAEnabled: Boolean(verification) }) + return { is2FAEnabled: Boolean(verification) } } export async function action({ request }: ActionFunctionArgs) { diff --git a/app/routes/settings+/profile.two-factor.verify.tsx b/app/routes/settings+/profile.two-factor.verify.tsx index 8b0f8028f..76c34b7d9 100644 --- a/app/routes/settings+/profile.two-factor.verify.tsx +++ b/app/routes/settings+/profile.two-factor.verify.tsx @@ -2,7 +2,7 @@ import { getFormProps, getInputProps, useForm } from '@conform-to/react' import { getZodConstraint, parseWithZod } from '@conform-to/zod' import { type SEOHandle } from '@nasa-gcn/remix-seo' import { - json, + data, redirect, type LoaderFunctionArgs, type ActionFunctionArgs, @@ -75,7 +75,7 @@ export async function loader({ request }: LoaderFunctionArgs) { issuer, }) const qrCode = await QRCode.toDataURL(otpUri) - return json({ otpUri, qrCode }) + return { otpUri, qrCode } } export async function action({ request }: ActionFunctionArgs) { @@ -104,7 +104,7 @@ export async function action({ request }: ActionFunctionArgs) { }) if (submission.status !== 'success') { - return json( + return data( { result: submission.reply() }, { status: submission.status === 'error' ? 400 : 200 }, ) diff --git a/app/routes/users+/$username.tsx b/app/routes/users+/$username.tsx index 443133b75..8fc5fb5af 100644 --- a/app/routes/users+/$username.tsx +++ b/app/routes/users+/$username.tsx @@ -1,5 +1,5 @@ import { invariantResponse } from '@epic-web/invariant' -import { json, type LoaderFunctionArgs } from '@remix-run/node' +import { type LoaderFunctionArgs } from '@remix-run/node' import { Form, Link, useLoaderData, type MetaFunction } from '@remix-run/react' import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx' import { Spacer } from '#app/components/spacer.tsx' @@ -25,7 +25,7 @@ export async function loader({ params }: LoaderFunctionArgs) { invariantResponse(user, 'User not found', { status: 404 }) - return json({ user, userJoinedDisplay: user.createdAt.toLocaleDateString() }) + return { user, userJoinedDisplay: user.createdAt.toLocaleDateString() } } export default function ProfileRoute() { diff --git a/app/routes/users+/$username_+/__note-editor.server.tsx b/app/routes/users+/$username_+/__note-editor.server.tsx index 8b1796cee..0ccc5410c 100644 --- a/app/routes/users+/$username_+/__note-editor.server.tsx +++ b/app/routes/users+/$username_+/__note-editor.server.tsx @@ -2,7 +2,7 @@ import { parseWithZod } from '@conform-to/zod' import { createId as cuid } from '@paralleldrive/cuid2' import { unstable_createMemoryUploadHandler as createMemoryUploadHandler, - json, + data, unstable_parseMultipartFormData as parseMultipartFormData, redirect, type ActionFunctionArgs, @@ -88,7 +88,7 @@ export async function action({ request }: ActionFunctionArgs) { }) if (submission.status !== 'success') { - return json( + return data( { result: submission.reply() }, { status: submission.status === 'error' ? 400 : 200 }, ) diff --git a/app/routes/users+/$username_+/notes.$noteId.tsx b/app/routes/users+/$username_+/notes.$noteId.tsx index 57e0d3e42..54cd0bd6b 100644 --- a/app/routes/users+/$username_+/notes.$noteId.tsx +++ b/app/routes/users+/$username_+/notes.$noteId.tsx @@ -2,7 +2,7 @@ import { getFormProps, useForm } from '@conform-to/react' import { parseWithZod } from '@conform-to/zod' import { invariantResponse } from '@epic-web/invariant' import { - json, + data, type LoaderFunctionArgs, type ActionFunctionArgs, } from '@remix-run/node' @@ -52,10 +52,7 @@ export async function loader({ params }: LoaderFunctionArgs) { const date = new Date(note.updatedAt) const timeAgo = formatDistanceToNow(date) - return json({ - note, - timeAgo, - }) + return { note, timeAgo } } const DeleteFormSchema = z.object({ @@ -70,7 +67,7 @@ export async function action({ request }: ActionFunctionArgs) { schema: DeleteFormSchema, }) if (submission.status !== 'success') { - return json( + return data( { result: submission.reply() }, { status: submission.status === 'error' ? 400 : 200 }, ) diff --git a/app/routes/users+/$username_+/notes.$noteId_.edit.tsx b/app/routes/users+/$username_+/notes.$noteId_.edit.tsx index 0d1481769..fb12f6027 100644 --- a/app/routes/users+/$username_+/notes.$noteId_.edit.tsx +++ b/app/routes/users+/$username_+/notes.$noteId_.edit.tsx @@ -1,5 +1,5 @@ import { invariantResponse } from '@epic-web/invariant' -import { json, type LoaderFunctionArgs } from '@remix-run/node' +import { type LoaderFunctionArgs } from '@remix-run/node' import { useLoaderData } from '@remix-run/react' import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx' import { requireUserId } from '#app/utils/auth.server.ts' @@ -28,7 +28,7 @@ export async function loader({ params, request }: LoaderFunctionArgs) { }, }) invariantResponse(note, 'Not found', { status: 404 }) - return json({ note: note }) + return { note: note } } export default function NoteEdit() { diff --git a/app/routes/users+/$username_+/notes.new.tsx b/app/routes/users+/$username_+/notes.new.tsx index ecc8580d4..62a0de79b 100644 --- a/app/routes/users+/$username_+/notes.new.tsx +++ b/app/routes/users+/$username_+/notes.new.tsx @@ -1,4 +1,4 @@ -import { json, type LoaderFunctionArgs } from '@remix-run/node' +import { type LoaderFunctionArgs } from '@remix-run/node' import { requireUserId } from '#app/utils/auth.server.ts' import { NoteEditor } from './__note-editor.tsx' @@ -6,7 +6,7 @@ export { action } from './__note-editor.server.tsx' export async function loader({ request }: LoaderFunctionArgs) { await requireUserId(request) - return json({}) + return {} } export default NoteEditor diff --git a/app/routes/users+/$username_+/notes.tsx b/app/routes/users+/$username_+/notes.tsx index 58134a381..3ff8e55b7 100644 --- a/app/routes/users+/$username_+/notes.tsx +++ b/app/routes/users+/$username_+/notes.tsx @@ -1,5 +1,5 @@ import { invariantResponse } from '@epic-web/invariant' -import { json, type LoaderFunctionArgs } from '@remix-run/node' +import { type LoaderFunctionArgs } from '@remix-run/node' import { Link, NavLink, Outlet, useLoaderData } from '@remix-run/react' import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx' import { Icon } from '#app/components/ui/icon.tsx' @@ -21,7 +21,7 @@ export async function loader({ params }: LoaderFunctionArgs) { invariantResponse(owner, 'Owner not found', { status: 404 }) - return json({ owner }) + return { owner } } export default function NotesRoute() { diff --git a/app/routes/users+/index.tsx b/app/routes/users+/index.tsx index c0703327c..7c321af60 100644 --- a/app/routes/users+/index.tsx +++ b/app/routes/users+/index.tsx @@ -1,4 +1,4 @@ -import { json, redirect, type LoaderFunctionArgs } from '@remix-run/node' +import { data, redirect, type LoaderFunctionArgs } from '@remix-run/node' import { Link, useLoaderData } from '@remix-run/react' import { z } from 'zod' import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx' @@ -41,11 +41,11 @@ export async function loader({ request }: LoaderFunctionArgs) { const result = UserSearchResultsSchema.safeParse(rawUsers) if (!result.success) { - return json({ status: 'error', error: result.error.message } as const, { + return data({ status: 'error', error: result.error.message } as const, { status: 400, }) } - return json({ status: 'idle', users: result.data } as const) + return { status: 'idle', users: result.data } as const } export default function UsersRoute() { diff --git a/app/utils/permissions.server.ts b/app/utils/permissions.server.ts index d96fa9164..74aa5aa82 100644 --- a/app/utils/permissions.server.ts +++ b/app/utils/permissions.server.ts @@ -1,4 +1,4 @@ -import { json } from '@remix-run/node' +import { data } from '@remix-run/node' import { requireUserId } from './auth.server.ts' import { prisma } from './db.server.ts' import { type PermissionString, parsePermissionString } from './user.ts' @@ -28,7 +28,7 @@ export async function requireUserWithPermission( }, }) if (!user) { - throw json( + throw data( { error: 'Unauthorized', requiredPermission: permissionData, @@ -47,7 +47,7 @@ export async function requireUserWithRole(request: Request, name: string) { where: { id: userId, roles: { some: { name } } }, }) if (!user) { - throw json( + throw data( { error: 'Unauthorized', requiredRole: name, diff --git a/package-lock.json b/package-lock.json index da348c053..1b1949b95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3802,7 +3802,6 @@ "resolved": "https://registry.npmjs.org/@remix-run/dev/-/dev-2.13.1.tgz", "integrity": "sha512-7+06Dail6zMyRlRvgrZ4cmQjs2gUb+M24iP4jbmql+0B7VAAPwzCRU0x+BF5z8GSef13kDrH3iXv/BQ2O2yOgw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.21.8", "@babel/generator": "^7.21.5", @@ -4607,7 +4606,6 @@ "resolved": "https://registry.npmjs.org/@remix-run/testing/-/testing-2.13.1.tgz", "integrity": "sha512-vbvJx0HS71g3cUzlm+aZ5v2Lf5FbltP0Spv6MsyDMHSWNYV+ciO4w4jTrVuykDZx8seZRbG40M9xDEJuDplegw==", "dev": true, - "license": "MIT", "dependencies": { "@remix-run/node": "2.13.1", "@remix-run/react": "2.13.1", @@ -8514,7 +8512,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -8523,7 +8520,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -8531,8 +8527,7 @@ "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/boolbase": { "version": "1.0.0", @@ -9298,7 +9293,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -9770,7 +9764,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -10333,8 +10326,7 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "node_modules/escape-string-regexp": { "version": "4.0.0", @@ -11048,7 +11040,6 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -11392,7 +11383,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -11400,8 +11390,7 @@ "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/find-up": { "version": "5.0.0", @@ -11517,7 +11506,6 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -12143,7 +12131,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -12208,7 +12195,6 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -13968,7 +13954,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -14674,7 +14659,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", "bin": { "mime": "cli.js" }, @@ -15740,7 +15724,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -16131,7 +16114,6 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -17336,7 +17318,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -17345,7 +17326,6 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -17360,7 +17340,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -18297,7 +18276,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -18305,8 +18283,15 @@ "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } }, "node_modules/send/node_modules/encodeurl": { "version": "1.0.2", @@ -18380,8 +18365,7 @@ "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/shebang-command": { "version": "2.0.0", @@ -19604,7 +19588,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", "engines": { "node": ">=0.6" } @@ -20242,7 +20225,6 @@ "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -20589,7 +20571,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -21832,7 +21813,6 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8.3.0" }, diff --git a/vite.config.ts b/vite.config.ts index ed88e4cbb..0ff2cf83d 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -5,6 +5,12 @@ import { flatRoutes } from 'remix-flat-routes' import { defineConfig } from 'vite' import { envOnlyMacros } from 'vite-env-only' +declare module '@remix-run/server-runtime' { + interface Future { + v3_singleFetch: true + } +} + const MODE = process.env.NODE_ENV export default defineConfig({ @@ -47,6 +53,7 @@ export default defineConfig({ v3_lazyRouteDiscovery: true, v3_relativeSplatPath: true, v3_throwAbortReason: true, + v3_singleFetch: true, }, routes: async (defineRoutes) => { return flatRoutes('routes', defineRoutes, {