About moostjs
Moost is a metadata-driven TypeScript event-processing framework for developers building HTTP, CLI, WebSocket, or workflow applications. Its adapter model lets controllers handle multiple event types while sharing dependency injection, interceptors, and pipes.
Key features
- 01Decorator-based event handlers
- 02HTTP, CLI, WebSocket, and workflow adapters
- 03Shared dependency injection
- 04Shared interceptors and pipes
Use cases
- 01Building HTTP and CLI applications
- 02Serving WebSocket messages alongside HTTP
- 03Defining multi-step workflows
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ moostjs/ moostjs --skill moostjsAfter installing, type/moostjsin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
references/core.mdcustom-adapters.mddecorators.mddi.mdevent-cli.mdevent-http.mdevent-wf.mdevent-ws.mdhttp-auth.mdhttp-request.mdhttp-response.mdinterceptors.mdotel.mdpipes.mdswagger.mdvite.mdws-rooms.mdws-testing.mdDetails
From the project READMEMoost
Metadata-driven event processing framework for TypeScript. Decorators + composables (via Wooks) handle HTTP, CLI, WebSocket, Workflow events. Each event type = one adapter. No module abstraction — controllers register directly on Moost. DI, interceptors, pipes are shared across all adapters. A single controller can expose @Get, @Cli, @Message methods simultaneously; each adapter binds only its own handler type.
Powered by: @prostojs/mate (metadata), @prostojs/infact (DI), @wooksjs/event-core (async event context), @prostojs/dye (compile-time terminal colors).
Domain map — load only what you need
| Domain | File | Load when |
|---|---|---|
| Core concepts, Moost class, lifecycle, registration, app init/dispose | core.md | New project, multi-adapter setup, app.init(), @MoostInit/@InjectMoost/app.addInitHook(), boot-time setup, Moost subclass, app.dispose()/@MoostDispose, graceful shutdown, disposeOnSignals() (SIGTERM/SIGINT handler, MaxListenersExceededWarning on dev reload, Ctrl-C disposes the wrong app), resources leaking across hot reloads, duplicate timers/jobs after reload |
| Decorators, metadata, custom decorators, Mate | decorators.md | Creating/using decorators, reading metadata, subclassing controllers / @Inherit / parent routes 404 / diagnostics.inheritance |
| DI scopes, @Injectable, @Inject, @Provide, @Circular | di.md | Services, scoping, providers, replacements; running code as another controller (withControllerContext, forkEventContext) |
| Interceptors: priority, @Intercept, guards, class-based | interceptors.md | Auth/logging/error cross-cutting |
| Pipes: @Pipe, @Resolve, TRANSFORM/VALIDATE | pipes.md | Validation, transformation, custom param decorators |
| Custom adapter: TMoostAdapter, defineMoostEventHandler | custom-adapters.md | Build an adapter for a new event source |
| HTTP setup/routing | event-http.md | MoostHttp, route decorators, handler returns, fetch/SSR, invoke (route inside the current request), withHttpContext, forwardHeaders/DEFAULT_FORWARD_HEADERS, anonymous 127.0.0.1 self-calls |
| HTTP request data | http-request.md | @Query/@Header/@Cookie/@Body/@Req/@Res/@Ip |
| HTTP response control | http-response.md | @SetStatus/@SetHeader/@SetCookie, refs, body limits, HttpError |
| HTTP auth guards | http-auth.md | defineAuthGuard, AuthGuard, @Authenticate |
| CLI | event-cli.md | CliApp, @Cli/@CliOption, help, CLI interceptors |
| Workflow | event-wf.md | @Step/@Workflow/@WorkflowSchema, pause/resume, outlets, state strategies |
| WebSocket core | event-ws.md | MoostWs/WsApp, @Message/@Connect/@Disconnect, wire protocol |
| WebSocket rooms | ws-rooms.md | useWsRooms, broadcasting, WsBroadcastTransport |
| WebSocket testing | ws-testing.md | prepareTestWsMessageContext / prepareTestWsConnectionContext |
| Vite plugin: dev/build, middleware, SSR/SPA, deploy | vite.md | moostVite, vite.config.ts, createSSRServer, ssrEntry/serverEntry, ssr.noExternal/ssr.external, ssrExternalCheck, dev-server split warning / "loaded natively by Node in dev" / instantiate(MoostHttp) fails only under vite serve, dist/server, HMR, "undefined useRequest() in prod", "Cannot read properties of undefined (reading 'headers')", externalized dep calling wooks composables, dev server serves a half-booted app / some API routes return index.html after an edit / app.init() error not showing in dev / "502 Moost app failed to load" / does the plugin wait for init(), SSR render contract / per-page head-SEO / status / ssrHead / TSSRRenderResult / TSSRRenderContext / ssrFetchForwarding (SSR viewer identity) |
| Swagger/OpenAPI | swagger.md | SwaggerController, Swagger* decorators, OpenAPI spec generation, spec.json/UI serving, securitySchemes |
| OpenTelemetry | otel.md | enableOtelForMoost, spans/tracing, @OtelIgnoreSpan/@OtelIgnoreMeter, span processors, useOtelContext/useSpan/withSpan, moost.event.duration metrics |
| RBAC/ABAC access control | @aooth/arbac-moost (aooth docs) | auth, roles/scopes, authorize guards — NOT part of this repo; @moostjs/arbac is deprecated, superseded by aooth |
Scaffold
npm create moost@latest [name] -- [--http|--cli|--ws|--ssr] [--wf] [--oxc] [--force]
Pass at most ONE project-type flag (--http --ws is the exception: HTTP app + WebSocket add-on). Flags pre-select add-ons and skip the corresponding interactive toggles. Details: core.md.
Quick start
import { Moost } from 'moost'
import { MoostHttp } from '@moostjs/event-http'
const app = new Moost()
app.adapter(new MoostHttp()).listen(3000)
app.registerControllers(AppController)
await app.init()
Other entry points:
- CLI:
new CliApp().controllers(AppController).useHelp({ name: 'my-cli' }).start()— sugar over Moost + MoostCli (event-cli.md) - Standalone WS:
await new WsApp().controllers(ChatController).start(3000)(event-ws.md) - Multi-adapter sharing one HTTP server: capture the adapter first —
const http = app.adapter(new MoostHttp()), thenhttp.listen(3000)andapp.adapter(new MoostWs({ httpApp: http.getHttpApp() }))(event-ws.md) - A
Moostsubclass is itself a controller — decorate its methods directly (core.md)
Cross-cutting facts
DI scopes — @Injectable() / @Injectable(true) / @Injectable('SINGLETON') = one instance for app lifetime. @Injectable('FOR_EVENT') = fresh instance per event. @Controller() implicitly sets @Injectable(true) (SINGLETON). Use 'FOR_EVENT' when class properties hold per-request state or when using property-level ref/resolver decorators. FOR_EVENT requires an active event context (composables don't work in SINGLETON constructors). Scope lifetime (HTTP response + handler, per-event ownership for workflow runs and WS messages, pre-0.6.42 scope isn't registered bugs): di.md#scopes.
Wooks composables work inside handlers — All @wooksjs/* composables (e.g., useRequest, useResponse, useHeaders) work directly in Moost handlers; they run in the same event context.
Logging — composable: useLogger('topic') (from moost, re-exported from @wooksjs/event-core). Property: @InjectEventLogger() (per-event) / @InjectMoostLogger('topic') (app-level, falls back to @LoggerTopic, then class @Id). Standalone: createLogger({ transports: [loggerConsoleTransport] }) — loggerConsoleTransport is an already-constructed transport constant; pass it, don't call it.
Re-exports — moost re-exports current, useLogger, key, cached, eventTypeKey, createEventContext, run from @wooksjs/event-core, plus createProvideRegistry/createReplaceRegistry from @prostojs/infact. moost also exports its own globalKey(name) — a duplication-safe context-key factory (interns the slot by name via globalThis); use it instead of key for any moost-owned context key so set/get can't desync when moost is loaded more than once (dual ESM/CJS, or a duplicated install). @moostjs/event-http re-exports httpKind, HttpError, useHttpContext, prerenderJson (+ type TPrerenderJsonOptions). @moostjs/event-cli re-exports cliKind, and Param/Controller/Intercept/Description/Optional/defineBeforeInterceptor/defineAfterInterceptor/defineInterceptor from moost (note: defineErrorInterceptor is NOT re-exported — import from moost). @moostjs/event-wf re-exports wfKind, useWfState, StepRetriableError, outlet primitives. @moostjs/event-ws re-exports wsConnectionKind/wsMessageKind, WsError, all useWs* composables, currentConnection, prepareTestWs*.
Architecture pointers
- Decorator system — all decorators go through
getMoostMate()(singletonMate,'moost'workspace); metadata read at bind time: decorators.md - Interceptor priorities & phases — interceptors.md
- Pipe priority order & scope levels — pipes.md
- Event handler lifecycle (
defineMoostEventHandler) — custom-adapters.md - Adapter pattern — each adapter implements
TMoostAdapter<H>, attached viaapp.adapter(a), filtersopts.handlersby its ownhandler.type: custom-adapters.md