Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 3 additions & 2 deletions app/components/error-boundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import {
useRouteError,
} from '@remix-run/react'
import { captureRemixErrorBoundaryError } from '@sentry/remix'
import { type ReactElement } from 'react'
import { getErrorMessage } from '#app/utils/misc.tsx'

type StatusHandler = (info: {
error: ErrorResponse
params: Record<string, string | undefined>
}) => JSX.Element | null
}) => ReactElement | null

export function GeneralErrorBoundary({
defaultStatusHandler = ({ error }) => (
Expand All @@ -23,7 +24,7 @@ export function GeneralErrorBoundary({
}: {
defaultStatusHandler?: StatusHandler
statusHandlers?: Record<number, StatusHandler>
unexpectedErrorHandler?: (error: unknown) => JSX.Element | null
unexpectedErrorHandler?: (error: unknown) => ReactElement | null
}) {
const error = useRouteError()
captureRemixErrorBoundaryError(error)
Expand Down
2 changes: 1 addition & 1 deletion app/components/forms.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ export function CheckboxField({
errors,
className,
}: {
labelProps: JSX.IntrinsicElements['label']
labelProps: React.LabelHTMLAttributes<HTMLLabelElement>
buttonProps: CheckboxProps & {
name: string
form: string
Expand Down
2 changes: 1 addition & 1 deletion app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
await logout({ request, redirectTo: '/' })
}
const { toast, headers: toastHeaders } = await getToast(request)
const honeyProps = honeypot.getInputProps()
const honeyProps = await honeypot.getInputProps()

return json(
{
Expand Down
2 changes: 1 addition & 1 deletion app/routes/_app+/_auth+/forgot-password.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ function getIdentifier({

export async function action({ request }: ActionFunctionArgs) {
const formData = await request.formData()
checkHoneypot(formData)
await checkHoneypot(formData)
const submission = await parseWithZod(formData, {
schema: ForgotPasswordSchema.superRefine(async (data, ctx) => {
const identifier = getIdentifier({ countryCode: data.countryCode, phoneNumber: data.phoneNumber })
Expand Down
2 changes: 1 addition & 1 deletion app/routes/_app+/_auth+/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
export async function action({ request }: ActionFunctionArgs) {
await requireAnonymous(request)
const formData = await request.formData()
checkHoneypot(formData)
await checkHoneypot(formData)
const submission = await parseWithZod(formData, {
schema: (intent) =>
LoginFormSchema.transform(async (data, ctx) => {
Expand Down
2 changes: 1 addition & 1 deletion app/routes/_app+/_auth+/onboarding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
export async function action({ request }: ActionFunctionArgs) {
const phoneNumber = await requireOnboardingPhoneNumber(request)
const formData = await request.formData()
checkHoneypot(formData)
await checkHoneypot(formData)
const submission = await parseWithZod(formData, {
schema: (intent) =>
SignupFormSchema.superRefine(async (data, ctx) => {
Expand Down
2 changes: 1 addition & 1 deletion app/routes/_app+/_auth+/signup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const countryCodes = [
export async function action({ request }: ActionFunctionArgs) {
const formData = await request.formData()

checkHoneypot(formData)
await checkHoneypot(formData)

const submission = await parseWithZod(formData, {
schema: SignupSchema.superRefine(async (data, ctx) => {
Expand Down
2 changes: 1 addition & 1 deletion app/routes/_app+/_auth+/verify.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const VerifySchema = z.object({

export async function action({ request }: ActionFunctionArgs) {
const formData = await request.formData()
checkHoneypot(formData)
await checkHoneypot(formData)
return validateRequest(request, formData)
}

Expand Down
4 changes: 2 additions & 2 deletions app/utils/cron.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* it gets us.
*/
import { remember } from '@epic-web/remember'
import cronParser from 'cron-parser'
import { CronExpressionParser } from 'cron-parser'
import {
clearIntervalAsync,
setIntervalAsync,
Expand All @@ -24,7 +24,7 @@ export class CronParseError extends Error {

function parseCronExpression(cronString: string, options?: { tz?: string }) {
try {
return cronParser.parseExpression(cronString, options)
return CronExpressionParser.parse(cronString, options)
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : 'Invalid cron string'
Expand Down
4 changes: 2 additions & 2 deletions app/utils/cron.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import cronParser from 'cron-parser'
import { CronExpressionParser } from 'cron-parser'

export function validateCronString(cronString: string): {
valid: boolean
error?: string
} {
try {
cronParser.parseExpression(cronString)
CronExpressionParser.parse(cronString)
return { valid: true }
} catch (error) {
const errorMessage =
Expand Down
4 changes: 2 additions & 2 deletions app/utils/honeypot.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ export const honeypot = new Honeypot({
encryptionSeed: process.env.HONEYPOT_SECRET,
})

export function checkHoneypot(formData: FormData) {
export async function checkHoneypot(formData: FormData) {
try {
honeypot.check(formData)
await honeypot.check(formData)
} catch (error) {
if (error instanceof SpamError) {
throw new Response('Form not submitted properly', { status: 400 })
Expand Down
2 changes: 1 addition & 1 deletion app/utils/litefs.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ export {
getInternalInstanceDomain,
getInstanceInfoSync,
} from 'litefs-js'
export { ensurePrimary, ensureInstance } from 'litefs-js/remix.js'
export { ensurePrimary, ensureInstance } from 'litefs-js/remix'
10 changes: 7 additions & 3 deletions app/utils/misc.use-double-check.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function TestComponent({ safeDelayMs = 0 }: { safeDelayMs?: number }) {

test('prevents default on the first click, and does not on the second', async () => {
const user = userEvent.setup()
render(<TestComponent safeDelayMs={50} />)
render(<TestComponent safeDelayMs={200} />)

const status = screen.getByRole('status')
const button = screen.getByRole('button')
Expand All @@ -40,13 +40,17 @@ test('prevents default on the first click, and does not on the second', async ()
await user.click(button)
expect(button).toHaveTextContent('You sure?')
expect(status).toHaveTextContent('Default Prevented: yes')
expect(button).toHaveAttribute('data-safe-delay', 'true')
await waitFor(() =>
expect(button).toHaveAttribute('data-safe-delay', 'true'),
)

// clicking it during the safe delay does nothing
await user.click(button)
expect(button).toHaveTextContent('You sure?')
expect(status).toHaveTextContent('Default Prevented: yes')
expect(button).toHaveAttribute('data-safe-delay', 'true')
await waitFor(() =>
expect(button).toHaveAttribute('data-safe-delay', 'true'),
)

await waitFor(() =>
expect(button).toHaveAttribute('data-safe-delay', 'false'),
Expand Down
Loading
Loading