This repository is a TypeScript monorepo using Bun, Turborepo, and Biome. You are an expert software engineer working in this environment.
- Be Extremely Concise: Sacrifice grammar for brevity. Output code and essential explanations only.
- Safety First: Never commit secrets. verify all changes with tests.
- Modern Standards: Use modern TypeScript (ESNext).
All commands use bun. Never use npm, yarn, or pnpm.
| Task | Command |
|---|---|
| Install | bun install |
| Build | bun run build (uses tsdown) |
| Clean | bun run clean |
| Lint (check only) | bun run lint |
| Fix lint + format | bun run check |
| Format only | bun run format |
| Type-check | bun run type-check |
| All tests | bun run test |
| Unit tests | bun run test:unit |
| Integration tests | bun run test:integration |
| Dev mode (watch) | bun run test:dev |
| Unused exports | bun run check:unused (knip) |
Run from the package directory, not the repo root:
cd packages/core
bun run test src/scheduler/services/job-processor.test.ts
# Unit only:
bun run test:unit tests/unit/backoff.test.tsFilter a specific package from root:
bun run test:core # all @monque/core tests
bun run test:unit:core # unit only for coreRuns automatically: type-check + biome check --write on staged files.
monque/
├── packages/
│ ├── core/ # @monque/core - Main scheduler logic
│ │ ├── src/
│ │ │ ├── scheduler/ # Monque class + internal services
│ │ │ ├── jobs/ # Job types, guards
│ │ │ ├── events/ # Event type maps
│ │ │ ├── workers/ # Worker types
│ │ │ ├── shared/ # Errors, utils (backoff, cron)
│ │ │ └── index.ts # Public API barrel
│ │ └── tests/
│ │ ├── unit/ # Pure logic tests (no DB)
│ │ ├── integration/ # Full flow with Testcontainers
│ │ ├── factories/ # fishery factories + faker
│ │ └── setup/ # Test utils, global setup
│ └── tsed/ # @monque/tsed - Ts.ED DI integration
├── apps/docs/ # Documentation site (Astro)
├── specs/ # Specifications
└── biome.json # Linter/formatter config
- Indentation: Tabs (width 2)
- Quotes: Single quotes
- Semicolons: Always
- Line width: 100 characters
| Element | Style | Example |
|---|---|---|
| Files | kebab-case | job-processor.ts, change-stream-handler.ts |
| Classes | PascalCase | Monque, JobProcessor, MonqueError |
| Functions | camelCase | calculateBackoff, getNextCronDate |
| True constants | UPPER_SNAKE_CASE | DEFAULT_BASE_INTERVAL, MAX_BACKOFF |
as const objects |
PascalCase (UPPER_SNAKE keys) | JobStatus.PENDING |
| Types/Interfaces | PascalCase, no I prefix |
MonqueOptions, SchedulerContext |
| Union types from const | {Name}Type suffix |
JobStatusType from JobStatus |
Biome auto-sorts imports into these groups (separated by blank lines):
- URL imports
- Built-ins (
node:url,bun:test) + external packages (mongodb,zod) - (blank line)
- Internal aliases (
@/utils,@tests/factories) - (blank line)
- Relative imports (
./types.js)
Rules:
import type { ... }for type-only imports (enforced byverbatimModuleSyntax)- Mixed:
export { type Job, JobStatus }with inlinetypekeyword - Relative imports use
.jsextensions (from './types.js') - Path alias imports do NOT use extensions (
from '@/jobs')
Strict mode with these extra flags enabled:
noUncheckedIndexedAccess- Index signatures returnT | undefinedexactOptionalPropertyTypes-undefinedmust be explicit in optional propsnoImplicitOverride-overridekeyword requirednoPropertyAccessFromIndexSignature- Must use bracket notation for index sigsnoUnusedLocals/noUnusedParameters
Rules:
- No
any. Useunknownwith type guards. Generic defaults:<T = unknown>. - No non-null assertions (
!). Use optional chaining or type guards. - No enums. Use
as constobjects:export const JobStatus = { PENDING: 'pending', PROCESSING: 'processing' } as const; export type JobStatusType = (typeof JobStatus)[keyof typeof JobStatus];
- Explicit return types on all public API methods.
- Named exports only. Zero default exports in the entire codebase.
Custom error hierarchy - all extend MonqueError:
MonqueError
├── InvalidCronError
├── ConnectionError
├── ShutdownTimeoutError
├── WorkerRegistrationError
├── JobStateError
├── InvalidCursorError
└── AggregationTimeoutError
Patterns:
- Guard-style early throws for validation
- Try/catch with re-wrapping at service boundaries
- Catch-and-emit for background operations (polling, heartbeats)
- Catch-and-ignore for shutdown cleanup paths
- Error normalization:
const err = error instanceof Error ? error : new Error(String(error))
- Every directory has an
index.tsbarrel re-exporting its public API - Root
src/index.tsis the single public entrypoint, grouped by category with comments - Use
export type { ... }for pure type re-exports - Never use default exports
- Monque class: Facade extending typed
EventEmitter(type-safeemit/on/once/off) - Internal services:
JobScheduler,JobManager,JobQueryService,JobProcessor,ChangeStreamHandler - All services receive a shared
SchedulerContextinterface (manual constructor injection) - Lazy init: Services null-initialized, created in
initialize(), private getters throw if accessed before init
- NO Mongoose. Native
mongodbdriver only. - Atomic locking:
findOneAndUpdatemandatory for picking up jobs - Idempotency:
upsert: truewith$setOnInserton{ name, uniqueKey } - Backoff: Exponential
min(2^failCount * base, MAX), reset status topending
- Decorator-based:
@JobController(namespace),@Job(name),@Cron(pattern) - Metadata stored via
Store.from(target).set(MONQUE, ...), collected bycollectJobMetadata()
Framework: Vitest with globals: true (no need to import describe/it/expect).
- Tests in
tests/directory (NOT colocated with source) tests/unit/- Mock DB withvi.spyOn, test logic isolation (5s timeout)tests/integration/- MongoDB via Testcontainers, full flows (30s timeout)tests/factories/-fisheryfactories with@faker-js/fakertests/setup/-global-setup.ts,seed.ts,test-utils.ts
@/->./src@tests/->./tests@test-utils/->./tests/setup
createMockContext()- FullSchedulerContextwithvi.fn()stubsJobFactorywith helpers:.pending(),.processing(),.completed(),.failed()getTestDb(),cleanupTestDb(),clearCollection(),uniqueCollectionName()waitFor(),stopMonqueInstances(),triggerJobImmediately(),findJobByQuery()
Always test: Happy Path, Idempotency, Resilience (backoff, race conditions).
- Read related source files before editing
- Plan changes if complex
- Implement following all style rules above
- Test - add/update tests covering changes
- Verify - run
bun run checkandbun run test:unitbefore finishing