Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
946a718
chore: update dependencies
cursoragent Jan 21, 2026
0f0dce6
chore: switch conform zod v4 imports
cursoragent Jan 21, 2026
e6d4368
test: increase Playwright web server timeout
cursoragent Jan 21, 2026
a0156a9
fix: update express wildcard route
cursoragent Jan 21, 2026
d2c5124
fix: update express static wildcard routes
cursoragent Jan 21, 2026
226e7cc
fix: update rate limit key generator
cursoragent Jan 21, 2026
d9f77c1
fix: adjust prisma client import
cursoragent Jan 21, 2026
1eba322
chore: configure prisma v7 adapter
cursoragent Jan 21, 2026
4aecaf8
fix: sanitize sqlite adapter url
cursoragent Jan 21, 2026
561ba32
test: pass env vars to web server
cursoragent Jan 21, 2026
2dff24a
chore: add prisma seed config
cursoragent Jan 21, 2026
2eaa113
fix: validate onboarding terms checkbox
cursoragent Jan 21, 2026
eb7cba0
fix: ensure react-router plugin during build
cursoragent Jan 21, 2026
2f8e7dc
fix: align onboarding terms and user search
cursoragent Jan 21, 2026
e2e9f82
fix: keep typed search query with sqlite params
cursoragent Jan 21, 2026
7b58abd
fix: preserve username constraints with required errors
cursoragent Jan 21, 2026
3070b9e
fix: align typed sql params for sqlite
cursoragent Jan 21, 2026
09e3b20
fix: load dotenv in prisma config
cursoragent Jan 21, 2026
8f8b7dc
fix: resolve prisma reset and typecheck errors
cursoragent Jan 22, 2026
b3224a5
fix: handle missing request ip
cursoragent Jan 22, 2026
28fc40a
fix: update prisma reset flags for vitest
cursoragent Jan 22, 2026
6d5e6b0
fix: correct prisma reset command args
cursoragent Jan 22, 2026
1d6e404
fix: use migrate deploy for test setup
cursoragent Jan 22, 2026
19354db
fix: drop cache server import in test setup
cursoragent Jan 22, 2026
9b7fb27
fix: lazy-load node sqlite in cache
cursoragent Jan 22, 2026
468ed86
fix: use memory cache in tests
cursoragent Jan 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 14 additions & 16 deletions app/routes/_auth/auth.$provider/callback.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ import { loader } from './callback.ts'

const ROUTE_PATH = '/auth/github/callback'
const PARAMS = { provider: 'github' }
const UNSTABLE_PATTERN = '/auth/:provider/callback'
const baseLoaderArgs = {
params: PARAMS,
context: {} as AppLoadContext,
unstable_pattern: UNSTABLE_PATTERN,
}

afterEach(async () => {
await deleteGitHubUsers()
Expand All @@ -28,8 +34,7 @@ test('a new user goes to onboarding', async () => {
const request = await setupRequest()
const response = await loader({
request,
params: PARAMS,
context: {} as AppLoadContext,
...baseLoaderArgs,
}).catch((e) => e)
expect(response).toHaveRedirect('/onboarding/github')
})
Expand All @@ -44,8 +49,7 @@ test('when auth fails, send the user to login with a toast', async () => {
const request = await setupRequest()
const response = await loader({
request,
params: PARAMS,
context: {} as AppLoadContext,
...baseLoaderArgs,
}).catch((e) => e)
invariant(response instanceof Response, 'response should be a Response')
expect(response).toHaveRedirect('/login')
Expand All @@ -67,8 +71,7 @@ test('when a user is logged in, it creates the connection', async () => {
})
const response = await loader({
request,
params: PARAMS,
context: {} as AppLoadContext,
...baseLoaderArgs,
})
expect(response).toHaveRedirect('/settings/profile/connections')
await expect(response).toSendToast(
Expand Down Expand Up @@ -107,8 +110,7 @@ test(`when a user is logged in and has already connected, it doesn't do anything
})
const response = await loader({
request,
params: PARAMS,
context: {} as AppLoadContext,
...baseLoaderArgs,
})
expect(response).toHaveRedirect('/settings/profile/connections')
await expect(response).toSendToast(
Expand All @@ -126,8 +128,7 @@ test('when a user exists with the same email, create connection and make session
const request = await setupRequest({ code: githubUser.code })
const response = await loader({
request,
params: PARAMS,
context: {} as AppLoadContext,
...baseLoaderArgs,
})

expect(response).toHaveRedirect('/')
Expand Down Expand Up @@ -174,8 +175,7 @@ test('gives an error if the account is already connected to another user', async
})
const response = await loader({
request,
params: PARAMS,
context: {} as AppLoadContext,
...baseLoaderArgs,
})
expect(response).toHaveRedirect('/settings/profile/connections')
await expect(response).toSendToast(
Expand All @@ -201,8 +201,7 @@ test('if a user is not logged in, but the connection exists, make a session', as
const request = await setupRequest({ code: githubUser.code })
const response = await loader({
request,
params: PARAMS,
context: {} as AppLoadContext,
...baseLoaderArgs,
})
expect(response).toHaveRedirect('/')
await expect(response).toHaveSessionForUser(userId)
Expand All @@ -229,8 +228,7 @@ test('if a user is not logged in, but the connection exists and they have enable
const request = await setupRequest({ code: githubUser.code })
const response = await loader({
request,
params: PARAMS,
context: {} as AppLoadContext,
...baseLoaderArgs,
})
const searchParams = new URLSearchParams({
type: twoFAVerificationType,
Expand Down
2 changes: 1 addition & 1 deletion app/routes/_auth/forgot-password.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getFormProps, getInputProps, useForm } from '@conform-to/react'
import { getZodConstraint, parseWithZod } from '@conform-to/zod'
import { getZodConstraint, parseWithZod } from '@conform-to/zod/v4'
import { type SEOHandle } from '@nasa-gcn/remix-seo'
import * as E from '@react-email/components'
import { data, redirect, Link, useFetcher } from 'react-router'
Expand Down
2 changes: 1 addition & 1 deletion app/routes/_auth/login.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getFormProps, getInputProps, useForm } from '@conform-to/react'
import { getZodConstraint, parseWithZod } from '@conform-to/zod'
import { getZodConstraint, parseWithZod } from '@conform-to/zod/v4'
import { type SEOHandle } from '@nasa-gcn/remix-seo'
import { startAuthentication } from '@simplewebauthn/browser'
import { useOptimistic, useState, useTransition } from 'react'
Expand Down
11 changes: 7 additions & 4 deletions app/routes/_auth/onboarding/$provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
useForm,
type SubmissionResult,
} from '@conform-to/react'
import { getZodConstraint, parseWithZod } from '@conform-to/zod'
import { getZodConstraint, parseWithZod } from '@conform-to/zod/v4'
import {
redirect,
data,
Expand Down Expand Up @@ -39,9 +39,12 @@ const SignupFormSchema = z.object({
imageUrl: z.string().optional(),
username: UsernameSchema,
name: NameSchema,
agreeToTermsOfServiceAndPrivacyPolicy: z.boolean({
required_error: 'You must agree to the terms of service and privacy policy',
}),
agreeToTermsOfServiceAndPrivacyPolicy: z
.coerce
.boolean()
.refine((value) => value, {
message: 'You must agree to the terms of service and privacy policy',
}),
remember: z.boolean().optional(),
redirectTo: z.string().optional(),
})
Expand Down
12 changes: 7 additions & 5 deletions app/routes/_auth/onboarding/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getFormProps, getInputProps, useForm } from '@conform-to/react'
import { getZodConstraint, parseWithZod } from '@conform-to/zod'
import { getZodConstraint, parseWithZod } from '@conform-to/zod/v4'
import { data, redirect, Form, useSearchParams } from 'react-router'
import { HoneypotInputs } from 'remix-utils/honeypot/react'
import { safeRedirect } from 'remix-utils/safe-redirect'
Expand Down Expand Up @@ -32,10 +32,12 @@ const SignupFormSchema = z
.object({
username: UsernameSchema,
name: NameSchema,
agreeToTermsOfServiceAndPrivacyPolicy: z.boolean({
required_error:
'You must agree to the terms of service and privacy policy',
}),
agreeToTermsOfServiceAndPrivacyPolicy: z
.coerce
.boolean()
.refine((value) => value, {
message: 'You must agree to the terms of service and privacy policy',
}),
remember: z.boolean().optional(),
redirectTo: z.string().optional(),
})
Expand Down
2 changes: 1 addition & 1 deletion app/routes/_auth/reset-password.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getFormProps, getInputProps, useForm } from '@conform-to/react'
import { getZodConstraint, parseWithZod } from '@conform-to/zod'
import { getZodConstraint, parseWithZod } from '@conform-to/zod/v4'
import { type SEOHandle } from '@nasa-gcn/remix-seo'
import { data, redirect, Form } from 'react-router'
import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'
Expand Down
2 changes: 1 addition & 1 deletion app/routes/_auth/signup.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getFormProps, getInputProps, useForm } from '@conform-to/react'
import { getZodConstraint, parseWithZod } from '@conform-to/zod'
import { getZodConstraint, parseWithZod } from '@conform-to/zod/v4'
import { type SEOHandle } from '@nasa-gcn/remix-seo'
import * as E from '@react-email/components'
import { data, redirect, Form, useSearchParams } from 'react-router'
Expand Down
2 changes: 1 addition & 1 deletion app/routes/_auth/verify.server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type Submission } from '@conform-to/react'
import { parseWithZod } from '@conform-to/zod'
import { parseWithZod } from '@conform-to/zod/v4'
import { data } from 'react-router'
import { z } from 'zod'
import { handleVerification as handleChangeEmailVerification } from '#app/routes/settings/profile/change-email.server.tsx'
Expand Down
2 changes: 1 addition & 1 deletion app/routes/_auth/verify.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getFormProps, getInputProps, useForm } from '@conform-to/react'
import { getZodConstraint, parseWithZod } from '@conform-to/zod'
import { getZodConstraint, parseWithZod } from '@conform-to/zod/v4'
import { type SEOHandle } from '@nasa-gcn/remix-seo'
import { Form, useSearchParams } from 'react-router'
import { HoneypotInputs } from 'remix-utils/honeypot/react'
Expand Down
2 changes: 1 addition & 1 deletion app/routes/resources/theme-switch.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useForm, getFormProps } from '@conform-to/react'
import { parseWithZod } from '@conform-to/zod'
import { parseWithZod } from '@conform-to/zod/v4'
import { invariantResponse } from '@epic-web/invariant'
import { data, redirect, useFetcher, useFetchers } from 'react-router'
import { ServerOnly } from 'remix-utils/server-only'
Expand Down
2 changes: 1 addition & 1 deletion app/routes/settings/profile/change-email.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getFormProps, getInputProps, useForm } from '@conform-to/react'
import { getZodConstraint, parseWithZod } from '@conform-to/zod'
import { getZodConstraint, parseWithZod } from '@conform-to/zod/v4'
import { type SEOHandle } from '@nasa-gcn/remix-seo'
import { data, redirect, Form } from 'react-router'
import { z } from 'zod'
Expand Down
2 changes: 1 addition & 1 deletion app/routes/settings/profile/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getFormProps, getInputProps, useForm } from '@conform-to/react'
import { getZodConstraint, parseWithZod } from '@conform-to/zod'
import { getZodConstraint, parseWithZod } from '@conform-to/zod/v4'
import { invariantResponse } from '@epic-web/invariant'
import { type SEOHandle } from '@nasa-gcn/remix-seo'
import { Img } from 'openimg/react'
Expand Down
2 changes: 1 addition & 1 deletion app/routes/settings/profile/password.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getFormProps, getInputProps, useForm } from '@conform-to/react'
import { getZodConstraint, parseWithZod } from '@conform-to/zod'
import { getZodConstraint, parseWithZod } from '@conform-to/zod/v4'
import { type SEOHandle } from '@nasa-gcn/remix-seo'
import { data, redirect, Form, Link } from 'react-router'
import { z } from 'zod'
Expand Down
2 changes: 1 addition & 1 deletion app/routes/settings/profile/password_.create.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getFormProps, getInputProps, useForm } from '@conform-to/react'
import { getZodConstraint, parseWithZod } from '@conform-to/zod'
import { getZodConstraint, parseWithZod } from '@conform-to/zod/v4'
import { type SEOHandle } from '@nasa-gcn/remix-seo'
import { data, redirect, Form, Link } from 'react-router'
import { ErrorList, Field } from '#app/components/forms.tsx'
Expand Down
2 changes: 1 addition & 1 deletion app/routes/settings/profile/photo.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getFormProps, getInputProps, useForm } from '@conform-to/react'
import { getZodConstraint, parseWithZod } from '@conform-to/zod'
import { getZodConstraint, parseWithZod } from '@conform-to/zod/v4'
import { invariantResponse } from '@epic-web/invariant'
import { parseFormData } from '@mjackson/form-data-parser'
import { type SEOHandle } from '@nasa-gcn/remix-seo'
Expand Down
4 changes: 2 additions & 2 deletions app/routes/settings/profile/two-factor/verify.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getFormProps, getInputProps, useForm } from '@conform-to/react'
import { getZodConstraint, parseWithZod } from '@conform-to/zod'
import { getZodConstraint, parseWithZod } from '@conform-to/zod/v4'
import { type SEOHandle } from '@nasa-gcn/remix-seo'
import * as QRCode from 'qrcode'
import { data, redirect, Form, useNavigation } from 'react-router'
Expand Down Expand Up @@ -73,7 +73,7 @@ export async function action({ request }: Route.ActionArgs) {
const submission = await parseWithZod(formData, {
schema: () =>
ActionSchema.superRefine(async (data, ctx) => {
if (data.intent === 'cancel') return null
if (data.intent === 'cancel') return
const codeIsValid = await isCodeValid({
code: data.code,
type: twoFAVerifyVerificationType,
Expand Down
2 changes: 1 addition & 1 deletion app/routes/users/$username/notes/$noteId.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getFormProps, useForm } from '@conform-to/react'
import { parseWithZod } from '@conform-to/zod'
import { parseWithZod } from '@conform-to/zod/v4'
import { invariantResponse } from '@epic-web/invariant'
import { formatDistanceToNow } from 'date-fns'
import { Img } from 'openimg/react'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { parseWithZod } from '@conform-to/zod'
import { parseWithZod } from '@conform-to/zod/v4'
import { parseFormData } from '@mjackson/form-data-parser'
import { createId as cuid } from '@paralleldrive/cuid2'
import { data, redirect, type ActionFunctionArgs } from 'react-router'
Expand Down
2 changes: 1 addition & 1 deletion app/routes/users/$username/notes/+shared/note-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
useForm,
type FieldMetadata,
} from '@conform-to/react'
import { getZodConstraint, parseWithZod } from '@conform-to/zod'
import { getZodConstraint, parseWithZod } from '@conform-to/zod/v4'
import { Img } from 'openimg/react'
import { useState } from 'react'
import { Form } from 'react-router'
Expand Down
2 changes: 1 addition & 1 deletion app/routes/users/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export async function loader({ request }: Route.LoaderArgs) {
}

const like = `%${searchTerm ?? ''}%`
const users = await prisma.$queryRawTyped(searchUsers(like))
const users = await prisma.$queryRawTyped(searchUsers(like, like))
return { status: 'idle', users } as const
}

Expand Down
Loading
Loading