A TypeScript framework for HTTP, WebSocket, CLI, and workflows.
NestJS-style structure. No modules. No ceremony.
A TypeScript framework for HTTP, WebSocket, CLI, and workflows.
NestJS-style structure. No modules. No ceremony.
Register controllers directly. No modules, no providers arrays, no import/export ceremonies. Keep the structure, drop the framework ritual.
Headers, cookies, params, and bodies are resolved only when your handler asks for them. Less hidden work, cleaner code, better hot paths.
HTTP, WebSocket, CLI, Workflows — the same controllers, DI, interceptors, and pipes work everywhere. Write an auth guard once, apply it anywhere.
@Controller()
export class HealthController {
@Get('health')
health() { return 'ok' }
}@Module({ controllers: [HealthController] })
export class HealthModule {}@Controller()
export class AppController {
@Get('hello/:name')
hello(@Param('name') name: string) {
return `Hello, ${name}!`
}
}@Module({
imports: [HealthModule],
controllers: [AppController],
})
export class AppModule {}const app = await NestFactory.create(AppModule)
await app.listen(3000)@Controller()
export class HealthController {
@Get('health')
health() { return 'ok' }
}@ImportController(HealthController)
class App extends Moost {
@Get('hello/:name')
hello(@Param('name') name: string) {
return `Hello, ${name}!`
}
}
const app = new App()
app.adapter(new MoostHttp()).listen(3000)
app.init()HTTP, WebSocket, CLI, Workflows — the same controllers, DI, and decorators everywhere.
@Controller('users')
export class UsersController {
@Get(':id')
find(@Param('id') id: string) {
return this.db.findUser(id)
}
@Post()
create(@Body() dto: CreateUserDto) {
return this.db.createUser(dto)
}
}Use Atscript for DTO validation without class-validator decorators or extra nested DTO classes.
export class CreateUserDto {
@ApiProperty({ description: 'Name', example: 'Alice', minLength: 2 })
@IsString()
@MinLength(2)
@MaxLength(100)
name: string
@ApiProperty({ description: 'Email', example: 'a@b.com' })
@IsEmail()
email: string
@ApiProperty({ description: 'Password', minLength: 8 })
@IsString()
@MinLength(8)
password: string
@ApiProperty({ description: 'Role', required: false, enum: UserRole })
@IsOptional()
@IsEnum(UserRole)
role?: UserRole
@ApiProperty({ description: 'Address', type: () => AddressDto })
@ValidateNested()
@Type(() => AddressDto)
address: AddressDto
}export class AddressDto {
@ApiProperty({ example: '123 Main St' })
@IsString()
street: string
@ApiProperty({ example: 'Springfield' })
@IsString()
city: string
@ApiProperty({ example: '62704' })
@IsString()
@Matches(/^\d{5}$/)
zip: string
}export interface CreateUserDto {
@meta.example "Alice"
@expect.minLength 2
@expect.maxLength 100
name: string
@meta.example "a@b.com"
email: string.email
@meta.sensitive
@expect.minLength 8
password: string
role?: UserRole
address: {
@meta.example "123 Main St"
street: string
@meta.example "Springfield"
city: string
@meta.example "62704"
@expect.pattern /^\d{5}$/
zip: string
}
}