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
11 changes: 7 additions & 4 deletions .github/workflows/adamantite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,10 @@ jobs:
fail-fast: false
matrix:
include:
- name: lint
command: bun run check
- name: check
command: bun run codegen && bun run check
- name: format
command: bun run format --check
- name: types
command: bun run typecheck
- name: monorepo
command: bun run check:monorepo

Expand All @@ -40,6 +38,11 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 24

- name: Setup Bun
uses: oven-sh/setup-bun@v2

Expand Down
17 changes: 0 additions & 17 deletions .oxlintrc.json

This file was deleted.

68 changes: 3 additions & 65 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,13 @@

## Project Structure

- Projects are organized in the following folders:
- `apps` - Cross-platform applications and user-facing products.
- `infra` - Infrastructure as code for local development and cloud providers.
- `packages` - Shared internal packages for use across apps.
- `scripts` - Scripts for random tasks, such as syncing the project with the template and graphing dependencies.
- `tooling` - Shared development configuration and script helpers. If a configuration is used across workspaces and not related to a specific package, it should go here.
- Apps and packages have their code in the `src` folder.
- Apps organized in the following folders:
- `app`/`routes`/`entrypoints` - The router/entrypoint of the application, usually using file-based routing.
- `features` - Feature-based modules.
- `shared` - Shared utilities and helpers.
- We enforce a unidirectional import flow between these three folders. The code only flows downwards to the routing folder, never going upwards.
- `shared` only imports outside dependencies. It cannot import from `features` or `routes`. Modules in `shared`  should be self-contained but can import from other modules in `shared`.
- `shared` should be used for services, utilities, and helpers that are used across the application.
- `features` can import from `shared`, but cannot import from other features.
- `routes` can import from `shared` and `features`, but routes cannot from other routes.
- Exception: in `apps/api`, routes may import other routes for Hono routing composition.
Check the [project structure documentation](./docs/project-structure.md) for an overview of the project structure and where to find different types of code.

## Code Quality

- We use `adamantite` for linting, formatting and type checking.
- `adamantite check` to run linting checks.
- `adamantite format` to format the code.
- `tsc --noEmit` to type check the code.
- `adamantite analyze` to analyze the code for unused dependencies.
- Always run `bun run format` after editing files.
- Run `bun run test` to run the test suite.
- After making changes, run `bun run check`, `bun run typecheck` and `bun run test` to ensure the code is still valid.
- After making changes, run `bun run check` and `bun run test` to ensure the code is still valid.
- After deleting files, run `bun run analyze` to ensure we are not using any dependencies that are not needed.

## Testing
Expand Down Expand Up @@ -93,46 +72,5 @@
- Use the `function` keyword for components.
- Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
- Use declarative JSX.

### UI and Styling

- Use components inside `@init/ui` for web projects and `#shared/components/ui` for mobile projects.
- Use components inside `@init/ui` for web projects and `@init/native-ui` for mobile projects.
- Use the `cn` function inside `@init/utils/ui` for classname composition.

## Database (applies to `packages/db/**`)

- Our database schema is in `packages/db/src/schema.ts`.
- We use Drizzle as our ORM. Follow Drizzle best practices.
- Use timestamps in `packages/db/src/schema.ts` where it makes sense.
- Use prefixed IDs for entities; see `packages/db/src/schema.ts` and the `id` function.
- Prefixes should be 4 letters with no conflicts.

## Expo (applies to `apps/mobile/**`)

- Prefer functional components with React hooks.
- Leverage Expo SDK features and APIs.
- Use React Navigation for structure and navigation.
- Manage assets with Expo's asset system.
- Use Reanimated for performant animations.

## Hono (applies to `apps/api/**`)

- Use middleware for authentication and logging.
- Implement route handlers using `app.get`, `app.post`, etc.
- Structure routes modularly.
- Handle errors globally with `app.onError`.
- Use `c.text()`, `c.json()`, and `c.redirect()` for responses.
- Leverage caching with `Cache-Control` or KV storage.

## Web UI (applies to `apps/app/**`, `apps/desktop/**`, `apps/docs/**`, `apps/extension/**`, `apps/web/**`)

- Use components inside `@init/ui` with proper composition and customization.
- Leverage Radix UI primitives for accessible interactive components.
- Follow Tailwind CSS class naming conventions and utility patterns.
- Implement mobile-first responsive design with Tailwind breakpoints.
- Maintain consistent spacing and layout using Tailwind's spacing scale.
- Use Tailwind's color system for consistent theming.
- Implement dark mode support using Tailwind's `dark` variant.
- Ensure components are accessible following WCAG guidelines.
- Keep component styles modular and reusable.
- Optimize component bundle size through proper code splitting.
7 changes: 3 additions & 4 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
"bump:deps": "bun update --interactive",
"clean": "git clean -xdf .cache .turbo dist node_modules",
"dev": "bun --hot src/index.ts",
"start": "bun --bun src/index.ts",
"typecheck": "tsc --noEmit"
"start": "bun --bun src/index.ts"
},
"dependencies": {
"@arcjet/ip": "^1.0.0-beta.15",
Expand All @@ -39,7 +38,7 @@
},
"devDependencies": {
"@tooling/tsconfig": "workspace:*",
"@types/bun": "1.3.5",
"typescript": "5.9.3"
"@types/bun": "catalog:",
"typescript": "catalog:"
}
}
2 changes: 1 addition & 1 deletion apps/api/src/routes/v1/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default factory
validator("query", z.object({ name: z.string().optional() })),
(c) => {
const query = c.req.valid("query")
return c.text(`Hello ${query?.name ?? "Hono"}!`)
return c.text(`Hello ${query.name ?? "Hono"}!`)
}
)
.get("/me", requireSession, (c) => c.json(c.var.session.user))
7 changes: 1 addition & 6 deletions apps/api/src/shared/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@ import type { AppContext } from "#shared/types.ts"
export const requireSession = createMiddleware<
DeepMerge<AppContext, { Variables: { session: Session } }>
>(async (c, next) => {
if (c.var.session) {
await next()
return
}

const session = await c.var.auth.api.getSession({
headers: c.req.raw.headers,
})
Expand All @@ -34,7 +29,7 @@ export const requireSession = createMiddleware<
*/
export function withRateLimiting(interval: TimeExpression, limit: number) {
return rateLimiter<AppContext>({
keyGenerator: (c) => c.var.session?.user.id ?? findIp(c.req.raw) ?? "unknown",
keyGenerator: (c) => c.var.session?.user.id ?? findIp(c.req.raw),
Comment thread
adelrodriguez marked this conversation as resolved.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep a fallback key for anonymous rate-limited requests

The public /health route is the current caller of withRateLimiting, so c.var.session is always null there. findIp(c.req.raw) can also fail to resolve an address (for example in local/dev setups or behind proxies that do not forward client IPs), and hono-rate-limiter uses whatever keyGenerator returns as the store key. After removing the 'unknown' fallback, all of those anonymous requests collapse onto the same undefined bucket, so a few probes can start 429ing every other health check.

Useful? React with 👍 / 👎.

limit,
standardHeaders: "draft-7",
windowMs: ms(interval),
Expand Down
1 change: 1 addition & 0 deletions apps/api/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"extends": "@tooling/tsconfig/base.json",
"compilerOptions": {
"types": ["bun"],
"rootDir": ".",
"jsx": "react-jsx",
"noEmit": true,
Expand Down
2 changes: 1 addition & 1 deletion apps/api/turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"outputs": ["dist/**"]
},
"deploy": {
"dependsOn": ["^format", "^lint", "^typecheck"],
"dependsOn": ["^format", "^lint"],
"env": []
}
}
Expand Down
7 changes: 3 additions & 4 deletions apps/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
"clean": "git clean -xdf .cache .turbo dist node_modules",
"dev": "bun --bun vite dev",
"preview": "bun --bun vite preview",
"start": "node .output/server/index.mjs",
"typecheck": "tsc --noEmit"
"start": "node .output/server/index.mjs"
},
"dependencies": {
"@init/auth": "workspace:*",
Expand Down Expand Up @@ -46,14 +45,14 @@
"@tooling/env": "workspace:*",
"@tooling/internationalization": "workspace:*",
"@tooling/tsconfig": "workspace:*",
"@types/node": "24.10.1",
"@types/node": "catalog:",
"@types/react": "19.1.13",
"@types/react-dom": "19.1.9",
"@vitejs/plugin-react": "5.1.2",
"babel-plugin-react-compiler": "^19.1.0-canary-7e86e86-20250120",
"nitro": "3.0.1-alpha.1",
"tailwindcss": "4.1.18",
"typescript": "5.9.3",
"typescript": "catalog:",
"vite": "7.3.1"
}
}
2 changes: 1 addition & 1 deletion apps/app/src/routes/_authenticated/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function RouteComponent() {
<AvatarFallback>{user.name[0] ?? "U"}</AvatarFallback>
</Avatar>
<div>
<div className="font-medium">{user.name ?? "Unknown"}</div>
<div className="font-medium">{user.name}</div>
<div className="text-muted-foreground">{user.email}</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/app/src/shared/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { singleton } from "@init/utils/singleton"

export const logger = singleton("logger:app", () =>
buildLogger([LoggerCategory.DEFAULT], {
async: globalThis.window === undefined,
async: !("window" in globalThis),
isDevelopment: import.meta.env.DEV,
})
)
1 change: 1 addition & 0 deletions apps/app/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"extends": "@tooling/tsconfig/app.json",
"compilerOptions": {
"types": ["node"],
"jsx": "preserve"
},
"include": ["src", "reset.d.ts", "vite.config.ts"],
Expand Down
2 changes: 1 addition & 1 deletion apps/app/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { defineConfig } from "vite"

// @ts-expect-error Bun resolves duplicate vite copies in its virtual store, causing plugin type mismatches
export default defineConfig(({ mode }) => {
void ensureEnv(mode)
void ensureEnv(mode, import.meta.url)

return {
envPrefix: ["PUBLIC_"],
Expand Down
5 changes: 2 additions & 3 deletions apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
"codegen": "paraglide-js compile --project ../../tooling/internationalization/project.inlang --outdir ./src/shared/internationalization",
"bump:deps": "bun update --interactive",
"clean": "git clean -xdf .cache .turbo dist node_modules",
"dev": "tauri dev",
"typecheck": "tsc --noEmit"
"dev": "tauri dev"
},
"dependencies": {
"@init/env": "workspace:*",
Expand Down Expand Up @@ -41,7 +40,7 @@
"@types/react-dom": "19.1.9",
"@vitejs/plugin-react": "5.1.2",
"babel-plugin-react-compiler": "^19.1.0-canary-7e86e86-20250120",
"typescript": "5.9.3",
"typescript": "catalog:",
"vite": "7.3.1"
}
}
2 changes: 1 addition & 1 deletion apps/desktop/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"

export default defineConfig(({ mode }) => {
void ensureEnv(mode)
void ensureEnv(mode, import.meta.url)
const host = process.env.TAURI_DEV_HOST

return {
Expand Down
3 changes: 1 addition & 2 deletions apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"clean": "git clean -xdf .cache .turbo dist node_modules",
"dev": "astro dev",
"preview": "astro preview",
"typecheck": "tsc --noEmit",
"typegen": "astro sync"
},
"dependencies": {
Expand All @@ -34,6 +33,6 @@
"@types/react": "19.1.13",
"@types/react-dom": "19.1.9",
"tailwindcss": "4.1.18",
"typescript": "5.9.3"
"typescript": "catalog:"
}
}
2 changes: 0 additions & 2 deletions apps/docs/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
"extends": "@tooling/tsconfig/app.json",
"compilerOptions": {
"jsx": "preserve",
// Properly support importing CJS modules in ESM
"esModuleInterop": true,
"plugins": [{ "name": "@astrojs/ts-plugin" }]
},
"include": [".astro/types.d.ts", "src", "reset.d.ts", "astro.config.ts"],
Expand Down
4 changes: 1 addition & 3 deletions apps/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@
"build:firefox": "wxt build -b firefox",
"clean": "git clean -xdf .cache .turbo dist node_modules",
"codegen": "paraglide-js compile --project ../../tooling/internationalization/project.inlang --outdir ./src/shared/internationalization",
"compile": "tsc --noEmit",
"bump:deps": "bun update --interactive",
"dev": "wxt",
"dev:firefox": "wxt -b firefox",
"postinstall": "wxt prepare",
"typecheck": "tsc --noEmit",
"typegen": "wxt prepare",
"zip": "wxt zip",
"zip:firefox": "wxt zip -b firefox"
Expand Down Expand Up @@ -44,7 +42,7 @@
"@types/react-dom": "19.1.9",
"@wxt-dev/auto-icons": "1.1.0",
"@wxt-dev/module-react": "1.1.5",
"typescript": "5.9.3",
"typescript": "catalog:",
"wxt": "0.20.13"
}
}
1 change: 1 addition & 0 deletions apps/extension/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"extends": "@tooling/tsconfig/app.json",
"compilerOptions": {
"types": ["chrome"],
"jsx": "preserve"
},
"include": ["src", "reset.d.ts", "./.wxt/wxt.d.ts", "wxt.config.ts"],
Expand Down
2 changes: 1 addition & 1 deletion apps/extension/wxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default defineConfig({
modules: ["@wxt-dev/module-react", "@wxt-dev/auto-icons"],
srcDir: "src",
vite: ({ mode }) => {
void ensureEnv(mode)
void ensureEnv(mode, import.meta.url)

return {
plugins: [
Expand Down
2 changes: 2 additions & 0 deletions apps/mobile/babel.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* oxlint-disable unicorn/prefer-module */

module.exports = (api) => {
// oxlint-disable-next-line no-unsafe-call
api.cache(true)
Expand Down
2 changes: 2 additions & 0 deletions apps/mobile/metro.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* oxlint-disable unicorn/prefer-module */

const { getSentryExpoConfig } = require("@sentry/react-native/metro")
const { withUniwindConfig } = require("uniwind/metro")

Expand Down
4 changes: 2 additions & 2 deletions apps/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
"prebuild": "expo prebuild --clean",
"start": "expo start",
"test": "bun test",
"typecheck": "tsc --noEmit",
"web": "expo start --web"
},
"dependencies": {
Expand Down Expand Up @@ -81,10 +80,11 @@
"@inlang/paraglide-js": "2.8.0",
"@sentry/cli": "2.56.0",
"@tooling/tsconfig": "workspace:*",
"@types/node": "catalog:",
"@types/react": "19.1.13",
"babel-plugin-react-compiler": "^19.1.0-canary-7e86e86-20250120",
"babel-preset-expo": "~54.0.0",
"expo-doctor": "1.17.14",
"typescript": "5.9.3"
"typescript": "catalog:"
}
}
7 changes: 5 additions & 2 deletions apps/mobile/src/shared/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ export const isDarkMode = Appearance.getColorScheme() === "dark"
export const isIOS = Platform.OS === "ios"
export const isAndroid = Platform.OS === "android"

// @ts-expect-error - no index signature for globalThis
export const isFabric = Boolean(globalThis?.nativeFabricUIManager)
type FabricGlobal = typeof globalThis & {
nativeFabricUIManager?: unknown
}

export const isFabric = Boolean((globalThis as FabricGlobal).nativeFabricUIManager)

export const ios = <T>(value: T) => (isIOS ? value : undefined)
export const android = <T>(value: T) => (isAndroid ? value : undefined)
Loading
Loading