Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .oxlintrc.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
"browser": true,
"node": true,
},
"options": {
"typeAware": true,
"typeCheck": true,
},
"categories": {
"correctness": "error",
"suspicious": "error",
Expand Down Expand Up @@ -50,7 +54,6 @@
"typescript/no-explicit-any": "error",
"typescript/no-non-null-asserted-nullish-coalescing": "error",
"typescript/no-non-null-assertion": "error",
"typescript/promise-function-async": "error",
"typescript/use-unknown-in-catch-callback-variable": "error",
"unicorn/prefer-node-protocol": "error",
"react/no-unknown-property": "error",
Expand All @@ -66,7 +69,6 @@
// Pedantic
"eqeqeq": ["error", "smart"],
"radix": "error",
"require-await": "error",
"typescript/no-unsafe-argument": "error",
"typescript/return-await": "error",
"react/jsx-no-target-blank": "error",
Expand Down
8 changes: 8 additions & 0 deletions @types/react.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import 'react';

declare module 'react' {
interface CSSProperties {
// Allow any CSS variable starting with '--'
[key: `--${string}`]: string | number;
}
}
4 changes: 2 additions & 2 deletions drizzle.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';

import { getLocalCloudflareD1Path } from './src/lib/database/utils';
import { drizzleEnv } from './src/lib/env/drizzle';

const DBEnvironments = ['local', 'remote'] as const;
type DBEnvironment = (typeof DBEnvironments)[number];
Expand All @@ -11,7 +12,6 @@ interface DBConfig {
config: ReturnType<typeof defineConfig>;
}

const DB_ENV = process.env.DB_ENV as DBEnvironment;
const OUT_DIR = './src/lib/database/migrations';
const SCHEMA_DIR = './src/lib/database/schema';

Expand Down Expand Up @@ -59,7 +59,7 @@ const ENVIRONMENTS: Record<DBEnvironment, DBConfig> = {
},
};

const activeConfig = ENVIRONMENTS[DB_ENV];
const activeConfig = ENVIRONMENTS[drizzleEnv.DB_ENV];

if (!activeConfig) {
throw new Error(
Expand Down
15 changes: 7 additions & 8 deletions lint-staged.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,20 @@ const ALL_FILES = '*';
const TYPESCRIPT_FILES = `*.{${TYPESCRIPT_EXTENSIONS.join(',')}}`;
const JAVASCRIPT_FILES = `*.{${JAVASCRIPT_EXTENSIONS.join(',')}}`;

// Format code with Oxfmt
/**
* Format code with Oxfmt
*/
function buildOxfmtCommand(stagedFiles) {
return `oxfmt --no-error-on-unmatched-pattern ${stagedFiles.join(' ')}`;
}

// Check and fix code with Oxlint
/**
* Check and fix code with Oxlint
*/
function buildOxlintCommand(stagedFiles) {
return `oxlint ${stagedFiles.join(' ')}`;
}

// Type check with TypeScript
function buildTypeCheckCommand() {
return 'tsc --noEmit';
}

/**
* Lint staged files
* @description Run commands on staged files based on their types
Expand All @@ -35,7 +34,7 @@ const lintStagedConfig = {
return [buildOxlintCommand(stagedFiles)];
},
[TYPESCRIPT_FILES]: function (stagedFiles) {
return [buildTypeCheckCommand(), buildOxlintCommand(stagedFiles)];
return [buildOxlintCommand(stagedFiles)];
},
};

Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
"format": "oxfmt",
"format:check": "oxfmt --check",
"lint": "oxlint",
"lint:ts": "tsc --noEmit",
"lint:fix": "oxlint --fix",
"storybook:dev": "storybook dev -p 6006",
"storybook:build": "storybook build",
Expand Down Expand Up @@ -115,8 +114,9 @@
"drizzle-kit": "^0.31.10",
"husky": "^9.1.7",
"lint-staged": "^16.4.0",
"oxfmt": "^0.42.0",
"oxlint": "^1.57.0",
"oxfmt": "^0.43.0",
"oxlint": "^1.58.0",
"oxlint-tsgolint": "^0.19.0",
"release-it": "^19.2.4",
"skills": "^1.4.5",
"storybook": "^10.3.3",
Expand Down
468 changes: 259 additions & 209 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/lib/auth/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,6 @@ export function getAuthErrorMessage(code: keyof AuthErrors | (string & {})) {
PASSWORD_ALREADY_SET: m.auth_error_base_password_already_set(),
};

// oxlint-disable-next-line typescript/no-unsafe-type-assertion
return AUTH_ERROR_CODES[code as keyof AuthErrors] as string | undefined;
}
8 changes: 4 additions & 4 deletions src/lib/auth/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,20 @@ export const authServer = betterAuth({
}),
secondaryStorage: {
get: async (key) => {
return await kvStore.get(key);
return kvStore.get(key);
},
set: async (key, value, ttl) => {
if (!ttl) return await kvStore.put(key, value);
if (!ttl) return kvStore.put(key, value);
// Cloudflare Workers KV has a minimum TTL of 60 seconds.
// If the provided TTL is less than that, we set it to the minimum.
let expirationTtl = ttl;
if (expirationTtl < KV_STORE_MIN_TTL_IN_SECONDS) {
expirationTtl = KV_STORE_MIN_TTL_IN_SECONDS;
}
return await kvStore.put(key, value, { expirationTtl });
return kvStore.put(key, value, { expirationTtl });
},
delete: async (key) => {
return await kvStore.delete(key);
return kvStore.delete(key);
},
},
plugins: [tanstackStartCookies()],
Expand Down
6 changes: 1 addition & 5 deletions src/lib/auth/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import type { authClient } from '~/lib/auth/client';
import { authServer } from '~/lib/auth/server';

export type AuthErrors = Record<
keyof typeof authServer.$ERROR_CODES | keyof typeof authClient.$ERROR_CODES,
string
>;
export type AuthErrors = Record<keyof typeof authServer.$ERROR_CODES, string>;
11 changes: 11 additions & 0 deletions src/lib/env/drizzle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { createEnv } from '@t3-oss/env-core';
import * as z from 'zod/v4';

/** Env schema for Drizzle configuration */
export const drizzleEnv = createEnv({
server: {
DB_ENV: z.enum(['local', 'remote']),
},
runtimeEnv: process.env,
emptyStringAsUndefined: true,
});
2 changes: 1 addition & 1 deletion src/lib/form/components/form-checkbox-single.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ function FormCheckboxSingleItem({
const isDisabled = fieldSet?.disabled || disabled;

function handleCheckedChange(checked: boolean) {
field.handleChange(checked === true);
field.handleChange(checked);
}

const checkbox = (
Expand Down
2 changes: 1 addition & 1 deletion src/lib/form/components/form-reset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function FormReset({
}: React.ComponentPropsWithRef<typeof Button>) {
const form = useFormContext();

function handleReset(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) {
function handleReset(event: React.MouseEvent<HTMLButtonElement>) {
event.preventDefault();
form.reset();
}
Expand Down
4 changes: 2 additions & 2 deletions src/lib/form/components/form-root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ export function FormRoot({
}: React.ComponentPropsWithRef<'form'>) {
const form = useFormContext();

function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
async function handleSubmit(event: React.SubmitEvent<HTMLFormElement>) {
event.preventDefault();
form.handleSubmit();
await form.handleSubmit();
}

return (
Expand Down
4 changes: 2 additions & 2 deletions src/routes/api/auth.$.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ export const Route = createFileRoute('/api/auth/$')({
server: {
handlers: {
GET: async ({ request }: { request: Request }) => {
return await authServer.handler(request);
return authServer.handler(request);
},
POST: async ({ request }: { request: Request }) => {
return await authServer.handler(request);
return authServer.handler(request);
},
},
},
Expand Down
2 changes: 1 addition & 1 deletion src/routes/app/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function RouteComponent() {
toast.success(m.auth_sign_out_success_title(), {
description: m.auth_sign_out_success_description(),
});
navigate({ to: '/' });
await navigate({ to: '/' });
}

return (
Expand Down
2 changes: 1 addition & 1 deletion src/routes/auth/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { authGuestGuard } from '~/modules/auth/auth.utils';

export const Route = createFileRoute('/auth')({
validateSearch: zodValidator(authSearchParamsSchema),
beforeLoad: async () => await authGuestGuard(),
beforeLoad: async () => authGuestGuard(),
component: RouteComponent,
});

Expand Down
4 changes: 2 additions & 2 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import handler from '@tanstack/react-start/server-entry';
import { paraglideMiddleware } from '~/lib/i18n/server';

export default {
fetch(req: Request): Promise<Response> {
return paraglideMiddleware(req, () => handler.fetch(req));
async fetch(req: Request): Promise<Response> {
return paraglideMiddleware(req, async () => handler.fetch(req));
},
};
4 changes: 2 additions & 2 deletions src/start.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { createMiddleware, createStart } from '@tanstack/react-start';

const requestMiddleware = createMiddleware({ type: 'request' }).server(
function handler({ next }) {
async function handler({ next }) {
return next();
},
);

const functionMiddleware = createMiddleware({ type: 'function' }).server(
function handler({ next }) {
async function handler({ next }) {
return next();
},
);
Expand Down
5 changes: 5 additions & 0 deletions src/ui/components/core/chart.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
// oxlint-disable typescript/no-unnecessary-type-arguments
// oxlint-disable typescript/restrict-template-expressions
// oxlint-disable typescript/no-unsafe-type-assertion
// oxlint-disable typescript/no-unsafe-argument

import * as React from 'react';
import * as RechartsPrimitive from 'recharts';
import type { TooltipValueType } from 'recharts';
Expand Down
2 changes: 1 addition & 1 deletion src/ui/components/core/input-group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function InputGroupAddon({
data-align={align}
className={cn(inputGroupAddonVariants({ align }), className)}
onClick={(e) => {
if ((e.target as HTMLElement).closest('button')) {
if (e.target instanceof HTMLElement && e.target.closest('button')) {
return;
}
e.currentTarget.parentElement?.querySelector('input')?.focus();
Expand Down
12 changes: 2 additions & 10 deletions src/ui/components/core/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,7 @@ function Sidebar({
data-slot="sidebar"
data-mobile="true"
className="w-(--sidebar-width) bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden"
style={
{
'--sidebar-width': SIDEBAR_WIDTH_MOBILE,
} as React.CSSProperties
}
style={{ '--sidebar-width': SIDEBAR_WIDTH_MOBILE }}
side={side}
>
<SheetHeader className="sr-only">
Expand Down Expand Up @@ -604,11 +600,7 @@ function SidebarMenuSkeleton({
<Skeleton
className="h-4 max-w-(--skeleton-width) flex-1"
data-sidebar="menu-skeleton-text"
style={
{
'--skeleton-width': width,
} as React.CSSProperties
}
style={{ '--skeleton-width': width }}
/>
</div>
);
Expand Down
4 changes: 3 additions & 1 deletion src/ui/components/core/sonner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,22 @@ import {
OctagonXIcon,
Loader2Icon,
} from 'lucide-react';
import { useTheme } from 'next-themes';
import {
Toaster as RootToaster,
type ToasterProps,
toast as baseToast,
} from 'sonner';

import { useTheme } from '~/ui/styles/theme';

const toast = baseToast;

function Toaster({ ...props }: ToasterProps) {
const { theme = 'system' } = useTheme();

return (
<RootToaster
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
theme={theme as ToasterProps['theme']}
className="toaster group"
icons={{
Expand Down
12 changes: 6 additions & 6 deletions src/ui/hooks/use-media-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const directionOperators: Record<BreakpointDirection, string> = {
'max-width': '<',
};

interface Options<TInitialValue> {
interface Options<TInitialValue extends boolean | undefined> {
/**
* Initial value to use before the media query listener is set up.
* This opens up the possibility of knowing the media query match state
Expand Down Expand Up @@ -80,9 +80,7 @@ export function useMediaQuery<TInitialValue extends boolean | undefined>(
options?: Options<TInitialValue>,
) {
const { initialValue } = options ?? {};
const [isMatches, setIsMatches] = React.useState<boolean | undefined>(
initialValue,
);
const [isMatches, setIsMatches] = React.useState(initialValue);

React.useEffect(
function watchMediaSize() {
Expand All @@ -92,10 +90,12 @@ export function useMediaQuery<TInitialValue extends boolean | undefined>(
);

function onChangeMediaQuery(event: MediaQueryListEvent) {
setIsMatches(event.matches);
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
setIsMatches(event.matches as TInitialValue);
}
mediaQuery.addEventListener('change', onChangeMediaQuery);
setIsMatches(mediaQuery.matches);
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
setIsMatches(mediaQuery.matches as TInitialValue);
return () => mediaQuery.removeEventListener('change', onChangeMediaQuery);
},
[breakpoint, direction],
Expand Down
2 changes: 2 additions & 0 deletions src/ui/styles/theme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
} from 'next-themes';
import * as React from 'react';

export type Theme = 'light' | 'dark' | 'system';

/**
* Theme provider component that wraps the application
* to configures the next-themes provider.
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"vite.config.ts",
"alchemy.run.ts",
"eslint.config.ts",
"commitlint.config.ts"
"commitlint.config.ts",
"drizzle.config.ts"
],
"exclude": ["node_modules"],
"compilerOptions": {
Expand Down