map

File Map & Sizes

src/ core/ application.ts 2924 lines THE file. Server, router, pipeline, cluster, scan. container.ts 128 lines DI container. Tiny but central. metadata.ts 60 lines Reflect polyfill. Read first. frame.ts 215 lines ResponseFrame compiler. session.ts Encrypted sessions (AES-256-GCM). errors.ts HttpError class. decorators/ 721 lines All decorators. route.ts is the key file. orm/ 822 lines DB, EntityAccessor, QueryBuilder, drivers. cluster/ 661 lines SharedMemory, HashMap, Counter, BitSet, State. other/ channel/, workers/, middleware/, validation/, config/, logging/, testing/. scripts/ Velogen tools. Regex-only, no runtime reflection.
start here

Reading Order

Don't start with application.ts. Build up to it.

  1. metadata.ts (60 lines) — 3-level WeakMap replaces reflect-metadata. CLASS_KEY separates class-level from property-level.
  2. container.ts (128 lines) — resolve(): cache → cycle check → lookup → parent fallback → createInstance().
  3. decorators/route.ts (97 lines) — The "pending metadata" pattern. Decorators execute bottom-up.
  4. controller.ts + service.ts — Simple metadata writers. Trivial after route.ts.
  5. types/index.ts (243 lines) — All interfaces. VeloRequest, RouteMetadata, ControllerMetadata.
  6. orm/decorators → database → entity-accessor — How DB() creates databases, register() attaches accessors.
  7. core/frame.ts (215 lines) — compileFrame() walks template, detects sentinels, returns compiled functions.
  8. application.ts — NOW read this. In the chunks below.
deep dive

application.ts (2924 lines)

1. Utility belt (L1-270)

  • L38-54 INJECTABLE_MAP — maps param names to injection keys
  • L59 _NOT_PARSED sentinel — 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)

  • routerTrie L338 + _staticRoutes L339
  • pendingServices/pendingControllers L344-345
  • _bunNativeMode L376, _sharedStateClasses L385

3. Registration (L408-938)

register() pushes to pending queues. initializeRegistrations() does topological sort + batch registration.

GOTCHA: Route metadata deep-cloning registerController() ~L870 deep-clones per instance. Skip = cross-scope contamination.

4. scan() (L480-570)

Phase 1: import .ts → inspect exports → push pending. Phase 2: resolve string scope refs.

NOTE scan() uses await import(file) — executes top-level side effects.

5. listen() boot sequence (L1103-1271)

  1. Init shared state L1107
  2. initializeRegistrations()
  3. Build trie + static cache
  4. Compile bun-native handlers L1128
  5. Bun.serve() or Node http.createServer()
  6. WebSocket wiring L1154-1246
  7. Scheduled tasks + @Go workers
  8. Inject shared rate-limit L1118

6. compileRouteHandler() (L2027-2383)

Runs ONCE per route. Builds layers:

  1. Parse param names → argBuilders
  2. Decide body parsing
  3. Compile validator
  4. S3 L2065: specialized call stub
  5. Timeout wrapping
  6. S4 L2152: Bun direct eligibility
  7. S6 L2269: pre-compile guard/mw/interceptor chains
  8. Assemble final handler closure
Three handler types handler (full), bunDirect (S4), bunNative (S11). Compiled independently. Logic in compileRouteHandler() doesn't appear in native mode.
Two param parsers parseHandlerParamNames() handles destructured/rest/underscore. _compileOneNativeHandler() simpler regex. Update BOTH.

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
Stale shared state on crash Worker crash = shared memory persists. No reset on restart.
Trie rollback Ambiguous routes trigger array snapshots at L2401. Only remaining per-request allocation.
patterns

Non-Obvious Patterns

Pending Metadata Pattern

Decorators execute bottom-up. @Validate/@Guards write to pending_* maps. @Get drains all pending into RouteMetadata.

Same-type stacking broken @Middlewares(m1) @Middlewares(m2) — only m2 survives. Use variadic form.

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.

Known race on expiry Two workers detect expired entry → both reset → one increment lost.

DB() Global Queue

DB() pushes to module-level _pendingDatabases. VeloApplication drains in initializeDatabases().

DB leak in tests Multiple VeloApplication instances share the global queue.
reference

All Metadata Keys

Class-level Symbol.for('controller') Symbol.for('service') Symbol.for('websocket') Symbol.for('response_frame') Route collections Symbol.for('routes') ← @Get/@Post Symbol.for('velocity:fn') ← @Fn Symbol.for('velocity:go') ← @Go Symbol.for('velocity:schedule') ← @Every/@Cron Pending (drained by route decorator) pending_middlewares pending_interceptors pending_guards pending_upload pending_schema pending_status pending_timeout Other 'velocity:channel-params' 'ws_commands' 'ws_command_else' 'design:paramtypes' 'design:type' (TS emitted)
scripts

Velogen: Regex-Only Parsing

velogen-types.js
Entity → type interfaces. 3 fallback patterns.
velogen-openapi.js
Controllers → OpenAPI 3.1. ±5 line context window.
velogen-client.js
Controllers → typed fetch client + @Fn + @WebSocket.
velogen-api.js
Controllers → API tester. Parses Joi schemas. Handles aliases.
velogen-manifest.js
All classes → manifest.json. Backward search.
velogen-env.js
.env → envelocity.ts. __ nesting, ___ preserved.
Duplicated regex Each script has own patterns. Change syntax = update ALL.
architecture

Boot & Request Flow

Boot Sequence

import '@velocity/framework' → metadata.ts new VeloApplication(config) → Container, Logger, Config velo.scan('./src') → import → inspect → pending → scopes velo.listen() ↓ _initSharedState() ↓ initializeRegistrations() ↓ ↓ conflicts → services → controllers (topo) ↓ ↓ ↓ DI → clone → compileRouteHandler() ↓ buildTrie() → staticCache → CORS ↓ _compileBunNativeHandlers() if native ↓ Bun.serve() | http.createServer() ↓ scheduled, @Go, sharedRateLimit

Request Flow (Bun)

bunFetchHandler(request) Path 1: native → staticRoutes O(1) | trie → Response Path 2: direct → findRoute → bunDirect → Response Path 3: full → createBunReqRes → handleRequest ↓ reqID → hooks → path → CORS → static → @Fn ↓ findRoutecompiled: lazy → body → validate ↓ guards → mw → handler → intercept → send ↓ onResponse → getResponse() → Response
traps

Things That Will Bite You

emitDecoratorMetadata + interfaces Interfaces erased → Object or ref error. DI only works with concrete classes. Test params must use any.
Decorator order Method: bottom-to-top. Class: top-to-bottom. Pending relies on bottom-up.
SharedMemorySegment Bun-only bun:ffi + dlopen. Node throws. No fallback.
Deep-cloned routes Mutating after registration has no effect.
Three independent Bun paths bunNative compiled separately. compileRouteHandler changes don't propagate.
scan() side effects await import() on every file. Top-level code runs.
Validator pass-through Unknown schema = no-op. No error.
realpath blocks tryServeStatic uses realpathSync per request.
notes

Implementation Notes

ORM column quoting findOne() quotes; deleteWhere() doesn't. Standardize.
WHERE precedence Chained .where() + OR = wrong precedence. Wrap in parens.
Rate limiter leak In-memory store unbounded. Add cap or sweep.
DI primitives auto-creates String/Number. Should error.
CORS origin Array + non-match = no header. Browser blocks.
WS message size No limit before JSON.parse.
Secret validation No length check on secrets.
Prepared statements Rebuilt per query. LRU = 10-20% gain.
Pool timeouts No idle/connection timeout config.
Error exposure 5xx includes err.message. Sanitize.
Manifest integrity No hash check. Stale = mismatch.
extend

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.

roadmap

Bugs to Fix

  • WHERE clause precedence bugsignificant
    Wrap .where() in parens.
  • Rate limiter memory leak bugsignificant
    Add cap or periodic sweep.
  • CORS missing origin header bugmedium
    Array origins + non-match = no header.
  • Decorator stacking overwrites bugmedium
    Same-type pending should merge.
  • Silent validator pass-through bugmedium
    Unknown schema = no-op. Throw.
  • Column quoting inconsistency buglow
    Standardize across EntityAccessor.
  • DI silent failure on primitives buglow
    Error on String/Number params.
roadmap

Performance

  • Prepared statement cache perfsignificant
    LRU for SQLite/pg. ~10-20%.
  • Cache static file realpath perfmedium
    realpathSync per request.
  • Trie rollback optimization perflow
    Delta encoding for ambiguous.
  • Faster JSON for Node perfmedium
    5-15% for 10KB+ payloads.
roadmap

Features

  • @Cache + ETag featuresignificant
    20-50% for cacheable GETs.
  • Pool timeouts featuremedium
    idle + connection timeout.
  • WS message size limit featuremedium
    Validate before parse.
  • Secret validation featurelow
    Reject empty/short.
  • Restart backoff featurelow
    Exponential delay.
  • Manifest hash featurelow
    Verify freshness.
  • @Worker featuremedium
    Per-request pool.
  • Param type coercion featurelow
    Auto :id → number.
  • Plugin architecture featuresignificant
    velo.use() + official plugins.
  • @Prepare input transformer featuresignificant
    Transform body+session+query into typed object. Compile-time, zero hot-path cost. ~80 lines.
  • Sanitize 5xx errors featuremedium
    Generic to client.
  • Shared velogen parser featuremedium
    Extract duplicated regex.
ideas

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