// codebase guide
Internal reference for navigating, understanding, and extending the Velocity framework.
File Map & Sizes
Reading Order
Don't start with application.ts. Build up to it.
- metadata.ts (60 lines) — 3-level WeakMap replaces reflect-metadata.
CLASS_KEYseparates class-level from property-level. - container.ts (128 lines) —
resolve(): cache → cycle check → lookup → parent fallback →createInstance(). - decorators/route.ts (97 lines) — The "pending metadata" pattern. Decorators execute bottom-up.
- controller.ts + service.ts — Simple metadata writers. Trivial after route.ts.
- types/index.ts (243 lines) — All interfaces. VeloRequest, RouteMetadata, ControllerMetadata.
- orm/decorators → database → entity-accessor — How DB() creates databases, register() attaches accessors.
- core/frame.ts (215 lines) — compileFrame() walks template, detects sentinels, returns compiled functions.
- application.ts — NOW read this. In the chunks below.
application.ts (2924 lines)
1. Utility belt (L1-270)
- L38-54
INJECTABLE_MAP— maps param names to injection keys - L59
_NOT_PARSEDsentinel — lazy fields (S1) - L83-122
ARG_BUILDER_MAP— extract values from request - L124-137
parseHandlerParamNames(fn)— core of param-name injection
2. Class fields (L330-400)
routerTrieL338 +_staticRoutesL339pendingServices/pendingControllersL344-345_bunNativeModeL376,_sharedStateClassesL385
3. Registration (L408-938)
register() pushes to pending queues. initializeRegistrations() does topological sort + batch registration.
4. scan() (L480-570)
Phase 1: import .ts → inspect exports → push pending. Phase 2: resolve string scope refs.
await import(file) — executes top-level side effects.5. listen() boot sequence (L1103-1271)
- Init shared state L1107
- initializeRegistrations()
- Build trie + static cache
- Compile bun-native handlers L1128
- Bun.serve() or Node http.createServer()
- WebSocket wiring L1154-1246
- Scheduled tasks + @Go workers
- Inject shared rate-limit L1118
6. compileRouteHandler() (L2027-2383)
Runs ONCE per route. Builds layers:
- Parse param names → argBuilders
- Decide body parsing
- Compile validator
- S3 L2065: specialized call stub
- Timeout wrapping
- S4 L2152: Bun direct eligibility
- S6 L2269: pre-compile guard/mw/interceptor chains
- Assemble final handler closure
7-10. Pipeline, trie, clustering, createBunReqRes
- handleRequest() L1698 — full-path handler
- walkTrieScan() L2386 — S2 char scanning. findRoute() tries static cache first.
- Clustering L1425 — primary spawns workers, shared state BEFORE spawning
- createBunReqRes() L2833 — S1 stable hidden class
Non-Obvious Patterns
Pending Metadata Pattern
Decorators execute bottom-up. @Validate/@Guards write to pending_* maps. @Get drains all pending into RouteMetadata.
Param-Name Injection
parseHandlerParamNames calls fn.toString(). Mapped through INJECTABLE_MAP → ARG_BUILDER_MAP. Once at startup.
SharedHashMap Linear Probing
12-byte buckets. All ops atomic via C helper.
DB() Global Queue
DB() pushes to module-level _pendingDatabases. VeloApplication drains in initializeDatabases().
All Metadata Keys
Velogen: Regex-Only Parsing
Boot & Request Flow
Boot Sequence
Request Flow (Bun)
Things That Will Bite You
any.Implementation Notes
How to Add Things
New decorator
decorators/ + Symbol.for() key. If route-level: pending pattern + drain in route.ts. Read in compileRouteHandler(). Export. Update velogen.
New DB driver
Implement DatabaseDriver. registerDriver(). See connection.ts L52-137.
New shared data structure
Class in cluster/ with SharedMemorySegment + offset. Atomic ops only. Add to shared-state.ts.
New velogen command
scripts/velogen-X.js. Add to COMMANDS. Regex-only.
Bugs to Fix
- WHERE clause precedence bugsignificantWrap .where() in parens.
- Rate limiter memory leak bugsignificantAdd cap or periodic sweep.
- CORS missing origin header bugmediumArray origins + non-match = no header.
- Decorator stacking overwrites bugmediumSame-type pending should merge.
- Silent validator pass-through bugmediumUnknown schema = no-op. Throw.
- Column quoting inconsistency buglowStandardize across EntityAccessor.
- DI silent failure on primitives buglowError on String/Number params.
Performance
- Prepared statement cache perfsignificantLRU for SQLite/pg. ~10-20%.
- Cache static file realpath perfmediumrealpathSync per request.
- Trie rollback optimization perflowDelta encoding for ambiguous.
- Faster JSON for Node perfmedium5-15% for 10KB+ payloads.
Features
- @Cache + ETag featuresignificant20-50% for cacheable GETs.
- Pool timeouts featuremediumidle + connection timeout.
- WS message size limit featuremediumValidate before parse.
- Secret validation featurelowReject empty/short.
- Restart backoff featurelowExponential delay.
- Manifest hash featurelowVerify freshness.
- @Worker featuremediumPer-request pool.
- Param type coercion featurelowAuto :id → number.
- Plugin architecture featuresignificantvelo.use() + official plugins.
- @Prepare input transformer featuresignificantTransform body+session+query into typed object. Compile-time, zero hot-path cost. ~80 lines.
- Sanitize 5xx errors featuremediumGeneric to client.
- Shared velogen parser featuremediumExtract duplicated regex.
Ideas Board
My Ideas
Starter Ideas click for details & implementation hints
- @Pipe(fn, fn)Transform return values through composable pure functions
- velo.mount('/admin', app)Sub-apps with isolated DI containers
- @Stream()AsyncIterator → SSE / ndjson streaming
- Typed route params@Get<{id: number}> auto-coercion
- @RateLimit(max, window)Per-route limiting with auto shared memory
- @GraphQL('/graphql')Auto-schema from @Entity definitions
- @OnEvent('name')Decoupled cross-service EventBus
- Hot module replacementRe-import + diff routes live
- @Deprecate('/old')Auto-redirect with Sunset headers
- velo.health()Zero-config k8s / ALB health probe
- @Prepare(Class)Transform request inputs into typed object
- @Scope(RequestScope)Per-request service instances for multi-tenant
- velo.compose()Pre-flatten middleware chains into one call