diff --git a/app/routes/_seo+/robots[.]txt.ts b/app/routes/_seo+/robots[.]txt.ts index 2abd727d..f252528f 100644 --- a/app/routes/_seo+/robots[.]txt.ts +++ b/app/routes/_seo+/robots[.]txt.ts @@ -1,9 +1,9 @@ import { generateRobotsTxt } from '@nasa-gcn/remix-seo' import { type DataFunctionArgs } from '@remix-run/node' +import { getDomainUrl } from '#app/utils/misc.tsx' export function loader({ request }: DataFunctionArgs) { - const origin = new URL(request.url).origin return generateRobotsTxt([ - { type: 'sitemap', value: `${origin}/sitemap.xml` }, + { type: 'sitemap', value: `${getDomainUrl(request)}/sitemap.xml` }, ]) } diff --git a/app/routes/_seo+/sitemap[.]xml.ts b/app/routes/_seo+/sitemap[.]xml.ts index 98d61b38..d490b0fa 100644 --- a/app/routes/_seo+/sitemap[.]xml.ts +++ b/app/routes/_seo+/sitemap[.]xml.ts @@ -1,10 +1,12 @@ import { generateSitemap } from '@nasa-gcn/remix-seo' +// @ts-expect-error - this does work, though it's not exactly a public API import { routes } from '@remix-run/dev/server-build' -import { type LoaderFunctionArgs } from '@remix-run/node' +import { type DataFunctionArgs } from '@remix-run/node' +import { getDomainUrl } from '#app/utils/misc.tsx' -export function loader({ request }: LoaderFunctionArgs) { +export function loader({ request }: DataFunctionArgs) { return generateSitemap(request, routes, { - siteUrl: new URL(request.url).origin, + siteUrl: getDomainUrl(request), headers: { 'Cache-Control': `public, max-age=${60 * 5}`, }, diff --git a/app/routes/admin+/cache.tsx b/app/routes/admin+/cache.tsx index 403dc63a..7e836c9b 100644 --- a/app/routes/admin+/cache.tsx +++ b/app/routes/admin+/cache.tsx @@ -1,3 +1,4 @@ +import { type SEOHandle } from '@nasa-gcn/remix-seo' import { json, redirect, type DataFunctionArgs } from '@remix-run/node' import { Form, @@ -28,6 +29,10 @@ import { } from '#app/utils/misc.tsx' import { requireUserWithRole } from '#app/utils/permissions.ts' +export const handle: SEOHandle = { + getSitemapEntries: () => null, +} + export async function loader({ request }: DataFunctionArgs) { await requireUserWithRole(request, 'admin') const searchParams = new URL(request.url).searchParams diff --git a/app/routes/settings+/profile.change-email.tsx b/app/routes/settings+/profile.change-email.tsx index 2a94ff99..c1684975 100644 --- a/app/routes/settings+/profile.change-email.tsx +++ b/app/routes/settings+/profile.change-email.tsx @@ -1,5 +1,6 @@ import { conform, useForm } from '@conform-to/react' import { getFieldsetConstraint, parse } from '@conform-to/zod' +import { type SEOHandle } from '@nasa-gcn/remix-seo' import * as E from '@react-email/components' import { json, redirect, type DataFunctionArgs } from '@remix-run/node' import { Form, useActionData, useLoaderData } from '@remix-run/react' @@ -19,9 +20,11 @@ import { invariant, useIsPending } from '#app/utils/misc.tsx' import { redirectWithToast } from '#app/utils/toast.server.ts' import { EmailSchema } from '#app/utils/user-validation.ts' import { verifySessionStorage } from '#app/utils/verification.server.ts' +import { type BreadcrumbHandle } from './profile.tsx' -export const handle = { +export const handle: BreadcrumbHandle & SEOHandle = { breadcrumb: Change Email, + getSitemapEntries: () => null, } const newEmailAddressSessionKey = 'new-email-address' diff --git a/app/routes/settings+/profile.connections.tsx b/app/routes/settings+/profile.connections.tsx index d09565d9..5ad946eb 100644 --- a/app/routes/settings+/profile.connections.tsx +++ b/app/routes/settings+/profile.connections.tsx @@ -1,3 +1,4 @@ +import { type SEOHandle } from '@nasa-gcn/remix-seo' import { json, type DataFunctionArgs, @@ -17,7 +18,7 @@ import { requireUserId } from '#app/utils/auth.server.ts' import { resolveConnectionData } from '#app/utils/connections.server.ts' import { ProviderConnectionForm, - ProviderName, + type ProviderName, ProviderNameSchema, providerIcons, providerNames, @@ -25,9 +26,11 @@ import { import { prisma } from '#app/utils/db.server.ts' import { invariantResponse } from '#app/utils/misc.tsx' import { createToastHeaders } from '#app/utils/toast.server.ts' +import { type BreadcrumbHandle } from './profile.tsx' -export const handle = { +export const handle: BreadcrumbHandle & SEOHandle = { breadcrumb: Connections, + getSitemapEntries: () => null, } async function userCanDeleteConnections(userId: string) { diff --git a/app/routes/settings+/profile.index.tsx b/app/routes/settings+/profile.index.tsx index 92734338..d97b8999 100644 --- a/app/routes/settings+/profile.index.tsx +++ b/app/routes/settings+/profile.index.tsx @@ -1,5 +1,6 @@ import { conform, useForm } from '@conform-to/react' import { getFieldsetConstraint, parse } from '@conform-to/zod' +import { type SEOHandle } from '@nasa-gcn/remix-seo' import { json, redirect, type DataFunctionArgs } from '@remix-run/node' import { Link, useFetcher, useLoaderData } from '@remix-run/react' import { z } from 'zod' @@ -18,6 +19,10 @@ import { sessionStorage } from '#app/utils/session.server.ts' import { NameSchema, UsernameSchema } from '#app/utils/user-validation.ts' import { twoFAVerificationType } from './profile.two-factor.tsx' +export const handle: SEOHandle = { + getSitemapEntries: () => null, +} + const ProfileFormSchema = z.object({ name: NameSchema.optional(), username: UsernameSchema, diff --git a/app/routes/settings+/profile.password.tsx b/app/routes/settings+/profile.password.tsx index 5dcf6cf9..de82a77d 100644 --- a/app/routes/settings+/profile.password.tsx +++ b/app/routes/settings+/profile.password.tsx @@ -1,5 +1,6 @@ import { conform, useForm } from '@conform-to/react' import { getFieldsetConstraint, parse } from '@conform-to/zod' +import { type SEOHandle } from '@nasa-gcn/remix-seo' import { json, redirect, type DataFunctionArgs } from '@remix-run/node' import { Form, Link, useActionData } from '@remix-run/react' import { z } from 'zod' @@ -16,9 +17,11 @@ import { prisma } from '#app/utils/db.server.ts' import { useIsPending } from '#app/utils/misc.tsx' import { redirectWithToast } from '#app/utils/toast.server.ts' import { PasswordSchema } from '#app/utils/user-validation.ts' +import { type BreadcrumbHandle } from './profile.tsx' -export const handle = { +export const handle: BreadcrumbHandle & SEOHandle = { breadcrumb: Password, + getSitemapEntries: () => null, } const ChangePasswordForm = z diff --git a/app/routes/settings+/profile.password_.create.tsx b/app/routes/settings+/profile.password_.create.tsx index e5bc636e..befb2cee 100644 --- a/app/routes/settings+/profile.password_.create.tsx +++ b/app/routes/settings+/profile.password_.create.tsx @@ -1,5 +1,6 @@ import { conform, useForm } from '@conform-to/react' import { getFieldsetConstraint, parse } from '@conform-to/zod' +import { type SEOHandle } from '@nasa-gcn/remix-seo' import { json, redirect, type DataFunctionArgs } from '@remix-run/node' import { Form, Link, useActionData } from '@remix-run/react' import { z } from 'zod' @@ -11,9 +12,11 @@ import { getPasswordHash, requireUserId } from '#app/utils/auth.server.ts' import { prisma } from '#app/utils/db.server.ts' import { useIsPending } from '#app/utils/misc.tsx' import { PasswordSchema } from '#app/utils/user-validation.ts' +import { type BreadcrumbHandle } from './profile.tsx' -export const handle = { +export const handle: BreadcrumbHandle & SEOHandle = { breadcrumb: Password, + getSitemapEntries: () => null, } const CreatePasswordForm = z diff --git a/app/routes/settings+/profile.photo.tsx b/app/routes/settings+/profile.photo.tsx index 5fc95aa6..9b6337f7 100644 --- a/app/routes/settings+/profile.photo.tsx +++ b/app/routes/settings+/profile.photo.tsx @@ -1,5 +1,6 @@ import { conform, useForm } from '@conform-to/react' import { getFieldsetConstraint, parse } from '@conform-to/zod' +import { type SEOHandle } from '@nasa-gcn/remix-seo' import { json, redirect, @@ -23,9 +24,11 @@ import { useDoubleCheck, useIsPending, } from '#app/utils/misc.tsx' +import { type BreadcrumbHandle } from './profile.tsx' -export const handle = { +export const handle: BreadcrumbHandle & SEOHandle = { breadcrumb: Photo, + getSitemapEntries: () => null, } const MAX_SIZE = 1024 * 1024 * 3 // 3MB diff --git a/app/routes/settings+/profile.tsx b/app/routes/settings+/profile.tsx index 09f7df2d..fc4102e7 100644 --- a/app/routes/settings+/profile.tsx +++ b/app/routes/settings+/profile.tsx @@ -1,3 +1,4 @@ +import { type SEOHandle } from '@nasa-gcn/remix-seo' import { json, type DataFunctionArgs } from '@remix-run/node' import { Link, Outlet, useMatches } from '@remix-run/react' import { z } from 'zod' @@ -8,8 +9,12 @@ import { prisma } from '#app/utils/db.server.ts' import { cn, invariantResponse } from '#app/utils/misc.tsx' import { useUser } from '#app/utils/user.ts' -export const handle = { +export const BreadcrumbHandle = z.object({ breadcrumb: z.any() }) +export type BreadcrumbHandle = z.infer + +export const handle: BreadcrumbHandle & SEOHandle = { breadcrumb: Edit Profile, + getSitemapEntries: () => null, } export async function loader({ request }: DataFunctionArgs) { @@ -23,7 +28,7 @@ export async function loader({ request }: DataFunctionArgs) { } const BreadcrumbHandleMatch = z.object({ - handle: z.object({ breadcrumb: z.any() }), + handle: BreadcrumbHandle, }) export default function EditUserProfile() { diff --git a/app/routes/settings+/profile.two-factor.disable.tsx b/app/routes/settings+/profile.two-factor.disable.tsx index 1b627f86..b6e5d255 100644 --- a/app/routes/settings+/profile.two-factor.disable.tsx +++ b/app/routes/settings+/profile.two-factor.disable.tsx @@ -1,3 +1,4 @@ +import { type SEOHandle } from '@nasa-gcn/remix-seo' import { json, type DataFunctionArgs } from '@remix-run/node' import { useFetcher } from '@remix-run/react' import { Icon } from '#app/components/ui/icon.tsx' @@ -7,10 +8,12 @@ import { requireUserId } from '#app/utils/auth.server.ts' import { prisma } from '#app/utils/db.server.ts' import { useDoubleCheck } from '#app/utils/misc.tsx' import { redirectWithToast } from '#app/utils/toast.server.ts' +import { type BreadcrumbHandle } from './profile.tsx' import { twoFAVerificationType } from './profile.two-factor.tsx' -export const handle = { +export const handle: BreadcrumbHandle & SEOHandle = { breadcrumb: Disable, + getSitemapEntries: () => null, } export async function loader({ request }: DataFunctionArgs) { diff --git a/app/routes/settings+/profile.two-factor.index.tsx b/app/routes/settings+/profile.two-factor.index.tsx index 22c92259..bb0cd155 100644 --- a/app/routes/settings+/profile.two-factor.index.tsx +++ b/app/routes/settings+/profile.two-factor.index.tsx @@ -1,4 +1,5 @@ import { generateTOTP } from '@epic-web/totp' +import { SEOHandle } from '@nasa-gcn/remix-seo' import { json, redirect, type DataFunctionArgs } from '@remix-run/node' import { Link, useFetcher, useLoaderData } from '@remix-run/react' import { Icon } from '#app/components/ui/icon.tsx' @@ -8,6 +9,10 @@ import { prisma } from '#app/utils/db.server.ts' import { twoFAVerificationType } from './profile.two-factor.tsx' import { twoFAVerifyVerificationType } from './profile.two-factor.verify.tsx' +export const handle: SEOHandle = { + getSitemapEntries: () => null, +} + export async function loader({ request }: DataFunctionArgs) { const userId = await requireUserId(request) const verification = await prisma.verification.findUnique({ diff --git a/app/routes/settings+/profile.two-factor.tsx b/app/routes/settings+/profile.two-factor.tsx index ae3eb614..7f5dfd19 100644 --- a/app/routes/settings+/profile.two-factor.tsx +++ b/app/routes/settings+/profile.two-factor.tsx @@ -1,9 +1,12 @@ +import { type SEOHandle } from '@nasa-gcn/remix-seo' import { Outlet } from '@remix-run/react' import { Icon } from '#app/components/ui/icon.tsx' import { type VerificationTypes } from '#app/routes/_auth+/verify.tsx' +import { type BreadcrumbHandle } from './profile.tsx' -export const handle = { +export const handle: BreadcrumbHandle & SEOHandle = { breadcrumb: 2FA, + getSitemapEntries: () => null, } export const twoFAVerificationType = '2fa' satisfies VerificationTypes diff --git a/app/routes/settings+/profile.two-factor.verify.tsx b/app/routes/settings+/profile.two-factor.verify.tsx index 71a4f484..04829828 100644 --- a/app/routes/settings+/profile.two-factor.verify.tsx +++ b/app/routes/settings+/profile.two-factor.verify.tsx @@ -1,6 +1,7 @@ import { conform, useForm } from '@conform-to/react' import { getFieldsetConstraint, parse } from '@conform-to/zod' import { getTOTPAuthUri } from '@epic-web/totp' +import { type SEOHandle } from '@nasa-gcn/remix-seo' import { json, redirect, type DataFunctionArgs } from '@remix-run/node' import { Form, @@ -18,10 +19,12 @@ import { requireUserId } from '#app/utils/auth.server.ts' import { prisma } from '#app/utils/db.server.ts' import { getDomainUrl, useIsPending } from '#app/utils/misc.tsx' import { redirectWithToast } from '#app/utils/toast.server.ts' +import { type BreadcrumbHandle } from './profile.tsx' import { twoFAVerificationType } from './profile.two-factor.tsx' -export const handle = { +export const handle: BreadcrumbHandle & SEOHandle = { breadcrumb: Verify, + getSitemapEntries: () => null, } const VerifySchema = z.object({ diff --git a/public/robots.txt b/public/robots.txt deleted file mode 100644 index c2a49f4f..00000000 --- a/public/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Allow: /