diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 4f6f59e..05f2e98 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -8,8 +8,8 @@ module.exports = { root: true, parserOptions: { - ecmaVersion: "latest", - sourceType: "module", + ecmaVersion: 'latest', + sourceType: 'module', ecmaFeatures: { jsx: true, }, @@ -19,32 +19,32 @@ module.exports = { commonjs: true, es6: true, }, - ignorePatterns: ["!**/.server", "!**/.client"], + ignorePatterns: ['!**/.server', '!**/.client'], // Base config - extends: ["eslint:recommended"], + extends: ['eslint:recommended'], overrides: [ // React { - files: ["**/*.{js,jsx,ts,tsx}"], - plugins: ["react", "jsx-a11y"], + files: ['**/*.{js,jsx,ts,tsx}'], + plugins: ['react', 'jsx-a11y'], extends: [ - "plugin:react/recommended", - "plugin:react/jsx-runtime", - "plugin:react-hooks/recommended", - "plugin:jsx-a11y/recommended", + 'plugin:react/recommended', + 'plugin:react/jsx-runtime', + 'plugin:react-hooks/recommended', + 'plugin:jsx-a11y/recommended', ], settings: { react: { - version: "detect", + version: 'detect', }, - formComponents: ["Form"], + formComponents: ['Form'], linkComponents: [ - { name: "Link", linkAttribute: "to" }, - { name: "NavLink", linkAttribute: "to" }, + { name: 'Link', linkAttribute: 'to' }, + { name: 'NavLink', linkAttribute: 'to' }, ], - "import/resolver": { + 'import/resolver': { typescript: {}, }, }, @@ -52,14 +52,14 @@ module.exports = { // Typescript { - files: ["**/*.{ts,tsx}"], - plugins: ["@typescript-eslint", "import"], - parser: "@typescript-eslint/parser", + files: ['**/*.{ts,tsx}'], + plugins: ['@typescript-eslint', 'import'], + parser: '@typescript-eslint/parser', settings: { - "import/internal-regex": "^~/", - "import/resolver": { + 'import/internal-regex': '^~/', + 'import/resolver': { node: { - extensions: [".ts", ".tsx"], + extensions: ['.ts', '.tsx'], }, typescript: { alwaysTryTypes: true, @@ -67,15 +67,15 @@ module.exports = { }, }, extends: [ - "plugin:@typescript-eslint/recommended", - "plugin:import/recommended", - "plugin:import/typescript", + 'plugin:@typescript-eslint/recommended', + 'plugin:import/recommended', + 'plugin:import/typescript', ], }, // Node { - files: [".eslintrc.cjs"], + files: ['.eslintrc.cjs'], env: { node: true, }, diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8e4c7a2 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,15 @@ +name: CI +on: + push: +jobs: + CI: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Setup Bun + uses: oven-sh/setup-bun@v1 + - name: Install dependencies + run: bun install + - name: Run Check + run: bun run check diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..aaa1262 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,21 @@ +{ + "[javascript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[javascriptreact]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[typescript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "editor.codeActionsOnSave": { + "quickfix.biome": "always", + "source.organizeImports.biome": "always" + }, + "editor.defaultFormatter": "biomejs.biome", + "editor.formatOnSave": true, + "files.autoSave": "onFocusChange" +} diff --git a/app/entry.client.tsx b/app/entry.client.tsx index 94d5dc0..0f088c2 100644 --- a/app/entry.client.tsx +++ b/app/entry.client.tsx @@ -4,15 +4,15 @@ * For more information, see https://remix.run/file-conventions/entry.client */ -import { RemixBrowser } from "@remix-run/react"; -import { startTransition, StrictMode } from "react"; -import { hydrateRoot } from "react-dom/client"; +import { RemixBrowser } from '@remix-run/react'; +import { StrictMode, startTransition } from 'react'; +import { hydrateRoot } from 'react-dom/client'; startTransition(() => { hydrateRoot( document, - + , ); }); diff --git a/app/entry.server.tsx b/app/entry.server.tsx index 0d5c40a..620ee26 100644 --- a/app/entry.server.tsx +++ b/app/entry.server.tsx @@ -4,10 +4,10 @@ * For more information, see https://remix.run/file-conventions/entry.server */ -import type { AppLoadContext, EntryContext } from "@remix-run/cloudflare"; -import { RemixServer } from "@remix-run/react"; -import { isbot } from "isbot"; -import { renderToReadableStream } from "react-dom/server"; +import type { AppLoadContext, EntryContext } from '@remix-run/cloudflare'; +import { RemixServer } from '@remix-run/react'; +import { isbot } from 'isbot'; +import { renderToReadableStream } from 'react-dom/server'; export default async function handleRequest( request: Request, @@ -17,8 +17,10 @@ export default async function handleRequest( // This is ignored so we can keep it in the template for visibility. Feel // free to delete this parameter in your app if you're not using it! // eslint-disable-next-line @typescript-eslint/no-unused-vars - loadContext: AppLoadContext + _loadContext: AppLoadContext, ) { + let finalStatusCode = responseStatusCode; + const body = await renderToReadableStream( , { @@ -26,18 +28,18 @@ export default async function handleRequest( onError(error: unknown) { // Log streaming rendering errors from inside the shell console.error(error); - responseStatusCode = 500; + finalStatusCode = 500; }, - } + }, ); - if (isbot(request.headers.get("user-agent") || "")) { + if (isbot(request.headers.get('user-agent') || '')) { await body.allReady; } - responseHeaders.set("Content-Type", "text/html"); + responseHeaders.set('Content-Type', 'text/html'); return new Response(body, { headers: responseHeaders, - status: responseStatusCode, + status: finalStatusCode, }); } diff --git a/app/libs/drizzle/client.server.ts b/app/libs/drizzle/client.server.ts index f7ed1b5..82d939a 100644 --- a/app/libs/drizzle/client.server.ts +++ b/app/libs/drizzle/client.server.ts @@ -1,4 +1,4 @@ -import { drizzle } from "drizzle-orm/d1"; +import { drizzle } from 'drizzle-orm/d1'; export const getDBClient = (d1: D1Database) => { const db = drizzle(d1, { logger: import.meta.env.DEV }); diff --git a/app/libs/drizzle/schema.ts b/app/libs/drizzle/schema.ts index 82e4eda..05cc9c8 100644 --- a/app/libs/drizzle/schema.ts +++ b/app/libs/drizzle/schema.ts @@ -1,22 +1,18 @@ -import { sql } from "drizzle-orm"; -import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core"; +import { sql } from 'drizzle-orm'; +import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'; -export const users = sqliteTable("users", { - id: integer("id").primaryKey(), - provider: text("provider").notNull(), - providerId: text("provider_id").notNull().unique(), - name: text("name").notNull(), - icon: text("icon"), - createdAt: text("created_at") - .notNull() - .default(sql`(current_timestamp)`), +export const users = sqliteTable('users', { + id: integer('id').primaryKey(), + provider: text('provider').notNull(), + providerId: text('provider_id').notNull().unique(), + name: text('name').notNull(), + icon: text('icon'), + createdAt: text('created_at').notNull().default(sql`(current_timestamp)`), }); -export const posts = sqliteTable("posts", { - id: integer("id").primaryKey(), - body: text("body"), - userId: integer("user_id").references(() => users.id), - createdAt: text("created_at") - .notNull() - .default(sql`(current_timestamp)`), +export const posts = sqliteTable('posts', { + id: integer('id').primaryKey(), + body: text('body'), + userId: integer('user_id').references(() => users.id), + createdAt: text('created_at').notNull().default(sql`(current_timestamp)`), }); diff --git a/app/root.tsx b/app/root.tsx index 0c0d3eb..dc09bb2 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -4,15 +4,15 @@ import { Outlet, Scripts, ScrollRestoration, -} from "@remix-run/react"; -import "./tailwind.css"; +} from '@remix-run/react'; +import './tailwind.css'; export function Layout({ children }: { children: React.ReactNode }) { return ( - + - - + + diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index 71f0f23..22ac36f 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -1,18 +1,18 @@ -import type { MetaFunction, LoaderFunctionArgs } from "@remix-run/cloudflare"; -import { json } from "@remix-run/cloudflare"; -import { Form, useLoaderData, useNavigation } from "@remix-run/react"; -import { desc, eq } from "drizzle-orm"; -import { useRef, useEffect } from "react"; -import { getDBClient } from "~/libs/drizzle/client.server"; -import { posts } from "~/libs/drizzle/schema"; -import { getAuthenticator } from "~/services/auth.server"; +import type { LoaderFunctionArgs, MetaFunction } from '@remix-run/cloudflare'; +import { json } from '@remix-run/cloudflare'; +import { Form, useLoaderData, useNavigation } from '@remix-run/react'; +import { desc, eq } from 'drizzle-orm'; +import { useEffect, useRef } from 'react'; +import { getDBClient } from '~/libs/drizzle/client.server'; +import { posts } from '~/libs/drizzle/schema'; +import { getAuthenticator } from '~/services/auth.server'; export const meta: MetaFunction = () => { return [ - { title: "New Remix App" }, + { title: 'New Remix App' }, { - name: "description", - content: "Welcome to Remix! Using Vite and Cloudflare!", + name: 'description', + content: 'Welcome to Remix! Using Vite and Cloudflare!', }, ]; }; @@ -36,7 +36,7 @@ export default function Index() { const data = useLoaderData(); const navigation = useNavigation(); - const isAdding = navigation.state === "submitting"; + const isAdding = navigation.state === 'submitting'; const formRef = useRef(null); const inputRef = useRef(null); @@ -49,80 +49,80 @@ export default function Index() { if (data.user) { return ( -
-
-
Hi, {data.user.name}
-
+
+
+
Hi, {data.user.name}
+ -
+
-
+
-
- +
+
- - - - - {data.posts.map((post) => ( + {data.posts.map(post => ( - - - -
+ ID + Body + Created At + Edit
+ {post.id} + {post.body} + {post.createdAt} -
- +
+ + @@ -137,13 +137,13 @@ export default function Index() { ); } return ( -
-

Home

-
- +
+

Home

+
+ diff --git a/app/routes/auth.google.callback.tsx b/app/routes/auth.google.callback.tsx index f5a78d6..21b80c4 100644 --- a/app/routes/auth.google.callback.tsx +++ b/app/routes/auth.google.callback.tsx @@ -1,10 +1,10 @@ -import type { LoaderFunctionArgs } from "@remix-run/cloudflare"; -import { getAuthenticator } from "~/services/auth.server"; +import type { LoaderFunctionArgs } from '@remix-run/cloudflare'; +import { getAuthenticator } from '~/services/auth.server'; export const loader = ({ context, request }: LoaderFunctionArgs) => { const authenticator = getAuthenticator(context); - return authenticator.authenticate("google", request, { - successRedirect: "/", - failureRedirect: "/", + return authenticator.authenticate('google', request, { + successRedirect: '/', + failureRedirect: '/', }); }; diff --git a/app/routes/auth.google.tsx b/app/routes/auth.google.tsx index 119f268..4446f8b 100644 --- a/app/routes/auth.google.tsx +++ b/app/routes/auth.google.tsx @@ -1,7 +1,7 @@ -import type { ActionFunctionArgs } from "@remix-run/cloudflare"; -import { getAuthenticator } from "~/services/auth.server"; +import type { ActionFunctionArgs } from '@remix-run/cloudflare'; +import { getAuthenticator } from '~/services/auth.server'; export const action = ({ context, request }: ActionFunctionArgs) => { const authenticator = getAuthenticator(context); - return authenticator.authenticate("google", request); + return authenticator.authenticate('google', request); }; diff --git a/app/routes/logout.tsx b/app/routes/logout.tsx index 067c4cb..0681681 100644 --- a/app/routes/logout.tsx +++ b/app/routes/logout.tsx @@ -1,7 +1,7 @@ -import type { ActionFunctionArgs } from "@remix-run/cloudflare"; -import { getAuthenticator } from "~/services/auth.server"; +import type { ActionFunctionArgs } from '@remix-run/cloudflare'; +import { getAuthenticator } from '~/services/auth.server'; export const action = async ({ context, request }: ActionFunctionArgs) => { const authenticator = getAuthenticator(context); - await authenticator.logout(request, { redirectTo: "/" }); + await authenticator.logout(request, { redirectTo: '/' }); }; diff --git a/app/routes/posts.create.tsx b/app/routes/posts.create.tsx index b90bf3d..aff36a2 100644 --- a/app/routes/posts.create.tsx +++ b/app/routes/posts.create.tsx @@ -1,7 +1,7 @@ -import { type ActionFunctionArgs, redirect } from "@remix-run/cloudflare"; -import { getDBClient } from "~/libs/drizzle/client.server"; -import { posts } from "~/libs/drizzle/schema"; -import { getAuthenticator } from "~/services/auth.server"; +import { type ActionFunctionArgs, redirect } from '@remix-run/cloudflare'; +import { getDBClient } from '~/libs/drizzle/client.server'; +import { posts } from '~/libs/drizzle/schema'; +import { getAuthenticator } from '~/services/auth.server'; export const action = async ({ context, request }: ActionFunctionArgs) => { const authenticator = getAuthenticator(context); @@ -9,14 +9,14 @@ export const action = async ({ context, request }: ActionFunctionArgs) => { if (user) { const db = getDBClient(context.cloudflare.env.DB); const formData = await request.formData(); - const postBody = formData.get("post-body")?.toString(); + const postBody = formData.get('post-body')?.toString(); // validation if (postBody === undefined || postBody.length === 0) { - return new Response("Post body is empty", { status: 500 }); + return new Response('Post body is empty', { status: 500 }); } await db .insert(posts) .values({ body: postBody?.toString(), userId: user.id }); } - return redirect("/"); + return redirect('/'); }; diff --git a/app/routes/posts.delete.tsx b/app/routes/posts.delete.tsx index db1355b..6f8ba0f 100644 --- a/app/routes/posts.delete.tsx +++ b/app/routes/posts.delete.tsx @@ -1,8 +1,8 @@ -import { type ActionFunctionArgs, redirect } from "@remix-run/cloudflare"; -import { and, eq } from "drizzle-orm"; -import { getDBClient } from "~/libs/drizzle/client.server"; -import { posts } from "~/libs/drizzle/schema"; -import { getAuthenticator } from "~/services/auth.server"; +import { type ActionFunctionArgs, redirect } from '@remix-run/cloudflare'; +import { and, eq } from 'drizzle-orm'; +import { getDBClient } from '~/libs/drizzle/client.server'; +import { posts } from '~/libs/drizzle/schema'; +import { getAuthenticator } from '~/services/auth.server'; export const action = async ({ context, request }: ActionFunctionArgs) => { const authenticator = getAuthenticator(context); @@ -10,16 +10,16 @@ export const action = async ({ context, request }: ActionFunctionArgs) => { if (user) { const db = getDBClient(context.cloudflare.env.DB); const formData = await request.formData(); - const postId = formData.get("post-id")?.toString(); + const postId = formData.get('post-id')?.toString(); // validation if (postId === undefined || Number.isNaN(Number.parseInt(postId))) { - return new Response("Post ID is invalid", { status: 500 }); + return new Response('Post ID is invalid', { status: 500 }); } await db .delete(posts) .where( - and(eq(posts.id, Number.parseInt(postId)), eq(posts.userId, user.id)) + and(eq(posts.id, Number.parseInt(postId)), eq(posts.userId, user.id)), ); } - return redirect("/"); + return redirect('/'); }; diff --git a/app/services/auth.server.ts b/app/services/auth.server.ts index 70b9eff..46c6951 100644 --- a/app/services/auth.server.ts +++ b/app/services/auth.server.ts @@ -1,24 +1,24 @@ -import { Authenticator } from "remix-auth"; -import type { AppLoadContext } from "@remix-run/cloudflare"; +import type { AppLoadContext } from '@remix-run/cloudflare'; +import { Authenticator } from 'remix-auth'; -import { GoogleStrategy } from "remix-auth-google"; -import { eq } from "drizzle-orm"; -import { users } from "~/libs/drizzle/schema"; -import { getDBClient } from "~/libs/drizzle/client.server"; +import { eq } from 'drizzle-orm'; +import { GoogleStrategy } from 'remix-auth-google'; +import { getDBClient } from '~/libs/drizzle/client.server'; +import { users } from '~/libs/drizzle/schema'; export type User = { name: string; id: number; }; -let createCookieSessionStorage: typeof import("@remix-run/cloudflare").createCookieSessionStorage; +let createCookieSessionStorage: typeof import('@remix-run/cloudflare').createCookieSessionStorage; if (import.meta.env.DEV) { - import("@remix-run/node").then((module) => { + import('@remix-run/node').then(module => { createCookieSessionStorage = module.createCookieSessionStorage; }); } else { - import("@remix-run/cloudflare").then((module) => { + import('@remix-run/cloudflare').then(module => { createCookieSessionStorage = module.createCookieSessionStorage; }); } @@ -28,13 +28,13 @@ let _authenticatedUser: Authenticator | null = null; export function getAuthenticator(context: AppLoadContext) { if (_authenticatedUser === null) { if (!createCookieSessionStorage) { - throw new Error("createCookieSessionStorage is not initialized"); + throw new Error('createCookieSessionStorage is not initialized'); } const sessionStorage = createCookieSessionStorage({ cookie: { - name: "_session", - sameSite: "lax", - path: "/", + name: '_session', + sameSite: 'lax', + path: '/', httpOnly: true, secrets: [context.cloudflare.env.AUTH_SECRET], secure: import.meta.env.PROD, @@ -68,7 +68,7 @@ export function getAuthenticator(context: AppLoadContext) { return { id: createUser.id, name: createUser.name }; } return { id: exitsUser[0].id, name: exitsUser[0].name }; - } + }, ); _authenticatedUser.use(googleStrategy); } diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..519bf40 --- /dev/null +++ b/biome.json @@ -0,0 +1,63 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json", + "organizeImports": { + "enabled": true + }, + "formatter": { + "enabled": true, + "formatWithErrors": false, + "ignore": [], + "indentWidth": 2, + "indentStyle": "space", + "lineWidth": 80 + }, + "javascript": { + "parser": { + "unsafeParameterDecoratorsEnabled": true + }, + "formatter": { + "quoteStyle": "single", + "jsxQuoteStyle": "single", + "trailingCommas": "all", + "semicolons": "always", + "arrowParentheses": "asNeeded" + } + }, + "json": { + "parser": { "allowComments": true }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2, + "lineWidth": 80 + } + }, + "linter": { + "enabled": true, + "rules": { + "complexity": { + "useSimplifiedLogicExpression": "error" + }, + "correctness": { + "noUnusedImports": "warn", + "useHookAtTopLevel": "error" + }, + "suspicious": { + "noConsoleLog": "warn", + "noEmptyBlockStatements": "error", + "noImplicitAnyLet": "error" + }, + "nursery": { + "useSortedClasses": "error" + } + } + }, + "files": { + "ignore": ["public", "app/libs/drizzle/migrations"] + }, + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + } +} diff --git a/bun.lockb b/bun.lockb index 1c83721..7f2b5e5 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/drizzle.config.ts b/drizzle.config.ts index c71e02b..99b2c49 100644 --- a/drizzle.config.ts +++ b/drizzle.config.ts @@ -1,8 +1,8 @@ -import type { Config } from "drizzle-kit"; +import type { Config } from 'drizzle-kit'; export default { - schema: "./app/libs/drizzle/schema.ts", - out: "./app/libs/drizzle/migrations", - driver: "d1-http", - dialect: "sqlite", + schema: './app/libs/drizzle/schema.ts', + out: './app/libs/drizzle/migrations', + driver: 'd1-http', + dialect: 'sqlite', } satisfies Config; diff --git a/functions/[[path]].ts b/functions/[[path]].ts index 26a7de6..eee211e 100644 --- a/functions/[[path]].ts +++ b/functions/[[path]].ts @@ -1,8 +1,11 @@ -import { createPagesFunctionHandler } from "@remix-run/cloudflare-pages"; +import { createPagesFunctionHandler } from '@remix-run/cloudflare-pages'; +import type { ServerBuild } from '@remix-run/cloudflare'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - the server build file is generated by `remix vite:build` // eslint-disable-next-line import/no-unresolved -import * as build from "../build/server"; +import * as build from '../build/server'; -export const onRequest = createPagesFunctionHandler({ build }); +export const onRequest = createPagesFunctionHandler({ + build: build as unknown as ServerBuild, +}); diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 0000000..19a08b1 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,11 @@ +pre-commit: + commands: + check: + glob: "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}" + run: bunx biome check --write --no-errors-on-unmatched --files-ignore-unknown=true {staged_files} && git update-index --again + +pre-push: + commands: + check: + glob: "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}" + run: bun type:check && bunx biome check --no-errors-on-unmatched --files-ignore-unknown=true {pushed_files} diff --git a/load-context.ts b/load-context.ts index 94ca2e1..6faab3e 100644 --- a/load-context.ts +++ b/load-context.ts @@ -1,9 +1,9 @@ -import { type PlatformProxy } from "wrangler"; +import type { PlatformProxy } from 'wrangler'; -type Cloudflare = Omit, "dispose">; +type Cloudflare = Omit, 'dispose'>; -declare module "@remix-run/cloudflare" { +declare module '@remix-run/cloudflare' { interface AppLoadContext { cloudflare: Cloudflare; } -} \ No newline at end of file +} diff --git a/package.json b/package.json index 8798aa9..0f5c3a7 100644 --- a/package.json +++ b/package.json @@ -3,19 +3,28 @@ "private": true, "sideEffects": false, "type": "module", + "version": "0.0.1", "scripts": { "build": "remix vite:build", "dev": "remix vite:dev", "start": "wrangler pages dev ./build/client", - "lint:eslint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .", - "lint:typecheck": "tsc --noEmit", + "fix": "run-s *:fix", + "format:fix": "biome format ./ --write", + "analyzer:fix": "biome check --write ./", + "lint:fix": "biome lint --write --unsafe ./", + "check": "run-s *:check", + "format:check": "biome format ./", + "analyzer:check": "biome check ./", + "lint:check": "biome lint ./", + "type:check": "tsc --noEmit", "cloudflare:deploy": "bun run build && wrangler pages deploy", "cloudflare:type:generate": "wrangler types", "db:sql:generate": "rm -rf ./app/libs/drizzle/migrations && drizzle-kit generate", "db:migrate:local": "wrangler d1 migrations apply dartsroutine-db --local", "db:migrate:remote": "wrangler d1 migrations apply dartsroutine-db --remote", "db:clear:local": "wrangler d1 execute dartsroutine-db --local --file=./app/libs/drizzle/clear.sql", - "db:clear:remote": "wrangler d1 execute dartsroutine-db --remote --file=./app/libs/drizzle/clear.sql" + "db:clear:remote": "wrangler d1 execute dartsroutine-db --remote --file=./app/libs/drizzle/clear.sql", + "prepare": "lefthook install" }, "dependencies": { "@remix-run/cloudflare": "^2.11.1", @@ -30,20 +39,15 @@ "remix-auth-google": "^2.0.0" }, "devDependencies": { + "@biomejs/biome": "1.8.3", "@cloudflare/workers-types": "^4.20240821.1", "@remix-run/dev": "^2.11.1", "@types/react": "^18.2.20", "@types/react-dom": "^18.2.7", - "@typescript-eslint/eslint-plugin": "^6.7.4", - "@typescript-eslint/parser": "^6.7.4", "autoprefixer": "^10.4.19", "drizzle-kit": "^0.24.1", - "eslint": "^8.38.0", - "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-import": "^2.28.1", - "eslint-plugin-jsx-a11y": "^6.7.1", - "eslint-plugin-react": "^7.33.2", - "eslint-plugin-react-hooks": "^4.6.0", + "lefthook": "^1.7.14", + "npm-run-all2": "^6.2.2", "postcss": "^8.4.38", "tailwindcss": "^3.4.4", "typescript": "^5.1.6", diff --git a/tailwind.config.ts b/tailwind.config.ts index 34d03da..e5b442a 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,7 +1,7 @@ -import type { Config } from "tailwindcss"; +import type { Config } from 'tailwindcss'; export default { - content: ["./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}"], + content: ['./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}'], theme: { extend: {}, }, diff --git a/tsconfig.json b/tsconfig.json index 857ca9d..59f53ef 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,9 +10,9 @@ "compilerOptions": { "lib": ["DOM", "DOM.Iterable", "ES2022"], "types": [ - "@remix-run/cloudflare", - "vite/client", - "@cloudflare/workers-types/2023-07-01" + "@remix-run/cloudflare", + "vite/client", + "@cloudflare/workers-types/2023-07-01" ], "isolatedModules": true, "esModuleInterop": true, diff --git a/vite.config.ts b/vite.config.ts index 8c8a052..71c0464 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,9 +1,9 @@ import { vitePlugin as remix, cloudflareDevProxyVitePlugin as remixCloudflareDevProxy, -} from "@remix-run/dev"; -import { defineConfig } from "vite"; -import tsconfigPaths from "vite-tsconfig-paths"; +} from '@remix-run/dev'; +import { defineConfig } from 'vite'; +import tsconfigPaths from 'vite-tsconfig-paths'; export default defineConfig({ plugins: [ diff --git a/worker-configuration.d.ts b/worker-configuration.d.ts index a572d3f..7430cae 100644 --- a/worker-configuration.d.ts +++ b/worker-configuration.d.ts @@ -2,9 +2,9 @@ // by running `wrangler types` interface Env { - AUTH_SECRET: string; - GOOGLE_CALLBACK_BASE_URL: string; - GOOGLE_CLIENT_ID: string; - GOOGLE_CLIENT_SECRET: string; - DB: D1Database; + AUTH_SECRET: string; + GOOGLE_CALLBACK_BASE_URL: string; + GOOGLE_CLIENT_ID: string; + GOOGLE_CLIENT_SECRET: string; + DB: D1Database; }