Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c83eb1c
Add workspace biome setup
gentamura Sep 20, 2025
b51a6dc
Add db workspace package
gentamura Sep 21, 2025
b401731
Document db package
gentamura Sep 21, 2025
57fd17c
Add bun test for db package
gentamura Sep 21, 2025
2ea2b20
Document bun testing workflow
gentamura Sep 21, 2025
f5af867
Document architecture guidance
gentamura Sep 23, 2025
bb6b84b
Add api auth and types packages
gentamura Sep 23, 2025
93e2713
Aggregate shared API types
gentamura Sep 26, 2025
965eaf9
Add js extensions to index exports
gentamura Sep 26, 2025
3c0a96b
Inline global connection cache
gentamura Sep 26, 2025
7aea53c
Update biome target directories
gentamura Sep 28, 2025
8f1ae0c
Update tsconfig to exclude test files
gentamura Sep 28, 2025
a2410b8
Add supabase authentication provider
gentamura Sep 28, 2025
9ebb16f
Document Supabase auth provider
gentamura Sep 28, 2025
74fa236
Use composite cursor for categories pagination
gentamura Sep 29, 2025
e6f05cc
Sanitize health check errors in production
gentamura Sep 29, 2025
ca31395
Ensure error messages always return strings
gentamura Sep 29, 2025
a9c8871
Decouple header authentication token from Supabase
gentamura Sep 30, 2025
8d9a45d
Await rejection assertions in Supabase auth tests
gentamura Sep 30, 2025
5a7abad
Bump drizzle-orm and postgres catalog versions
gentamura Sep 30, 2025
f6dc7e4
Refine Postgres connection caching
gentamura Sep 30, 2025
fd4aa69
Lazy initialize default Postgres database
gentamura Sep 30, 2025
9635447
Harden RLS policies with ownership checks
gentamura Sep 30, 2025
5601c09
Normalize category pagination limits
gentamura Oct 1, 2025
2f72749
Extract shared authentication helper for API routes
gentamura Oct 1, 2025
57f5506
Add CI
gentamura Oct 1, 2025
d027a2b
Update tsconfig settings at build time
gentamura Oct 1, 2025
01dae1f
Fix type errors in supabase auth test
gentamura Oct 1, 2025
d6550dd
Harden category pagination limit parsing
gentamura Oct 2, 2025
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
16 changes: 16 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: CI

on:
push:
branches: [main]
pull_request:

jobs:
lint:
uses: listee-dev/listee-ci/.github/workflows/lint.yml@main

typecheck:
uses: listee-dev/listee-ci/.github/workflows/typecheck.yml@main

test:
uses: listee-dev/listee-ci/.github/workflows/test.yml@main
23 changes: 20 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,40 @@
## Project Structure & Module Organization
This monorepo uses Bun workspaces. Each package lives in `packages/<name>` with source under `src/`. Build outputs flow to `dist/` and must never be edited manually. Shared tooling lives at the root (`tsconfig.json`, `biome.json`, `vitest.config.ts`, `bun.lock`); review cross-package impact before changing these files.

## Dependency Management
- Use the root `package.json` `catalog` to pin shared dependency versions. Packages reference catalog entries with the `"catalog:"` protocol.
- Add new shared dependencies to the root catalog before consuming them in individual packages. This keeps versions centralized and avoids drift across workspaces.
- Always run `bun install` from the repository root so that catalog resolutions and the shared `bun.lock` stay in sync.
- When publishing npm packages, ensure you build or pack with Bun (`bun pm pack` / `bun publish`) so catalog references collapse to concrete semver ranges.

## Build, Test, and Development Commands
- `bun install` — Sync dependencies and respect the lockfile used in CI.
- `bun run build` — Run the TypeScript project references build, emitting artifacts to every `dist/` folder.
- `bun run lint` — Execute Biome formatter and linter in a single pass.
- `bun run test` — Launch Vitest in the Node environment for the entire workspace.
- `bun run lint` — Execute Biome formatter and linter in a single pass (only `packages/*/src/**` is scanned via `files.includes`).
- `bun test` or `bun run test` — Execute Bun's built-in test runner across the workspace (see `packages/db/src/index.test.ts` for examples).
- `bun run changeset` — Draft release notes and version bumps via Changesets.
- `bun run clean` — Remove build artifacts and reinstall dependencies (does not delete untracked source files).

## Coding Style & Naming Conventions
TypeScript runs with `strict` enabled; avoid implicit `any` and replace `as` casts with dedicated type guards or the `satisfies` operator where appropriate. Prefer `unknown` for external inputs. Use kebab-case for package folders, PascalCase for types and enums, and camelCase for variables and functions. Always commit the formatter output produced by `bun run lint`.
All source comments, test names, and test descriptions must be written in English.

## Testing Guidelines
Vitest is the test runner. Co-locate tests as `*.test.ts` files or inside `__tests__/`. Name suites with behavior-focused sentences so failures highlight intent. For new features, cover both success paths and the most representative error paths. Run `bun run test` (and `bun run build` when touching types) before opening a PR.
Use Bun's built-in test runner. Co-locate tests as `*.test.ts` files or inside `__tests__/`. Name suites with behavior-focused sentences so failures highlight intent. For new features, cover both success paths and the most representative error paths. Run `bun test` (and `bun run build` when touching types) before opening a PR.

## Commit & Pull Request Guidelines
Write imperative commit summaries under 50 characters (e.g., `Add chat session schema`) and include context, impact, and test notes in the body when needed. PR descriptions must capture purpose, key changes, test evidence, linked issues, and screenshots or logs for user-facing updates. Attach the latest `.changeset/` entry whenever a release is required.

## Security & Release Management
Never commit secrets; surface runtime configuration via factories that accept environment values. Version changes must follow SemVer, with breaking updates declared in Changesets. Verify releases by checking the generated changelog and confirming publication for each package on npm.
Enable secret scanning and push protection in CI (e.g., gitleaks), and require npm 2FA + provenance for publishing.

## Architecture Playbook
- Maintain a single dependency direction (`routes → queries → services → repositories`) so that upper layers stay ignorant of lower-level details.
- `routes` should delegate exclusively to `queries`, translate their results into HTTP responses, and decide status codes. Avoid placing business logic here.
- `queries` compose the necessary `services` and `repositories` per use case. Inject dependencies through factories so tests can swap in mocks easily.
- `services` may depend on `repositories`, but repositories must never depend on services. Extract complex domain logic into dedicated modules and keep the service layer thin.
- `repositories` encapsulate external SDK, SQL, or KV access and return plain or domain-specific types (`string`, `Date`, structured objects) to callers.
- Separate authentication and authorization concerns inside `packages/auth`. Place runtime-specific adapters under `authentication/` (`header.ts`, `supabase.ts`, shared utilities, and `errors.ts`) and domain policies under `authorization/` (e.g., `policies/chat.ts` exposing `canAccessChat`). Policies can declare repository interfaces and receive concrete implementations via dependency injection.
- Supabase JWT verification is handled by `createSupabaseAuthentication`, which fetches the JWKS from `.well-known/jwks.json`; only extend this provider via dedicated modules so JWKS caching and claim validation remain centralized.
- Process authenticated requests in the order `Route Handler → Authentication → Queries → Authorization → Services/Repositories`, passing the authenticated actor into queries before evaluating policies.
42 changes: 39 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# listee-libs

## Overview
`listee-libs` is the public monorepo that hosts the Listee SDK packages. Each module is published under the `@listee/*` scope so downstream applications (API, web, CLI, MCP) can consume them independently. The initial release focuses on `@listee/types` and `@listee/db`, with additional packages (`auth`, `chat`, `ui`, `sdk`) following incrementally.
`listee-libs` is the public monorepo that hosts the Listee SDK packages. Each module is published under the `@listee/*` scope so downstream applications (API, web, CLI, MCP) can consume them independently. The initial release focuses on `@listee/db` (database access layer) and `@listee/auth` (token verification utilities), with `@listee/types` and other packages (`chat`, `ui`, `sdk`) landing incrementally.

## Repository Layout
- `packages/<name>` — Individual packages with their implementation in `src/` and compiled output in `dist/`.
Expand All @@ -11,15 +11,51 @@
- `.github/workflows/` — CI pipelines based on `listee-dev/listee-ci@v1` workflows.

## Getting Started
1. Install Bun `1.2.19` (or later). We recommend pinning via `"packageManager": "bun@1.2.19"` in the root package.json for reproducibility.
2. Run `bun install` to sync dependencies.
1. Install Bun `1.2.22` (or later). We recommend pinning via `"packageManager": "bun@1.2.22"` in the root package.json for reproducibility.
2. Run `bun install` at the repository root (catalog-aware installation for every workspace).
3. Use `bun run lint`, `bun run build`, and `bun run test` to verify changes locally.
4. Initialize Changesets with `bun run changeset init` if you are bootstrapping a fresh clone.

## Packages

### `@listee/db`
- Provides a thin Postgres + Drizzle ORM layer with connection caching for local development.
- Requires `POSTGRES_URL` to be defined before calling `createPostgresConnection`.
- Exposes helpers:
- `createPostgresConnection` — returns a cached `postgres` client (disabled in production); accepts optional overrides.
- `db` — shared `drizzle-orm` database instance backed by the cached connection.
- `createRlsClient`/`createDrizzle` — wrap transactions with Supabase-style RLS claims and role switching.
- Publishes generated types alongside compiled output (`sideEffects: false` for optimal tree-shaking).
- Ships with Bun-based unit tests (`packages/db/src/index.test.ts`) that mock `postgres`/`drizzle-orm`. Run `bun test` from the repo root to execute them.

### `@listee/auth`
- Exposes reusable authentication providers under `packages/auth/src/authentication/`.
- `createHeaderAuthentication` performs lightweight header extraction suitable for development stubs.
- `createSupabaseAuthentication` validates Supabase-issued JWT access tokens against the project's JWKS (`/auth/v1/.well-known/jwks.json`), enforces issuer/audience/role constraints, and returns a typed `SupabaseToken` payload.
- Shared utilities (`shared.ts`, `errors.ts`) handle predictable error surfaces; tests live beside the implementation (`supabase.test.ts`) and exercise positive/negative paths.
- The package emits declarations from `src/` only; test files are excluded from `dist/` via `tsconfig.json`.

## Contribution Notes
- Follow the guidance in `AGENTS.md` for agent automation workflows and repository conventions.
- Keep documentation and code comments in English.
- Coordinate feature work through focused branches (`feature/...`, `chore/...`, etc.) and submit PRs with clear descriptions, linked issues, and test evidence.

## Architecture Guidelines

### Responsibility Boundaries
- `routes` only depend on `queries`, translate the return values into HTTP responses, and decide status codes.
- `queries` orchestrate the necessary `services` and `repositories` for each use case and accept dependencies via factories so they remain easy to test.
- `services` may depend on `repositories` (never the other way around). When a service grows large, consider moving domain logic under a dedicated `domain/` module and keeping application services thin.
- `repositories` sit at the bottom layer and encapsulate external SDK calls, SQL, or KV access. They should return plain TypeScript/domain types (`string`, `Date`, structured objects) to upstream layers.

### Dependency Flow
Keep a single direction: `routes → queries → (services → repositories)`. With the stack arranged this way you can reuse everything below `queries` across different runtimes (e.g., Cloudflare Workers) and mock each layer in isolation during tests.

### Authentication vs Authorization
- Treat authentication (identifying who the caller is) and authorization (deciding what that caller may do) as separate concerns under the `auth` package.
- Place authentication adapters in `packages/auth/src/authentication/` and expose helpers such as `getAuthenticatedUser(request)` so each runtime can plug in its own token/session verification.
- Organize authorization policies under `packages/auth/src/authorization/` with domain-specific modules (e.g., `policies/chat.ts` providing `canAccessChat`). Policies may declare repository interfaces that the application injects, keeping policy evaluation independent from data fetching details.
- The recommended execution order for an authenticated endpoint is `Route Handler → Authentication → Queries → Authorization → Services/Repositories`. Queries receive the authenticated actor (for example, via context) and call the relevant authorization policy before touching domain services.

## Release Process
Changesets drive versioning and publishing. Merging to `main` triggers the shared CI pipelines, including the release workflow that prepares npm publications. Confirm published versions for `@listee/types` and `@listee/db` before announcing availability to downstream projects.
28 changes: 28 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"$schema": "https://biomejs.dev/schemas/2.2.4/schema.json",
"formatter": {
"enabled": true,
"indentStyle": "space"
},
"assist": {
"actions": {
"source": {
"organizeImports": "on"
}
}
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"javascript": {
"formatter": {
"quoteStyle": "double"
}
},
"files": {
"includes": ["packages/*/src/**"]
}
}
98 changes: 98 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "listee-libs",
"version": "0.0.0",
"private": true,
"packageManager": "bun@1.2.22",
"catalog": {
"drizzle-orm": "^0.44.5",
"hono": "^4.4.4",
"postgres": "^3.4.7",
"jose": "^5.2.3"
},
"workspaces": [
"packages/*"
],
"scripts": {
"lint": "biome check",
"lint:fix": "biome check --write",
"test": "bun test"
},
"devDependencies": {
"@biomejs/biome": "2.2.4",
"@types/bun": "1.2.22"
}
}
22 changes: 22 additions & 0 deletions packages/api/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "@listee/api",
"version": "0.0.0",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"sideEffects": false,
"files": [
"dist"
],
"scripts": {
"build": "tsc --project tsconfig.build.json",
"clean": "rm -rf dist"
},
"dependencies": {
"@listee/auth": "workspace:*",
"@listee/db": "workspace:*",
"@listee/types": "workspace:*",
"hono": "catalog:"
}
}
Loading