diff --git a/.eslintrc.cjs b/.eslintrc.cjs index c963d6310..4071bf8b5 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -32,6 +32,7 @@ module.exports = { 'sibling', 'index', ], + pathGroups: [{ pattern: '#*/**', group: 'internal' }], }, ], }, diff --git a/app/components/error-boundary.tsx b/app/components/error-boundary.tsx index 03bedd72c..12175f31c 100644 --- a/app/components/error-boundary.tsx +++ b/app/components/error-boundary.tsx @@ -4,7 +4,7 @@ import { useRouteError, } from '@remix-run/react' import { type ErrorResponse } from '@remix-run/router' -import { getErrorMessage } from '../utils/misc.tsx' +import { getErrorMessage } from '#app/utils/misc.tsx' type StatusHandler = (info: { error: ErrorResponse diff --git a/app/components/search-bar.tsx b/app/components/search-bar.tsx index 93023e694..859c52d65 100644 --- a/app/components/search-bar.tsx +++ b/app/components/search-bar.tsx @@ -1,5 +1,5 @@ import { Form, useSearchParams, useSubmit } from '@remix-run/react' -import { useDebounce, useIsPending } from '../utils/misc.tsx' +import { useDebounce, useIsPending } from '#app/utils/misc.tsx' import { Icon } from './ui/icon.tsx' import { Input } from './ui/input.tsx' import { Label } from './ui/label.tsx' diff --git a/app/components/toaster.tsx b/app/components/toaster.tsx index c0761a2fa..621253038 100644 --- a/app/components/toaster.tsx +++ b/app/components/toaster.tsx @@ -1,6 +1,6 @@ import { useEffect } from 'react' import { Toaster, toast as showToast } from 'sonner' -import { type Toast } from '../utils/toast.server.ts' +import { type Toast } from '#app/utils/toast.server.ts' export function EpicToaster({ toast }: { toast?: Toast | null }) { return ( diff --git a/app/components/ui/button.tsx b/app/components/ui/button.tsx index 03d9faad7..87f29af42 100644 --- a/app/components/ui/button.tsx +++ b/app/components/ui/button.tsx @@ -2,7 +2,7 @@ import { Slot } from '@radix-ui/react-slot' import { cva, type VariantProps } from 'class-variance-authority' import * as React from 'react' -import { cn } from '../../utils/misc.tsx' +import { cn } from '#app/utils/misc.tsx' const buttonVariants = cva( 'inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50', diff --git a/app/components/ui/checkbox.tsx b/app/components/ui/checkbox.tsx index 5badee3f8..637a7fdd6 100644 --- a/app/components/ui/checkbox.tsx +++ b/app/components/ui/checkbox.tsx @@ -1,7 +1,7 @@ import * as CheckboxPrimitive from '@radix-ui/react-checkbox' import * as React from 'react' -import { cn } from '../../utils/misc.tsx' +import { cn } from '#app/utils/misc.tsx' export type CheckboxProps = Omit< React.ComponentPropsWithoutRef, diff --git a/app/components/ui/dropdown-menu.tsx b/app/components/ui/dropdown-menu.tsx index 19df94aa0..3bb4fe3a3 100644 --- a/app/components/ui/dropdown-menu.tsx +++ b/app/components/ui/dropdown-menu.tsx @@ -1,7 +1,7 @@ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu' import * as React from 'react' -import { cn } from '../../utils/misc.tsx' +import { cn } from '#app/utils/misc.tsx' const DropdownMenu = DropdownMenuPrimitive.Root diff --git a/app/components/ui/icon.tsx b/app/components/ui/icon.tsx index c7bd9ff1f..fb0108fa2 100644 --- a/app/components/ui/icon.tsx +++ b/app/components/ui/icon.tsx @@ -1,6 +1,6 @@ import { type SVGProps } from 'react' +import { cn } from '#app/utils/misc.tsx' import { type IconName } from '@/icon-name' -import { cn } from '../../utils/misc.tsx' import href from './icons/sprite.svg' export { href } diff --git a/app/components/ui/input.tsx b/app/components/ui/input.tsx index a2f8813cf..18801dca9 100644 --- a/app/components/ui/input.tsx +++ b/app/components/ui/input.tsx @@ -1,6 +1,6 @@ import * as React from 'react' -import { cn } from '../../utils/misc.tsx' +import { cn } from '#app/utils/misc.tsx' export interface InputProps extends React.InputHTMLAttributes {} diff --git a/app/components/ui/label.tsx b/app/components/ui/label.tsx index 39ab5575d..ec453ee26 100644 --- a/app/components/ui/label.tsx +++ b/app/components/ui/label.tsx @@ -2,7 +2,7 @@ import * as LabelPrimitive from '@radix-ui/react-label' import { cva, type VariantProps } from 'class-variance-authority' import * as React from 'react' -import { cn } from '../../utils/misc.tsx' +import { cn } from '#app/utils/misc.tsx' const labelVariants = cva( 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70', diff --git a/app/components/ui/status-button.tsx b/app/components/ui/status-button.tsx index 6d66bed08..1bfdb61b7 100644 --- a/app/components/ui/status-button.tsx +++ b/app/components/ui/status-button.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useSpinDelay } from 'spin-delay' -import { cn } from '../../utils/misc.tsx' +import { cn } from '#app/utils/misc.tsx' import { Button, type ButtonProps } from './button.tsx' import { Icon } from './icon.tsx' import { diff --git a/app/components/ui/textarea.tsx b/app/components/ui/textarea.tsx index c48dd7ef3..f7719e851 100644 --- a/app/components/ui/textarea.tsx +++ b/app/components/ui/textarea.tsx @@ -1,6 +1,6 @@ import * as React from 'react' -import { cn } from '../../utils/misc.tsx' +import { cn } from '#app/utils/misc.tsx' export interface TextareaProps extends React.TextareaHTMLAttributes {} diff --git a/app/components/ui/tooltip.tsx b/app/components/ui/tooltip.tsx index 5268538ea..5017f3ef7 100644 --- a/app/components/ui/tooltip.tsx +++ b/app/components/ui/tooltip.tsx @@ -1,7 +1,7 @@ import * as TooltipPrimitive from '@radix-ui/react-tooltip' import * as React from 'react' -import { cn } from '../../utils/misc.tsx' +import { cn } from '#app/utils/misc.tsx' const TooltipProvider = TooltipPrimitive.Provider diff --git a/app/routes/$.tsx b/app/routes/$.tsx index 69f74a3f4..b26d52a19 100644 --- a/app/routes/$.tsx +++ b/app/routes/$.tsx @@ -6,8 +6,8 @@ // message for them than the Remix and/or browser default. import { Link, useLocation } from '@remix-run/react' -import { GeneralErrorBoundary } from '../components/error-boundary.tsx' -import { Icon } from '../components/ui/icon.tsx' +import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx' +import { Icon } from '#app/components/ui/icon.tsx' export async function loader() { throw new Response('Not found', { status: 404 }) diff --git a/app/routes/_auth+/auth.$provider.callback.test.ts b/app/routes/_auth+/auth.$provider.callback.test.ts index 4f6ccacd4..0b515995b 100644 --- a/app/routes/_auth+/auth.$provider.callback.test.ts +++ b/app/routes/_auth+/auth.$provider.callback.test.ts @@ -2,23 +2,17 @@ import { generateTOTP } from '@epic-web/totp' import { faker } from '@faker-js/faker' import { http } from 'msw' import { expect, test } from 'vitest' -import { createUser } from '../../../tests/db-utils.ts' -import { - mockGithubProfile, - primaryGitHubEmail, -} from '../../../tests/mocks/github.ts' -import { server } from '../../../tests/mocks/index.ts' -import { consoleError } from '../../../tests/setup/setup-test-env.ts' -import { BASE_URL, convertSetCookieToCookie } from '../../../tests/utils.ts' -import { - getSessionExpirationDate, - sessionKey, -} from '../../utils/auth.server.ts' -import { prisma } from '../../utils/db.server.ts' -import { GITHUB_PROVIDER_NAME } from '../../utils/github-auth.server.ts' -import { invariant } from '../../utils/misc.tsx' -import { sessionStorage } from '../../utils/session.server.ts' -import { twoFAVerificationType } from '../settings+/profile.two-factor.tsx' +import { twoFAVerificationType } from '#app/routes/settings+/profile.two-factor.tsx' +import { getSessionExpirationDate, sessionKey } from '#app/utils/auth.server.ts' +import { prisma } from '#app/utils/db.server.ts' +import { GITHUB_PROVIDER_NAME } from '#app/utils/github-auth.server.ts' +import { invariant } from '#app/utils/misc.tsx' +import { sessionStorage } from '#app/utils/session.server.ts' +import { createUser } from '#tests/db-utils.ts' +import { mockGithubProfile, primaryGitHubEmail } from '#tests/mocks/github.ts' +import { server } from '#tests/mocks/index.ts' +import { consoleError } from '#tests/setup/setup-test-env.ts' +import { BASE_URL, convertSetCookieToCookie } from '#tests/utils.ts' import { loader } from './auth.$provider.callback.ts' const ROUTE_PATH = '/auth/github/callback' diff --git a/app/routes/_auth+/auth.$provider.callback.ts b/app/routes/_auth+/auth.$provider.callback.ts index e134708a4..dc59a1271 100644 --- a/app/routes/_auth+/auth.$provider.callback.ts +++ b/app/routes/_auth+/auth.$provider.callback.ts @@ -3,20 +3,20 @@ import { authenticator, getSessionExpirationDate, getUserId, -} from '../../utils/auth.server.ts' -import { handleMockCallback } from '../../utils/connections.server.ts' -import { ProviderNameSchema, providerLabels } from '../../utils/connections.tsx' -import { prisma } from '../../utils/db.server.ts' -import { combineHeaders } from '../../utils/misc.tsx' +} from '#app/utils/auth.server.ts' +import { handleMockCallback } from '#app/utils/connections.server.ts' +import { ProviderNameSchema, providerLabels } from '#app/utils/connections.tsx' +import { prisma } from '#app/utils/db.server.ts' +import { combineHeaders } from '#app/utils/misc.tsx' import { destroyRedirectToHeader, getRedirectCookieValue, -} from '../../utils/redirect-cookie.server.ts' +} from '#app/utils/redirect-cookie.server.ts' import { createToastHeaders, redirectWithToast, -} from '../../utils/toast.server.ts' -import { verifySessionStorage } from '../../utils/verification.server.ts' +} from '#app/utils/toast.server.ts' +import { verifySessionStorage } from '#app/utils/verification.server.ts' import { handleNewSession } from './login.tsx' import { onboardingEmailSessionKey, diff --git a/app/routes/_auth+/auth.$provider.ts b/app/routes/_auth+/auth.$provider.ts index 87cc4aa09..4b88948c7 100644 --- a/app/routes/_auth+/auth.$provider.ts +++ b/app/routes/_auth+/auth.$provider.ts @@ -1,9 +1,9 @@ import { redirect, type DataFunctionArgs } from '@remix-run/node' -import { authenticator } from '../../utils/auth.server.ts' -import { handleMockAction } from '../../utils/connections.server.ts' -import { ProviderNameSchema } from '../../utils/connections.tsx' -import { getReferrerRoute } from '../../utils/misc.tsx' -import { getRedirectCookieHeader } from '../../utils/redirect-cookie.server.ts' +import { authenticator } from '#app/utils/auth.server.ts' +import { handleMockAction } from '#app/utils/connections.server.ts' +import { ProviderNameSchema } from '#app/utils/connections.tsx' +import { getReferrerRoute } from '#app/utils/misc.tsx' +import { getRedirectCookieHeader } from '#app/utils/redirect-cookie.server.ts' export async function loader() { return redirect('/login') diff --git a/app/routes/_auth+/forgot-password.tsx b/app/routes/_auth+/forgot-password.tsx index 745480925..6e2a67d61 100644 --- a/app/routes/_auth+/forgot-password.tsx +++ b/app/routes/_auth+/forgot-password.tsx @@ -9,12 +9,12 @@ import { } from '@remix-run/node' import { Link, useFetcher } from '@remix-run/react' import { z } from 'zod' -import { GeneralErrorBoundary } from '../../components/error-boundary.tsx' -import { ErrorList, Field } from '../../components/forms.tsx' -import { StatusButton } from '../../components/ui/status-button.tsx' -import { prisma } from '../../utils/db.server.ts' -import { sendEmail } from '../../utils/email.server.ts' -import { EmailSchema, UsernameSchema } from '../../utils/user-validation.ts' +import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx' +import { ErrorList, Field } from '#app/components/forms.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' +import { prisma } from '#app/utils/db.server.ts' +import { sendEmail } from '#app/utils/email.server.ts' +import { EmailSchema, UsernameSchema } from '#app/utils/user-validation.ts' import { prepareVerification } from './verify.tsx' const ForgotPasswordSchema = z.object({ diff --git a/app/routes/_auth+/login.tsx b/app/routes/_auth+/login.tsx index e2fd90305..1514ba557 100644 --- a/app/routes/_auth+/login.tsx +++ b/app/routes/_auth+/login.tsx @@ -9,31 +9,31 @@ import { import { Form, Link, useActionData, useSearchParams } from '@remix-run/react' import { safeRedirect } from 'remix-utils' import { z } from 'zod' -import { GeneralErrorBoundary } from '../../components/error-boundary.tsx' -import { CheckboxField, ErrorList, Field } from '../../components/forms.tsx' -import { Spacer } from '../../components/spacer.tsx' -import { StatusButton } from '../../components/ui/status-button.tsx' +import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx' +import { CheckboxField, ErrorList, Field } from '#app/components/forms.tsx' +import { Spacer } from '#app/components/spacer.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' +import { twoFAVerificationType } from '#app/routes/settings+/profile.two-factor.tsx' import { getUserId, login, requireAnonymous, sessionKey, -} from '../../utils/auth.server.ts' +} from '#app/utils/auth.server.ts' import { ProviderConnectionForm, providerNames, -} from '../../utils/connections.tsx' -import { prisma } from '../../utils/db.server.ts' +} from '#app/utils/connections.tsx' +import { prisma } from '#app/utils/db.server.ts' import { combineResponseInits, invariant, useIsPending, -} from '../../utils/misc.tsx' -import { sessionStorage } from '../../utils/session.server.ts' -import { redirectWithToast } from '../../utils/toast.server.ts' -import { PasswordSchema, UsernameSchema } from '../../utils/user-validation.ts' -import { verifySessionStorage } from '../../utils/verification.server.ts' -import { twoFAVerificationType } from '../settings+/profile.two-factor.tsx' +} from '#app/utils/misc.tsx' +import { sessionStorage } from '#app/utils/session.server.ts' +import { redirectWithToast } from '#app/utils/toast.server.ts' +import { PasswordSchema, UsernameSchema } from '#app/utils/user-validation.ts' +import { verifySessionStorage } from '#app/utils/verification.server.ts' import { getRedirectToUrl, type VerifyFunctionArgs } from './verify.tsx' const verifiedTimeKey = 'verified-time' diff --git a/app/routes/_auth+/logout.tsx b/app/routes/_auth+/logout.tsx index 27a2f60c9..5f2b2b51a 100644 --- a/app/routes/_auth+/logout.tsx +++ b/app/routes/_auth+/logout.tsx @@ -1,5 +1,5 @@ import { redirect, type DataFunctionArgs } from '@remix-run/node' -import { logout } from '../../utils/auth.server.ts' +import { logout } from '#app/utils/auth.server.ts' export async function loader() { return redirect('/') diff --git a/app/routes/_auth+/onboarding.tsx b/app/routes/_auth+/onboarding.tsx index 6071ed04c..15935bf15 100644 --- a/app/routes/_auth+/onboarding.tsx +++ b/app/routes/_auth+/onboarding.tsx @@ -14,24 +14,20 @@ import { } from '@remix-run/react' import { safeRedirect } from 'remix-utils' import { z } from 'zod' -import { CheckboxField, ErrorList, Field } from '../../components/forms.tsx' -import { Spacer } from '../../components/spacer.tsx' -import { StatusButton } from '../../components/ui/status-button.tsx' -import { - requireAnonymous, - sessionKey, - signup, -} from '../../utils/auth.server.ts' -import { redirectWithConfetti } from '../../utils/confetti.server.ts' -import { prisma } from '../../utils/db.server.ts' -import { invariant, useIsPending } from '../../utils/misc.tsx' -import { sessionStorage } from '../../utils/session.server.ts' +import { CheckboxField, ErrorList, Field } from '#app/components/forms.tsx' +import { Spacer } from '#app/components/spacer.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' +import { requireAnonymous, sessionKey, signup } from '#app/utils/auth.server.ts' +import { redirectWithConfetti } from '#app/utils/confetti.server.ts' +import { prisma } from '#app/utils/db.server.ts' +import { invariant, useIsPending } from '#app/utils/misc.tsx' +import { sessionStorage } from '#app/utils/session.server.ts' import { NameSchema, PasswordSchema, UsernameSchema, -} from '../../utils/user-validation.ts' -import { verifySessionStorage } from '../../utils/verification.server.ts' +} from '#app/utils/user-validation.ts' +import { verifySessionStorage } from '#app/utils/verification.server.ts' import { type VerifyFunctionArgs } from './verify.tsx' const onboardingEmailSessionKey = 'onboardingEmail' diff --git a/app/routes/_auth+/onboarding_.$provider.tsx b/app/routes/_auth+/onboarding_.$provider.tsx index cb0b0fee4..07e3c99ea 100644 --- a/app/routes/_auth+/onboarding_.$provider.tsx +++ b/app/routes/_auth+/onboarding_.$provider.tsx @@ -15,22 +15,22 @@ import { } from '@remix-run/react' import { safeRedirect } from 'remix-utils' import { z } from 'zod' -import { CheckboxField, ErrorList, Field } from '../../components/forms.tsx' -import { Spacer } from '../../components/spacer.tsx' -import { StatusButton } from '../../components/ui/status-button.tsx' +import { CheckboxField, ErrorList, Field } from '#app/components/forms.tsx' +import { Spacer } from '#app/components/spacer.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' import { authenticator, requireAnonymous, sessionKey, signupWithConnection, -} from '../../utils/auth.server.ts' -import { redirectWithConfetti } from '../../utils/confetti.server.ts' -import { ProviderNameSchema } from '../../utils/connections.tsx' -import { prisma } from '../../utils/db.server.ts' -import { invariant, useIsPending } from '../../utils/misc.tsx' -import { sessionStorage } from '../../utils/session.server.ts' -import { NameSchema, UsernameSchema } from '../../utils/user-validation.ts' -import { verifySessionStorage } from '../../utils/verification.server.ts' +} from '#app/utils/auth.server.ts' +import { redirectWithConfetti } from '#app/utils/confetti.server.ts' +import { ProviderNameSchema } from '#app/utils/connections.tsx' +import { prisma } from '#app/utils/db.server.ts' +import { invariant, useIsPending } from '#app/utils/misc.tsx' +import { sessionStorage } from '#app/utils/session.server.ts' +import { NameSchema, UsernameSchema } from '#app/utils/user-validation.ts' +import { verifySessionStorage } from '#app/utils/verification.server.ts' import { type VerifyFunctionArgs } from './verify.tsx' export const onboardingEmailSessionKey = 'onboardingEmail' diff --git a/app/routes/_auth+/reset-password.tsx b/app/routes/_auth+/reset-password.tsx index 79f8e0db3..dff7047d3 100644 --- a/app/routes/_auth+/reset-password.tsx +++ b/app/routes/_auth+/reset-password.tsx @@ -8,14 +8,14 @@ import { } from '@remix-run/node' import { Form, useActionData, useLoaderData } from '@remix-run/react' import { z } from 'zod' -import { GeneralErrorBoundary } from '../../components/error-boundary.tsx' -import { ErrorList, Field } from '../../components/forms.tsx' -import { StatusButton } from '../../components/ui/status-button.tsx' -import { requireAnonymous, resetUserPassword } from '../../utils/auth.server.ts' -import { prisma } from '../../utils/db.server.ts' -import { invariant, useIsPending } from '../../utils/misc.tsx' -import { PasswordSchema } from '../../utils/user-validation.ts' -import { verifySessionStorage } from '../../utils/verification.server.ts' +import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx' +import { ErrorList, Field } from '#app/components/forms.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' +import { requireAnonymous, resetUserPassword } from '#app/utils/auth.server.ts' +import { prisma } from '#app/utils/db.server.ts' +import { invariant, useIsPending } from '#app/utils/misc.tsx' +import { PasswordSchema } from '#app/utils/user-validation.ts' +import { verifySessionStorage } from '#app/utils/verification.server.ts' import { type VerifyFunctionArgs } from './verify.tsx' const resetPasswordUsernameSessionKey = 'resetPasswordUsername' diff --git a/app/routes/_auth+/signup.tsx b/app/routes/_auth+/signup.tsx index 42643fee9..de8fa41db 100644 --- a/app/routes/_auth+/signup.tsx +++ b/app/routes/_auth+/signup.tsx @@ -9,17 +9,17 @@ import { } from '@remix-run/node' import { Form, useActionData, useSearchParams } from '@remix-run/react' import { z } from 'zod' -import { GeneralErrorBoundary } from '../../components/error-boundary.tsx' -import { ErrorList, Field } from '../../components/forms.tsx' -import { StatusButton } from '../../components/ui/status-button.tsx' +import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx' +import { ErrorList, Field } from '#app/components/forms.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' import { ProviderConnectionForm, providerNames, -} from '../../utils/connections.tsx' -import { prisma } from '../../utils/db.server.ts' -import { sendEmail } from '../../utils/email.server.ts' -import { useIsPending } from '../../utils/misc.tsx' -import { EmailSchema } from '../../utils/user-validation.ts' +} from '#app/utils/connections.tsx' +import { prisma } from '#app/utils/db.server.ts' +import { sendEmail } from '#app/utils/email.server.ts' +import { useIsPending } from '#app/utils/misc.tsx' +import { EmailSchema } from '#app/utils/user-validation.ts' import { prepareVerification } from './verify.tsx' const SignupSchema = z.object({ diff --git a/app/routes/_auth+/verify.tsx b/app/routes/_auth+/verify.tsx index 3efc80ac3..4974420d3 100644 --- a/app/routes/_auth+/verify.tsx +++ b/app/routes/_auth+/verify.tsx @@ -9,17 +9,17 @@ import { useSearchParams, } from '@remix-run/react' import { z } from 'zod' -import { GeneralErrorBoundary } from '../../components/error-boundary.tsx' -import { ErrorList, Field } from '../../components/forms.tsx' -import { Spacer } from '../../components/spacer.tsx' -import { StatusButton } from '../../components/ui/status-button.tsx' -import { handleVerification as handleChangeEmailVerification } from '../../routes/settings+/profile.change-email.tsx' -import { requireUserId } from '../../utils/auth.server.ts' -import { prisma } from '../../utils/db.server.ts' -import { getDomainUrl, useIsPending } from '../../utils/misc.tsx' -import { redirectWithToast } from '../../utils/toast.server.ts' -import { twoFAVerificationType } from '../settings+/profile.two-factor.tsx' -import { type twoFAVerifyVerificationType } from '../settings+/profile.two-factor.verify.tsx' +import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx' +import { ErrorList, Field } from '#app/components/forms.tsx' +import { Spacer } from '#app/components/spacer.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' +import { handleVerification as handleChangeEmailVerification } from '#app/routes/settings+/profile.change-email.tsx' +import { twoFAVerificationType } from '#app/routes/settings+/profile.two-factor.tsx' +import { type twoFAVerifyVerificationType } from '#app/routes/settings+/profile.two-factor.verify.tsx' +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 { handleVerification as handleLoginTwoFactorVerification, shouldRequestTwoFA, diff --git a/app/routes/_marketing+/index.tsx b/app/routes/_marketing+/index.tsx index df0f7ee28..cd34a96c9 100644 --- a/app/routes/_marketing+/index.tsx +++ b/app/routes/_marketing+/index.tsx @@ -4,7 +4,7 @@ import { TooltipContent, TooltipProvider, TooltipTrigger, -} from '../../components/ui/tooltip.tsx' +} from '#app/components/ui/tooltip.tsx' import { logos, stars } from './logos/logos.ts' export const meta: V2_MetaFunction = () => [{ title: 'Epic Notes' }] diff --git a/app/routes/admin+/cache.tsx b/app/routes/admin+/cache.tsx index 06f63d459..403dc63a5 100644 --- a/app/routes/admin+/cache.tsx +++ b/app/routes/admin+/cache.tsx @@ -7,26 +7,26 @@ import { useSearchParams, useSubmit, } from '@remix-run/react' -import { Field } from '../../components/forms.tsx' -import { Spacer } from '../../components/spacer.tsx' -import { Button } from '../../components/ui/button.tsx' +import { Field } from '#app/components/forms.tsx' +import { Spacer } from '#app/components/spacer.tsx' +import { Button } from '#app/components/ui/button.tsx' import { cache, getAllCacheKeys, lruCache, searchCacheKeys, -} from '../../utils/cache.server.ts' +} from '#app/utils/cache.server.ts' import { ensureInstance, getAllInstances, getInstanceInfo, -} from '../../utils/litefs.server.ts' +} from '#app/utils/litefs.server.ts' import { invariantResponse, useDebounce, useDoubleCheck, -} from '../../utils/misc.tsx' -import { requireUserWithRole } from '../../utils/permissions.ts' +} from '#app/utils/misc.tsx' +import { requireUserWithRole } from '#app/utils/permissions.ts' export async function loader({ request }: DataFunctionArgs) { await requireUserWithRole(request, 'admin') diff --git a/app/routes/admin+/cache_.lru.$cacheKey.ts b/app/routes/admin+/cache_.lru.$cacheKey.ts index 71376472d..fa08ebc2b 100644 --- a/app/routes/admin+/cache_.lru.$cacheKey.ts +++ b/app/routes/admin+/cache_.lru.$cacheKey.ts @@ -1,9 +1,9 @@ import { json, type DataFunctionArgs } from '@remix-run/node' import { getAllInstances, getInstanceInfo } from 'litefs-js' import { ensureInstance } from 'litefs-js/remix.js' -import { lruCache } from '../../utils/cache.server.ts' -import { invariantResponse } from '../../utils/misc.tsx' -import { requireUserWithRole } from '../../utils/permissions.ts' +import { lruCache } from '#app/utils/cache.server.ts' +import { invariantResponse } from '#app/utils/misc.tsx' +import { requireUserWithRole } from '#app/utils/permissions.ts' export async function loader({ request, params }: DataFunctionArgs) { await requireUserWithRole(request, 'admin') diff --git a/app/routes/admin+/cache_.sqlite.$cacheKey.ts b/app/routes/admin+/cache_.sqlite.$cacheKey.ts index 9e5a68bf7..aa185e654 100644 --- a/app/routes/admin+/cache_.sqlite.$cacheKey.ts +++ b/app/routes/admin+/cache_.sqlite.$cacheKey.ts @@ -1,9 +1,9 @@ import { json, type DataFunctionArgs } from '@remix-run/node' import { getAllInstances, getInstanceInfo } from 'litefs-js' import { ensureInstance } from 'litefs-js/remix.js' -import { cache } from '../../utils/cache.server.ts' -import { invariantResponse } from '../../utils/misc.tsx' -import { requireUserWithRole } from '../../utils/permissions.ts' +import { cache } from '#app/utils/cache.server.ts' +import { invariantResponse } from '#app/utils/misc.tsx' +import { requireUserWithRole } from '#app/utils/permissions.ts' export async function loader({ request, params }: DataFunctionArgs) { await requireUserWithRole(request, 'admin') diff --git a/app/routes/admin+/cache_.sqlite.tsx b/app/routes/admin+/cache_.sqlite.tsx index dc346d043..df5ce0204 100644 --- a/app/routes/admin+/cache_.sqlite.tsx +++ b/app/routes/admin+/cache_.sqlite.tsx @@ -1,7 +1,7 @@ import { type DataFunctionArgs, json, redirect } from '@remix-run/node' import { getInstanceInfo, getInternalInstanceDomain } from 'litefs-js' import { z } from 'zod' -import { cache } from '../../utils/cache.server.ts' +import { cache } from '#app/utils/cache.server.ts' export async function action({ request }: DataFunctionArgs) { const { currentIsPrimary, primaryInstance } = await getInstanceInfo() diff --git a/app/routes/me.tsx b/app/routes/me.tsx index 6b6c03035..732429303 100644 --- a/app/routes/me.tsx +++ b/app/routes/me.tsx @@ -1,6 +1,6 @@ import { redirect, type DataFunctionArgs } from '@remix-run/node' -import { authenticator, requireUserId } from '../utils/auth.server.ts' -import { prisma } from '../utils/db.server.ts' +import { authenticator, requireUserId } from '#app/utils/auth.server.ts' +import { prisma } from '#app/utils/db.server.ts' export async function loader({ request }: DataFunctionArgs) { const userId = await requireUserId(request) diff --git a/app/routes/resources+/download-user-data.tsx b/app/routes/resources+/download-user-data.tsx index 52d749a10..c4c2be87e 100644 --- a/app/routes/resources+/download-user-data.tsx +++ b/app/routes/resources+/download-user-data.tsx @@ -1,7 +1,7 @@ import { json, type DataFunctionArgs } from '@remix-run/node' -import { requireUserId } from '../../utils/auth.server.ts' -import { prisma } from '../../utils/db.server.ts' -import { getDomainUrl } from '../../utils/misc.tsx' +import { requireUserId } from '#app/utils/auth.server.ts' +import { prisma } from '#app/utils/db.server.ts' +import { getDomainUrl } from '#app/utils/misc.tsx' export const ROUTE_PATH = '/resources/download-user-data' diff --git a/app/routes/resources+/note-images.$imageId.tsx b/app/routes/resources+/note-images.$imageId.tsx index 07416fa25..869396bee 100644 --- a/app/routes/resources+/note-images.$imageId.tsx +++ b/app/routes/resources+/note-images.$imageId.tsx @@ -1,6 +1,6 @@ import { type DataFunctionArgs } from '@remix-run/node' -import { prisma } from '../../utils/db.server.ts' -import { invariantResponse } from '../../utils/misc.tsx' +import { prisma } from '#app/utils/db.server.ts' +import { invariantResponse } from '#app/utils/misc.tsx' export async function loader({ params }: DataFunctionArgs) { invariantResponse(params.imageId, 'Image ID is required', { status: 400 }) diff --git a/app/routes/resources+/user-images.$imageId.tsx b/app/routes/resources+/user-images.$imageId.tsx index c18a92dea..da6af1d8c 100644 --- a/app/routes/resources+/user-images.$imageId.tsx +++ b/app/routes/resources+/user-images.$imageId.tsx @@ -1,6 +1,6 @@ import { type DataFunctionArgs } from '@remix-run/node' -import { prisma } from '../../utils/db.server.ts' -import { invariantResponse } from '../../utils/misc.tsx' +import { prisma } from '#app/utils/db.server.ts' +import { invariantResponse } from '#app/utils/misc.tsx' export async function loader({ params }: DataFunctionArgs) { invariantResponse(params.imageId, 'Image ID is required', { status: 400 }) diff --git a/app/routes/settings+/profile.change-email.tsx b/app/routes/settings+/profile.change-email.tsx index 4ebb9c1c6..bb07d603e 100644 --- a/app/routes/settings+/profile.change-email.tsx +++ b/app/routes/settings+/profile.change-email.tsx @@ -4,21 +4,21 @@ import * as E from '@react-email/components' import { json, redirect, type DataFunctionArgs } from '@remix-run/node' import { Form, useActionData, useLoaderData } from '@remix-run/react' import { z } from 'zod' -import { ErrorList, Field } from '../../components/forms.tsx' -import { Icon } from '../../components/ui/icon.tsx' -import { StatusButton } from '../../components/ui/status-button.tsx' +import { ErrorList, Field } from '#app/components/forms.tsx' +import { Icon } from '#app/components/ui/icon.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' import { prepareVerification, requireRecentVerification, type VerifyFunctionArgs, -} from '../../routes/_auth+/verify.tsx' -import { requireUserId } from '../../utils/auth.server.ts' -import { prisma } from '../../utils/db.server.ts' -import { sendEmail } from '../../utils/email.server.ts' -import { invariant, useIsPending } from '../../utils/misc.tsx' -import { redirectWithToast } from '../../utils/toast.server.ts' -import { EmailSchema } from '../../utils/user-validation.ts' -import { verifySessionStorage } from '../../utils/verification.server.ts' +} from '#app/routes/_auth+/verify.tsx' +import { requireUserId } from '#app/utils/auth.server.ts' +import { prisma } from '#app/utils/db.server.ts' +import { sendEmail } from '#app/utils/email.server.ts' +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' export const handle = { breadcrumb: Change Email, diff --git a/app/routes/settings+/profile.connections.tsx b/app/routes/settings+/profile.connections.tsx index 92e6c7689..797d14277 100644 --- a/app/routes/settings+/profile.connections.tsx +++ b/app/routes/settings+/profile.connections.tsx @@ -6,19 +6,19 @@ import { import { Form, useFetcher, useLoaderData } from '@remix-run/react' import { useState } from 'react' import { z } from 'zod' -import { Icon } from '../../components/ui/icon.tsx' -import { StatusButton } from '../../components/ui/status-button.tsx' +import { Icon } from '#app/components/ui/icon.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, -} from '../../components/ui/tooltip.tsx' -import { requireUserId } from '../../utils/auth.server.ts' -import { prisma } from '../../utils/db.server.ts' -import { GITHUB_PROVIDER_NAME } from '../../utils/github-auth.server.ts' -import { invariantResponse, useIsPending } from '../../utils/misc.tsx' -import { createToastHeaders } from '../../utils/toast.server.ts' +} from '#app/components/ui/tooltip.tsx' +import { requireUserId } from '#app/utils/auth.server.ts' +import { prisma } from '#app/utils/db.server.ts' +import { GITHUB_PROVIDER_NAME } from '#app/utils/github-auth.server.ts' +import { invariantResponse, useIsPending } from '#app/utils/misc.tsx' +import { createToastHeaders } from '#app/utils/toast.server.ts' export const handle = { breadcrumb: Connections, diff --git a/app/routes/settings+/profile.index.tsx b/app/routes/settings+/profile.index.tsx index f232861ee..927343387 100644 --- a/app/routes/settings+/profile.index.tsx +++ b/app/routes/settings+/profile.index.tsx @@ -3,19 +3,19 @@ import { getFieldsetConstraint, parse } from '@conform-to/zod' import { json, redirect, type DataFunctionArgs } from '@remix-run/node' import { Link, useFetcher, useLoaderData } from '@remix-run/react' import { z } from 'zod' -import { ErrorList, Field } from '../../components/forms.tsx' -import { Button } from '../../components/ui/button.tsx' -import { Icon } from '../../components/ui/icon.tsx' -import { StatusButton } from '../../components/ui/status-button.tsx' -import { requireUserId, sessionKey } from '../../utils/auth.server.ts' -import { prisma } from '../../utils/db.server.ts' +import { ErrorList, Field } from '#app/components/forms.tsx' +import { Button } from '#app/components/ui/button.tsx' +import { Icon } from '#app/components/ui/icon.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' +import { requireUserId, sessionKey } from '#app/utils/auth.server.ts' +import { prisma } from '#app/utils/db.server.ts' import { getUserImgSrc, invariantResponse, useDoubleCheck, -} from '../../utils/misc.tsx' -import { sessionStorage } from '../../utils/session.server.ts' -import { NameSchema, UsernameSchema } from '../../utils/user-validation.ts' +} from '#app/utils/misc.tsx' +import { sessionStorage } from '#app/utils/session.server.ts' +import { NameSchema, UsernameSchema } from '#app/utils/user-validation.ts' import { twoFAVerificationType } from './profile.two-factor.tsx' const ProfileFormSchema = z.object({ diff --git a/app/routes/settings+/profile.password.tsx b/app/routes/settings+/profile.password.tsx index 52b11ec9e..63c5fcbc8 100644 --- a/app/routes/settings+/profile.password.tsx +++ b/app/routes/settings+/profile.password.tsx @@ -3,19 +3,19 @@ import { getFieldsetConstraint, parse } from '@conform-to/zod' import { json, redirect, type DataFunctionArgs } from '@remix-run/node' import { Form, Link, useActionData } from '@remix-run/react' import { z } from 'zod' -import { ErrorList, Field } from '../../components/forms.tsx' -import { Button } from '../../components/ui/button.tsx' -import { Icon } from '../../components/ui/icon.tsx' -import { StatusButton } from '../../components/ui/status-button.tsx' +import { ErrorList, Field } from '#app/components/forms.tsx' +import { Button } from '#app/components/ui/button.tsx' +import { Icon } from '#app/components/ui/icon.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' import { getPasswordHash, requireUserId, verifyUserPassword, -} from '../../utils/auth.server.ts' -import { prisma } from '../../utils/db.server.ts' -import { useIsPending } from '../../utils/misc.tsx' -import { redirectWithToast } from '../../utils/toast.server.ts' -import { PasswordSchema } from '../../utils/user-validation.ts' +} from '#app/utils/auth.server.ts' +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' export const handle = { breadcrumb: Password, diff --git a/app/routes/settings+/profile.password_.create.tsx b/app/routes/settings+/profile.password_.create.tsx index 707ae7426..ee347c9b1 100644 --- a/app/routes/settings+/profile.password_.create.tsx +++ b/app/routes/settings+/profile.password_.create.tsx @@ -3,14 +3,14 @@ import { getFieldsetConstraint, parse } from '@conform-to/zod' import { json, redirect, type DataFunctionArgs } from '@remix-run/node' import { Form, Link, useActionData } from '@remix-run/react' import { z } from 'zod' -import { ErrorList, Field } from '../../components/forms.tsx' -import { Button } from '../../components/ui/button.tsx' -import { Icon } from '../../components/ui/icon.tsx' -import { StatusButton } from '../../components/ui/status-button.tsx' -import { getPasswordHash, requireUserId } from '../../utils/auth.server.ts' -import { prisma } from '../../utils/db.server.ts' -import { useIsPending } from '../../utils/misc.tsx' -import { PasswordSchema } from '../../utils/user-validation.ts' +import { ErrorList, Field } from '#app/components/forms.tsx' +import { Button } from '#app/components/ui/button.tsx' +import { Icon } from '#app/components/ui/icon.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' +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' export const handle = { breadcrumb: Password, diff --git a/app/routes/settings+/profile.photo.tsx b/app/routes/settings+/profile.photo.tsx index 11c4b937b..0d85cc24e 100644 --- a/app/routes/settings+/profile.photo.tsx +++ b/app/routes/settings+/profile.photo.tsx @@ -11,18 +11,18 @@ import { Form, useActionData, useLoaderData } from '@remix-run/react' import { useState } from 'react' import { ServerOnly } from 'remix-utils' import { z } from 'zod' -import { ErrorList } from '../../components/forms.tsx' -import { Button } from '../../components/ui/button.tsx' -import { Icon } from '../../components/ui/icon.tsx' -import { StatusButton } from '../../components/ui/status-button.tsx' -import { requireUserId } from '../../utils/auth.server.ts' -import { prisma } from '../../utils/db.server.ts' +import { ErrorList } from '#app/components/forms.tsx' +import { Button } from '#app/components/ui/button.tsx' +import { Icon } from '#app/components/ui/icon.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' +import { requireUserId } from '#app/utils/auth.server.ts' +import { prisma } from '#app/utils/db.server.ts' import { getUserImgSrc, invariantResponse, useDoubleCheck, useIsPending, -} from '../../utils/misc.tsx' +} from '#app/utils/misc.tsx' export const handle = { breadcrumb: Photo, diff --git a/app/routes/settings+/profile.tsx b/app/routes/settings+/profile.tsx index e1dc8a462..26cb44a40 100644 --- a/app/routes/settings+/profile.tsx +++ b/app/routes/settings+/profile.tsx @@ -1,11 +1,11 @@ import { json, type DataFunctionArgs } from '@remix-run/node' import { Link, Outlet, useMatches } from '@remix-run/react' -import { Spacer } from '../../components/spacer.tsx' -import { Icon } from '../../components/ui/icon.tsx' -import { requireUserId } from '../../utils/auth.server.ts' -import { prisma } from '../../utils/db.server.ts' -import { cn, invariantResponse } from '../../utils/misc.tsx' -import { useUser } from '../../utils/user.ts' +import { Spacer } from '#app/components/spacer.tsx' +import { Icon } from '#app/components/ui/icon.tsx' +import { requireUserId } from '#app/utils/auth.server.ts' +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 = { breadcrumb: Edit Profile, diff --git a/app/routes/settings+/profile.two-factor.disable.tsx b/app/routes/settings+/profile.two-factor.disable.tsx index ba6558b76..1b627f865 100644 --- a/app/routes/settings+/profile.two-factor.disable.tsx +++ b/app/routes/settings+/profile.two-factor.disable.tsx @@ -1,12 +1,12 @@ import { json, type DataFunctionArgs } from '@remix-run/node' import { useFetcher } from '@remix-run/react' -import { Icon } from '../../components/ui/icon.tsx' -import { StatusButton } from '../../components/ui/status-button.tsx' -import { requireRecentVerification } from '../../routes/_auth+/verify.tsx' -import { requireUserId } from '../../utils/auth.server.ts' -import { prisma } from '../../utils/db.server.ts' -import { useDoubleCheck } from '../../utils/misc.tsx' -import { redirectWithToast } from '../../utils/toast.server.ts' +import { Icon } from '#app/components/ui/icon.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' +import { requireRecentVerification } from '#app/routes/_auth+/verify.tsx' +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 { twoFAVerificationType } from './profile.two-factor.tsx' export const handle = { diff --git a/app/routes/settings+/profile.two-factor.index.tsx b/app/routes/settings+/profile.two-factor.index.tsx index f32740560..22c922598 100644 --- a/app/routes/settings+/profile.two-factor.index.tsx +++ b/app/routes/settings+/profile.two-factor.index.tsx @@ -1,10 +1,10 @@ import { generateTOTP } from '@epic-web/totp' import { json, redirect, type DataFunctionArgs } from '@remix-run/node' import { Link, useFetcher, useLoaderData } from '@remix-run/react' -import { Icon } from '../../components/ui/icon.tsx' -import { StatusButton } from '../../components/ui/status-button.tsx' -import { requireUserId } from '../../utils/auth.server.ts' -import { prisma } from '../../utils/db.server.ts' +import { Icon } from '#app/components/ui/icon.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' +import { requireUserId } from '#app/utils/auth.server.ts' +import { prisma } from '#app/utils/db.server.ts' import { twoFAVerificationType } from './profile.two-factor.tsx' import { twoFAVerifyVerificationType } from './profile.two-factor.verify.tsx' diff --git a/app/routes/settings+/profile.two-factor.tsx b/app/routes/settings+/profile.two-factor.tsx index 7b5dc38cc..ae3eb614b 100644 --- a/app/routes/settings+/profile.two-factor.tsx +++ b/app/routes/settings+/profile.two-factor.tsx @@ -1,6 +1,6 @@ import { Outlet } from '@remix-run/react' -import { Icon } from '../../components/ui/icon.tsx' -import { type VerificationTypes } from '../../routes/_auth+/verify.tsx' +import { Icon } from '#app/components/ui/icon.tsx' +import { type VerificationTypes } from '#app/routes/_auth+/verify.tsx' export const handle = { breadcrumb: 2FA, diff --git a/app/routes/settings+/profile.two-factor.verify.tsx b/app/routes/settings+/profile.two-factor.verify.tsx index 53ca92caa..ad91cce8f 100644 --- a/app/routes/settings+/profile.two-factor.verify.tsx +++ b/app/routes/settings+/profile.two-factor.verify.tsx @@ -5,14 +5,14 @@ import { json, redirect, type DataFunctionArgs } from '@remix-run/node' import { Form, useActionData, useLoaderData } from '@remix-run/react' import * as QRCode from 'qrcode' import { z } from 'zod' -import { Field } from '../../components/forms.tsx' -import { Icon } from '../../components/ui/icon.tsx' -import { StatusButton } from '../../components/ui/status-button.tsx' -import { isCodeValid } from '../../routes/_auth+/verify.tsx' -import { requireUserId } from '../../utils/auth.server.ts' -import { prisma } from '../../utils/db.server.ts' -import { getDomainUrl, useIsPending } from '../../utils/misc.tsx' -import { redirectWithToast } from '../../utils/toast.server.ts' +import { Field } from '#app/components/forms.tsx' +import { Icon } from '#app/components/ui/icon.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' +import { isCodeValid } from '#app/routes/_auth+/verify.tsx' +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 { twoFAVerificationType } from './profile.two-factor.tsx' export const handle = { diff --git a/app/routes/users+/$username.tsx b/app/routes/users+/$username.tsx index cbe47409e..b44ccb964 100644 --- a/app/routes/users+/$username.tsx +++ b/app/routes/users+/$username.tsx @@ -5,13 +5,13 @@ import { useLoaderData, type V2_MetaFunction, } from '@remix-run/react' -import { GeneralErrorBoundary } from '../../components/error-boundary.tsx' -import { Spacer } from '../../components/spacer.tsx' -import { Button } from '../../components/ui/button.tsx' -import { Icon } from '../../components/ui/icon.tsx' -import { prisma } from '../../utils/db.server.ts' -import { getUserImgSrc, invariantResponse } from '../../utils/misc.tsx' -import { useOptionalUser } from '../../utils/user.ts' +import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx' +import { Spacer } from '#app/components/spacer.tsx' +import { Button } from '#app/components/ui/button.tsx' +import { Icon } from '#app/components/ui/icon.tsx' +import { prisma } from '#app/utils/db.server.ts' +import { getUserImgSrc, invariantResponse } from '#app/utils/misc.tsx' +import { useOptionalUser } from '#app/utils/user.ts' export async function loader({ params }: DataFunctionArgs) { const user = await prisma.user.findFirst({ diff --git a/app/routes/users+/$username_+/__note-editor.tsx b/app/routes/users+/$username_+/__note-editor.tsx index 9f634924a..2ba2d5929 100644 --- a/app/routes/users+/$username_+/__note-editor.tsx +++ b/app/routes/users+/$username_+/__note-editor.tsx @@ -20,17 +20,17 @@ import { import { Form, useFetcher } from '@remix-run/react' import { useRef, useState } from 'react' import { z } from 'zod' -import { GeneralErrorBoundary } from '../../../components/error-boundary.tsx' -import { floatingToolbarClassName } from '../../../components/floating-toolbar.tsx' -import { ErrorList, Field, TextareaField } from '../../../components/forms.tsx' -import { Button } from '../../../components/ui/button.tsx' -import { Icon } from '../../../components/ui/icon.tsx' -import { Label } from '../../../components/ui/label.tsx' -import { StatusButton } from '../../../components/ui/status-button.tsx' -import { Textarea } from '../../../components/ui/textarea.tsx' -import { requireUserId } from '../../../utils/auth.server.ts' -import { prisma } from '../../../utils/db.server.ts' -import { cn, getNoteImgSrc } from '../../../utils/misc.tsx' +import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx' +import { floatingToolbarClassName } from '#app/components/floating-toolbar.tsx' +import { ErrorList, Field, TextareaField } from '#app/components/forms.tsx' +import { Button } from '#app/components/ui/button.tsx' +import { Icon } from '#app/components/ui/icon.tsx' +import { Label } from '#app/components/ui/label.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' +import { Textarea } from '#app/components/ui/textarea.tsx' +import { requireUserId } from '#app/utils/auth.server.ts' +import { prisma } from '#app/utils/db.server.ts' +import { cn, getNoteImgSrc } from '#app/utils/misc.tsx' const titleMinLength = 1 const titleMaxLength = 100 diff --git a/app/routes/users+/$username_+/notes.$noteId.tsx b/app/routes/users+/$username_+/notes.$noteId.tsx index 428044985..15ad015d3 100644 --- a/app/routes/users+/$username_+/notes.$noteId.tsx +++ b/app/routes/users+/$username_+/notes.$noteId.tsx @@ -10,25 +10,25 @@ import { } from '@remix-run/react' import { formatDistanceToNow } from 'date-fns' import { z } from 'zod' -import { GeneralErrorBoundary } from '../../../components/error-boundary.tsx' -import { floatingToolbarClassName } from '../../../components/floating-toolbar.tsx' -import { ErrorList } from '../../../components/forms.tsx' -import { Button } from '../../../components/ui/button.tsx' -import { Icon } from '../../../components/ui/icon.tsx' -import { StatusButton } from '../../../components/ui/status-button.tsx' -import { requireUserId } from '../../../utils/auth.server.ts' -import { prisma } from '../../../utils/db.server.ts' +import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx' +import { floatingToolbarClassName } from '#app/components/floating-toolbar.tsx' +import { ErrorList } from '#app/components/forms.tsx' +import { Button } from '#app/components/ui/button.tsx' +import { Icon } from '#app/components/ui/icon.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' +import { requireUserId } from '#app/utils/auth.server.ts' +import { prisma } from '#app/utils/db.server.ts' import { getNoteImgSrc, invariantResponse, useIsPending, -} from '../../../utils/misc.tsx' +} from '#app/utils/misc.tsx' import { requireUserWithPermission, userHasPermission, -} from '../../../utils/permissions.ts' -import { redirectWithToast } from '../../../utils/toast.server.ts' -import { useOptionalUser } from '../../../utils/user.ts' +} from '#app/utils/permissions.ts' +import { redirectWithToast } from '#app/utils/toast.server.ts' +import { useOptionalUser } from '#app/utils/user.ts' import { type loader as notesLoader } from './notes.tsx' export async function loader({ params }: DataFunctionArgs) { diff --git a/app/routes/users+/$username_+/notes.$noteId_.edit.tsx b/app/routes/users+/$username_+/notes.$noteId_.edit.tsx index c83f947c4..83c86e383 100644 --- a/app/routes/users+/$username_+/notes.$noteId_.edit.tsx +++ b/app/routes/users+/$username_+/notes.$noteId_.edit.tsx @@ -1,8 +1,8 @@ import { json, type DataFunctionArgs } from '@remix-run/node' import { useLoaderData } from '@remix-run/react' -import { requireUserId } from '../../../utils/auth.server.ts' -import { prisma } from '../../../utils/db.server.ts' -import { invariantResponse } from '../../../utils/misc.tsx' +import { requireUserId } from '#app/utils/auth.server.ts' +import { prisma } from '#app/utils/db.server.ts' +import { invariantResponse } from '#app/utils/misc.tsx' import { NoteEditor, action } from './__note-editor.tsx' export { action } diff --git a/app/routes/users+/$username_+/notes.new.tsx b/app/routes/users+/$username_+/notes.new.tsx index 507d76919..35248e99e 100644 --- a/app/routes/users+/$username_+/notes.new.tsx +++ b/app/routes/users+/$username_+/notes.new.tsx @@ -1,6 +1,6 @@ import { json } from '@remix-run/router' import { type DataFunctionArgs } from '@remix-run/server-runtime' -import { requireUserId } from '../../../utils/auth.server.ts' +import { requireUserId } from '#app/utils/auth.server.ts' import { NoteEditor, action } from './__note-editor.tsx' export async function loader({ request }: DataFunctionArgs) { diff --git a/app/routes/users+/$username_+/notes.tsx b/app/routes/users+/$username_+/notes.tsx index 9aaf7da0e..6f8a7f016 100644 --- a/app/routes/users+/$username_+/notes.tsx +++ b/app/routes/users+/$username_+/notes.tsx @@ -1,10 +1,10 @@ import { json, type DataFunctionArgs } from '@remix-run/node' import { Link, NavLink, Outlet, useLoaderData } from '@remix-run/react' -import { GeneralErrorBoundary } from '../../../components/error-boundary.tsx' -import { Icon } from '../../../components/ui/icon.tsx' -import { prisma } from '../../../utils/db.server.ts' -import { cn, getUserImgSrc, invariantResponse } from '../../../utils/misc.tsx' -import { useOptionalUser } from '../../../utils/user.ts' +import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx' +import { Icon } from '#app/components/ui/icon.tsx' +import { prisma } from '#app/utils/db.server.ts' +import { cn, getUserImgSrc, invariantResponse } from '#app/utils/misc.tsx' +import { useOptionalUser } from '#app/utils/user.ts' export async function loader({ params }: DataFunctionArgs) { const owner = await prisma.user.findFirst({ diff --git a/app/routes/users+/index.tsx b/app/routes/users+/index.tsx index 658ed66c8..86275f903 100644 --- a/app/routes/users+/index.tsx +++ b/app/routes/users+/index.tsx @@ -1,11 +1,11 @@ import { json, redirect, type DataFunctionArgs } from '@remix-run/node' import { Link, useLoaderData } from '@remix-run/react' import { z } from 'zod' -import { GeneralErrorBoundary } from '../../components/error-boundary.tsx' -import { ErrorList } from '../../components/forms.tsx' -import { SearchBar } from '../../components/search-bar.tsx' -import { prisma } from '../../utils/db.server.ts' -import { cn, getUserImgSrc, useDelayedIsPending } from '../../utils/misc.tsx' +import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx' +import { ErrorList } from '#app/components/forms.tsx' +import { SearchBar } from '#app/components/search-bar.tsx' +import { prisma } from '#app/utils/db.server.ts' +import { cn, getUserImgSrc, useDelayedIsPending } from '#app/utils/misc.tsx' const UserSearchResultSchema = z.object({ id: z.string(), diff --git a/app/utils/cache.server.ts b/app/utils/cache.server.ts index 5bd0a0e9f..0a374911d 100644 --- a/app/utils/cache.server.ts +++ b/app/utils/cache.server.ts @@ -11,7 +11,7 @@ import { } from 'cachified' import { LRUCache } from 'lru-cache' import { z } from 'zod' -import { updatePrimaryCacheValue } from '../routes/admin+/cache_.sqlite.tsx' +import { updatePrimaryCacheValue } from '#app/routes/admin+/cache_.sqlite.tsx' import { getInstanceInfo, getInstanceInfoSync } from './litefs.server.ts' import { singleton } from './singleton.server.ts' import { cachifiedTimingReporter, type Timings } from './timing.server.ts' diff --git a/app/utils/connections.tsx b/app/utils/connections.tsx index a5bce0c39..39fd69b68 100644 --- a/app/utils/connections.tsx +++ b/app/utils/connections.tsx @@ -1,7 +1,7 @@ import { Form } from '@remix-run/react' import { z } from 'zod' -import { Icon } from '../components/ui/icon.tsx' -import { StatusButton } from '../components/ui/status-button.tsx' +import { Icon } from '#app/components/ui/icon.tsx' +import { StatusButton } from '#app/components/ui/status-button.tsx' import { useIsPending } from './misc.tsx' export const GITHUB_PROVIDER_NAME = 'github' diff --git a/app/utils/misc.error-message.test.ts b/app/utils/misc.error-message.test.ts index bc368dd76..07bc32260 100644 --- a/app/utils/misc.error-message.test.ts +++ b/app/utils/misc.error-message.test.ts @@ -1,6 +1,6 @@ import { faker } from '@faker-js/faker' import { expect, test } from 'vitest' -import { consoleError } from '../../tests/setup/setup-test-env.ts' +import { consoleError } from '#tests/setup/setup-test-env.ts' import { getErrorMessage } from './misc.tsx' test('Error object returns message', () => { diff --git a/app/utils/request-info.ts b/app/utils/request-info.ts index d7ca9083f..637521581 100644 --- a/app/utils/request-info.ts +++ b/app/utils/request-info.ts @@ -1,5 +1,5 @@ import { useRouteLoaderData } from '@remix-run/react' -import { type loader as rootLoader } from '../root.tsx' +import { type loader as rootLoader } from '#app/root.tsx' import { invariant } from './misc.tsx' /** diff --git a/app/utils/user.ts b/app/utils/user.ts index 73a8a2aff..dd2a017a6 100644 --- a/app/utils/user.ts +++ b/app/utils/user.ts @@ -1,6 +1,6 @@ import { type SerializeFrom } from '@remix-run/node' import { useRouteLoaderData } from '@remix-run/react' -import { type loader as rootLoader } from '../root.tsx' +import { type loader as rootLoader } from '#app/root.tsx' function isUser(user: any): user is SerializeFrom['user'] { return user && typeof user === 'object' && typeof user.id === 'string' diff --git a/components.json b/components.json index 545554d4b..a7f7e3d74 100644 --- a/components.json +++ b/components.json @@ -9,7 +9,7 @@ "cssVariables": true }, "aliases": { - "components": "../../components", - "utils": "../../utils/misc.tsx" + "components": "#app/components", + "utils": "#app/utils/misc.tsx" } } diff --git a/docs/caching.md b/docs/caching.md index 002abae0d..1e9743277 100644 --- a/docs/caching.md +++ b/docs/caching.md @@ -34,8 +34,8 @@ up by caching them and utilizing the stale-while-revalidate features in cachified. Here's how you would use cachified to do this: ```tsx -import { cachified, cache } from '../utils/cache.server.ts' -import { type Timings } from '../utils/timing.server.ts' +import { cachified, cache } from '#app/utils/cache.server.ts' +import { type Timings } from '#app/utils/timing.server.ts' const eventSchema = z.object({ /* the schema for events */ diff --git a/docs/decisions/011-sitemaps.md b/docs/decisions/011-sitemaps.md index 5f680b342..66286f6ef 100644 --- a/docs/decisions/011-sitemaps.md +++ b/docs/decisions/011-sitemaps.md @@ -19,8 +19,8 @@ it's kind of annoying. ## Decision Instead of building a sitemap into the template, we'll use -[an example](../examples.md) people can reference to add a sitemap to their Epic -Stack sites if they like. +[an example](#app/examples.md) people can reference to add a sitemap to their +Epic Stack sites if they like. ## Consequences diff --git a/docs/decisions/021-node-version.md b/docs/decisions/021-node-version.md index 0215c74ea..84063580a 100644 --- a/docs/decisions/021-node-version.md +++ b/docs/decisions/021-node-version.md @@ -45,7 +45,8 @@ stable version of Debian: v12). Folks should hopefully run into few compatibility issues. It's possible they will need features that are not back-ported to the current active LTS version, however it's trivial to update the Node.js version. Added documentation to the -[managing updates](../managing-updates.md) docs should help people manage this. +[managing updates](#app/managing-updates.md) docs should help people manage +this. We'll need to update the Node.js version in the starter whenever the active LTS version changes. diff --git a/docs/decisions/022-report-only-csp.md b/docs/decisions/022-report-only-csp.md index 5bf8a4b02..4a7b7c591 100644 --- a/docs/decisions/022-report-only-csp.md +++ b/docs/decisions/022-report-only-csp.md @@ -16,7 +16,7 @@ users of the Epic Stack. There's an option for CSPs called `report-only` which allows the browser to report CSP violations without actually blocking the resource. This turns the CSP -into an opt-in which follows our [guiding principle](../guiding-principles.md) +into an opt-in which follows our [guiding principle](#app/guiding-principles.md) of "Minimize Setup Friction" (similar to deferring setup of third-party services until they're actually needed). diff --git a/docs/decisions/026-path-aliases.md b/docs/decisions/026-path-aliases.md index bdcbf3530..5d11cf30c 100644 --- a/docs/decisions/026-path-aliases.md +++ b/docs/decisions/026-path-aliases.md @@ -2,7 +2,7 @@ Date: 2023-08-14 -Status: accepted +Status: superseded by [031-imports](./031-imports.md) ## Context @@ -11,16 +11,15 @@ This allows you to avoid relative imports and makes it easier to move files around without having to update imports. When the Epic Stack started, we used path imports that were similar to those in -the rest of the Remix ecosystem: `~/` referenced the `app/` directory. We added +the rest of the Remix ecosystem: `#` referenced the `app/` directory. We added `tests/` to make it easier to import test utils. However, we've found that this is confusing for new developers. It's not clear -what `~/` means, and seeing `import { thing } from 'tests/thing'` is confusing. -I floated the idea of adding another alias for `@/` to be the app directory and -or possibly just moving the `~/` to the root and having that be the only alias. -But at the end of the day, we're using TypeScript which will prevent us from -making mistakes and modern editors will automatically handle imports for you -anyway. +what `#` means, and seeing `import { thing } from 'tests/thing'` is confusing. I +floated the idea of adding another alias for `@/` to be the app directory and or +possibly just moving the `#` to the root and having that be the only alias. But +at the end of the day, we're using TypeScript which will prevent us from making +mistakes and modern editors will automatically handle imports for you anyway. At first it may feel like a pain, but less tooling magic is better and editors can really help reduce the pain. Additionally, we have ESLint configured to sort diff --git a/docs/decisions/030-github-auth.md b/docs/decisions/030-github-auth.md index 1c87eb4e3..6eca20aa1 100644 --- a/docs/decisions/030-github-auth.md +++ b/docs/decisions/030-github-auth.md @@ -64,6 +64,6 @@ ensure they continue to function properly as people tune things for their needs. Additionally, we'll need to account for the fact that some folks don't want to set up the GitHub login flow from the start (to keep in line with our -[Minimize Setup Friction guiding principle](../guiding-principles.md)), so we'll -have to make sure that the app still runs properly without GitHub auth +[Minimize Setup Friction guiding principle](#app/guiding-principles.md)), so +we'll have to make sure that the app still runs properly without GitHub auth configured. diff --git a/docs/decisions/031-imports.md b/docs/decisions/031-imports.md new file mode 100644 index 000000000..ae770cf58 --- /dev/null +++ b/docs/decisions/031-imports.md @@ -0,0 +1,70 @@ +# Imports + +Date: 2023-08-16 + +Status: accepted + +## Context + +Recently, we removed the `#*` and `tests/*` aliases in favor of relative +imports. The arguments for this are described in +[026-path-aliases](./026-path-aliases.md). While the arguments are sound, the +big challenge with this approach is the fact that there are some times where you +need to type out the import for something and doing that is a huge pain with +relative routes. + +The issue is the fact that you can choose one of these options: + +1. Very flat files +2. Long relative imports +3. Path aliases + +Keeping files flat is just not a great option because it requires exceedingly +long filenames for longer routes and it makes it hard to find files. Long +relative imports are just a pain to type out and they are hard to read, copy, +and manually modify. + +Despite the magic of Path aliases, they are actually a standard `package.json` +supported feature. Sort of. +[The `"imports"` field](https://nodejs.org/api/packages.html#imports) in +`package.json` allows you to configure aliases for your imports. It's not +exactly the same as TypeScript Path aliases, and using them doesn't give you +autocomplete with TypeScript +([yet](https://github.com/microsoft/TypeScript/pull/55015)), but if you +configure both, then you can get the best of both worlds! + +By using the `"imports"` field, you don't have to do any special configuration +for `vitest` to be able to resolve imports. It just resolves them using the +standard. + +And by using the `tsconfig.json` `paths` field configured in the same way as the +`"imports"` field, you get autocomplete and type checking for your imports. This +should hopefully be temporary until TypeScript supports the `"imports"` field +directly. + +One interesting requirement for `imports` is that they _must_ start with the `#` +character to disambiguate from other imports. This is a bit annoying, but it's +something that's not difficult to get used to. They also _must not_ start with +`#/`. So you have to do `#app` instead of `#/app`. This is also a bit odd, but +again it's just a matter of familiarity. So it's no big deal. + +## Decision + +We're going to configure `"imports"` in the `package.json` and `paths` in the +`tsconfig.json` to use path aliases for imports. + +We'll set it to `"#*": "./*"` which will allow us to import anything in the root +of the repo with `#/`. + +## Consequences + +This is unfortunately _very_ soon after making the decision to drop the alias. +But I see this as slightly different because we're only using the alias to make +up for a shortcoming in TypeScript temporarily. Once TypeScript supports the +`"imports"` field, we can drop the `paths` field and just use the `"imports"` +standard for Node.js. + +If someone wants to use the Epic Stack without Node.js, and their runtime +doesn't support `package.json` imports (I'm not sure whether other runtimes do +or not) they'll have to continue using the paths configuration. But that's not a +consideration here. diff --git a/docs/server-timing.md b/docs/server-timing.md index 8f3675bdb..e66d71a20 100644 --- a/docs/server-timing.md +++ b/docs/server-timing.md @@ -31,7 +31,7 @@ import { combineServerTimings, makeTimings, time, -} from '../utils/timing.server.ts' +} from '#app/utils/timing.server.ts' export async function loader({ params }: DataFunctionArgs) { const timings = makeTimings('notes loader') // <-- 1. Setup Timings diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index ca4e5d43b..e316165ae 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -38,7 +38,7 @@ be done in the `server/index.ts` file. Epic Stack uses SVG sprite icons for performance reasons. If you've received an error like this during local development: -> X [ERROR] Could not resolve "../components/ui/icon.tsx" +> X [ERROR] Could not resolve "#app/components/ui/icon.tsx" You need to be manually regenerate the icon with `npm run build:icons`. diff --git a/other/build-server.ts b/other/build-server.ts index 0e03bf483..c51207643 100644 --- a/other/build-server.ts +++ b/other/build-server.ts @@ -10,7 +10,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)) const here = (...s: Array) => path.join(__dirname, ...s) const globsafe = (s: string) => s.replace(/\\/g, '/') -const allFiles = globSync(globsafe(here('../server/**/*.*')), { +const allFiles = globSync(globsafe(here('#app/server/**/*.*')), { ignore: [ 'server/dev-server.js', // for development only '**/tsconfig.json', @@ -24,10 +24,10 @@ for (const file of allFiles) { if (/\.(ts|js|tsx|jsx)$/.test(file)) { entries.push(file) } else { - const dest = file.replace(here('../server'), here('../server-build')) + const dest = file.replace(here('#app/server'), here('#app/server-build')) fsExtra.ensureDirSync(path.parse(dest).dir) fsExtra.copySync(file, dest) - console.log(`copied: ${file.replace(`${here('../server')}/`, '')}`) + console.log(`copied: ${file.replace(`${here('#app/server')}/`, '')}`) } } @@ -37,7 +37,7 @@ console.log('building...') esbuild .build({ entryPoints: entries, - outdir: here('../server-build'), + outdir: here('#app/server-build'), target: [`node${pkg.engines.node}`], platform: 'node', sourcemap: true, diff --git a/other/sentry-create-release.js b/other/sentry-create-release.js index 299a17228..b4b694a4c 100644 --- a/other/sentry-create-release.js +++ b/other/sentry-create-release.js @@ -1,7 +1,7 @@ import { createRelease } from '@sentry/remix/scripts/createRelease.js' import 'dotenv/config' -const DEFAULT_URL_PREFIX = '~/build/' +const DEFAULT_URL_PREFIX = '#build/' const DEFAULT_BUILD_PATH = 'public/build' // exit with non-zero code if we have everything for Sentry diff --git a/package.json b/package.json index bb2b452b5..80647ab73 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,9 @@ "epic-stack": true, "author": "Kent C. Dodds (https://kentcdodds.com/)", "type": "module", + "imports": { + "#*": "./*" + }, "scripts": { "build": "run-s build:*", "build:icons": "tsx ./other/build-icons.ts", diff --git a/prisma/seed.ts b/prisma/seed.ts index b5192bd52..22160577a 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -1,13 +1,13 @@ import { faker } from '@faker-js/faker' import { promiseHash } from 'remix-utils' -import { prisma } from '../app/utils/db.server.ts' +import { prisma } from '#app/utils/db.server.ts' import { createPassword, createUser, getNoteImages, getUserImages, img, -} from '../tests/db-utils.ts' +} from '#tests/db-utils.ts' async function seed() { console.log('🌱 Seeding...') diff --git a/server/index.ts b/server/index.ts index 42ef7eb64..b8fb1b2b3 100644 --- a/server/index.ts +++ b/server/index.ts @@ -24,7 +24,7 @@ import morgan from 'morgan' // @ts-ignore - this file may not exist if you haven't built yet, but it will // definitely exist by the time the dev or prod server actually runs. -import * as remixBuild from '../build/index.js' +import * as remixBuild from '#app/build/index.js' installGlobals() @@ -34,7 +34,7 @@ const createRequestHandler = wrapExpressCreateRequestHandler( _createRequestHandler, ) -const BUILD_PATH = '../build/index.js' +const BUILD_PATH = '#app/build/index.js' const build = remixBuild as unknown as ServerBuild let devBuild = build diff --git a/tests/db-utils.ts b/tests/db-utils.ts index 7d1b73114..5e864773e 100644 --- a/tests/db-utils.ts +++ b/tests/db-utils.ts @@ -2,8 +2,8 @@ import fs from 'node:fs' import { faker } from '@faker-js/faker' import bcrypt from 'bcryptjs' import { UniqueEnforcer } from 'enforce-unique' -import { getPasswordHash } from '../app/utils/auth.server.ts' -import { prisma } from '../app/utils/db.server.ts' +import { getPasswordHash } from '#app/utils/auth.server.ts' +import { prisma } from '#app/utils/db.server.ts' const uniqueUsernameEnforcer = new UniqueEnforcer() diff --git a/tests/e2e/2fa.test.ts b/tests/e2e/2fa.test.ts index b26189ea6..88d72d391 100644 --- a/tests/e2e/2fa.test.ts +++ b/tests/e2e/2fa.test.ts @@ -1,7 +1,7 @@ import { generateTOTP } from '@epic-web/totp' import { faker } from '@faker-js/faker' import { expect, test } from '@playwright/test' -import { insertNewUser, loginPage } from '../playwright-utils.ts' +import { insertNewUser, loginPage } from '#tests/playwright-utils.ts' test('Users can add 2FA to their account and use it when logging in', async ({ page, diff --git a/tests/e2e/notes.test.ts b/tests/e2e/notes.test.ts index 78bff2494..10149ffdb 100644 --- a/tests/e2e/notes.test.ts +++ b/tests/e2e/notes.test.ts @@ -1,7 +1,7 @@ import { faker } from '@faker-js/faker' import { expect, test } from '@playwright/test' -import { prisma } from '../../app/utils/db.server.ts' -import { loginPage } from '../playwright-utils.ts' +import { prisma } from '#app/utils/db.server.ts' +import { loginPage } from '#tests/playwright-utils.ts' test('Users can create notes', async ({ page }) => { const user = await loginPage({ page }) diff --git a/tests/e2e/onboarding.test.ts b/tests/e2e/onboarding.test.ts index 9c1632e14..d632d8f84 100644 --- a/tests/e2e/onboarding.test.ts +++ b/tests/e2e/onboarding.test.ts @@ -1,9 +1,9 @@ import { faker } from '@faker-js/faker' import { expect, test } from '@playwright/test' -import { prisma } from '../../app/utils/db.server.ts' -import { invariant } from '../../app/utils/misc.tsx' -import { readEmail } from '../mocks/utils.ts' -import { createUser, insertNewUser } from '../playwright-utils.ts' +import { prisma } from '#app/utils/db.server.ts' +import { invariant } from '#app/utils/misc.tsx' +import { readEmail } from '#tests/mocks/utils.ts' +import { createUser, insertNewUser } from '#tests/playwright-utils.ts' const urlRegex = /(?https?:\/\/[^\s$.?#].[^\s]*)/ function extractUrl(text: string) { diff --git a/tests/e2e/search.test.ts b/tests/e2e/search.test.ts index 4003347eb..72201f030 100644 --- a/tests/e2e/search.test.ts +++ b/tests/e2e/search.test.ts @@ -1,5 +1,5 @@ import { expect, test } from '@playwright/test' -import { insertNewUser } from '../playwright-utils.ts' +import { insertNewUser } from '#tests/playwright-utils.ts' test('Search from home page', async ({ page }) => { const newUser = await insertNewUser() diff --git a/tests/e2e/settings-profile.test.ts b/tests/e2e/settings-profile.test.ts index 5d0850552..91e1c23c2 100644 --- a/tests/e2e/settings-profile.test.ts +++ b/tests/e2e/settings-profile.test.ts @@ -1,15 +1,15 @@ import { faker } from '@faker-js/faker' import { expect, test } from '@playwright/test' -import { verifyUserPassword } from '../../app/utils/auth.server.ts' -import { prisma } from '../../app/utils/db.server.ts' -import { invariant } from '../../app/utils/misc.tsx' -import { readEmail } from '../mocks/utils.ts' +import { verifyUserPassword } from '#app/utils/auth.server.ts' +import { prisma } from '#app/utils/db.server.ts' +import { invariant } from '#app/utils/misc.tsx' +import { readEmail } from '#tests/mocks/utils.ts' import { createUser, insertNewUser, loginPage, waitFor, -} from '../playwright-utils.ts' +} from '#tests/playwright-utils.ts' test('Users can update their basic info', async ({ page }) => { await loginPage({ page }) diff --git a/tests/playwright-utils.ts b/tests/playwright-utils.ts index 480a52bc0..cb17274ea 100644 --- a/tests/playwright-utils.ts +++ b/tests/playwright-utils.ts @@ -1,11 +1,8 @@ import { test, type Page } from '@playwright/test' import * as setCookieParser from 'set-cookie-parser' -import { - getSessionExpirationDate, - sessionKey, -} from '../app/utils/auth.server.ts' -import { prisma } from '../app/utils/db.server.ts' -import { sessionStorage } from '../app/utils/session.server.ts' +import { getSessionExpirationDate, sessionKey } from '#app/utils/auth.server.ts' +import { prisma } from '#app/utils/db.server.ts' +import { sessionStorage } from '#app/utils/session.server.ts' import { insertNewUser, insertedUsers } from './db-utils.ts' export * from './db-utils.ts' diff --git a/tests/setup/custom-matchers.ts b/tests/setup/custom-matchers.ts index 2de031f97..f9abc7935 100644 --- a/tests/setup/custom-matchers.ts +++ b/tests/setup/custom-matchers.ts @@ -1,15 +1,15 @@ import matchers from '@testing-library/jest-dom/matchers.js' import * as setCookieParser from 'set-cookie-parser' import { expect } from 'vitest' -import { sessionKey } from '../../app/utils/auth.server.ts' -import { prisma } from '../../app/utils/db.server.ts' -import { sessionStorage } from '../../app/utils/session.server.ts' +import { sessionKey } from '#app/utils/auth.server.ts' +import { prisma } from '#app/utils/db.server.ts' +import { sessionStorage } from '#app/utils/session.server.ts' import { type OptionalToast, toastSessionStorage, toastKey, -} from '../../app/utils/toast.server.ts' -import { convertSetCookieToCookie } from '../utils.ts' +} from '#app/utils/toast.server.ts' +import { convertSetCookieToCookie } from '#tests/utils.ts' import '@testing-library/jest-dom/vitest.d.ts' expect.extend(matchers) diff --git a/tests/setup/db-setup.ts b/tests/setup/db-setup.ts index 88321e7fc..7dadd8051 100644 --- a/tests/setup/db-setup.ts +++ b/tests/setup/db-setup.ts @@ -14,12 +14,12 @@ beforeAll(async () => { // we *must* use dynamic imports here so the process.env.DATABASE_URL is set // befor prisma is imported and initialized afterEach(async () => { - const { prisma } = await import('../../app/utils/db.server.ts') + const { prisma } = await import('#app/utils/db.server.ts') await prisma.user.deleteMany() }) afterAll(async () => { - const { prisma } = await import('../../app/utils/db.server.ts') + const { prisma } = await import('#app/utils/db.server.ts') prisma.$disconnect() await fsExtra.remove(databasePath) }) diff --git a/tests/setup/setup-test-env.ts b/tests/setup/setup-test-env.ts index d790c0ef4..c5da09e28 100644 --- a/tests/setup/setup-test-env.ts +++ b/tests/setup/setup-test-env.ts @@ -1,13 +1,13 @@ import 'dotenv/config' import 'source-map-support/register.js' import './db-setup.ts' -import '../../app/utils/env.server.ts' +import '#app/utils/env.server.ts' // we need these to be imported first 👆 import { installGlobals } from '@remix-run/node' import { cleanup } from '@testing-library/react' import { afterEach, beforeEach, expect, vi, type SpyInstance } from 'vitest' -import { server } from '../mocks/index.ts' +import { server } from '#tests/mocks/index.ts' import './custom-matchers.ts' installGlobals() diff --git a/tests/utils.ts b/tests/utils.ts index 0ea771da5..546a3b66b 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -1,6 +1,6 @@ import * as setCookieParser from 'set-cookie-parser' -import { sessionKey } from '../app/utils/auth.server.ts' -import { sessionStorage } from '../app/utils/session.server.ts' +import { sessionKey } from '#app/utils/auth.server.ts' +import { sessionStorage } from '#app/utils/session.server.ts' export const BASE_URL = 'https://www.epicstack.dev' diff --git a/tsconfig.json b/tsconfig.json index c07e42b74..d152e34aa 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,6 +14,7 @@ "allowJs": true, "forceConsistentCasingInFileNames": true, "paths": { + "#*": ["./*"], "@/icon-name": [ "./app/components/ui/icons/name.d.ts", "./types/icon-name.d.ts"