Dependency injection that your IDE understands. Compile-time validation. Zero runtime magic. Just functions and types.
npm install @justscale/core @justscale/httpconst UserService = createService({
inject: { db: DatabaseService },
factory: ({ db }) => ({
findById: (id) => db.query('SELECT * FROM users WHERE id = ?', [id]),
}),
});
// TypeScript knows the full type of UserService
// Your IDE gives you autocomplete on db.query, findById, etc.Built for developers who want their IDE to do the heavy lifting
All dependencies validated by TypeScript. Missing a service? You'll know before you run.
No decorators, no reflect-metadata, no surprises. Just functions and types.
Same services work across HTTP, CLI, WebSocket. Write once, expose anywhere.
Features are composable units. Share them across projects, test them in isolation.
Watch how type-safe dependency injection works step by step
Create a service with typed dependencies
Controllers define routes. Bootstrap wires everything together.
TypeScript catches missing dependencies at compile time
No runtime surprises. Fix it before you ship.
Now add middleware to protect and enhance your routes ↓
Each middleware adds to the context. TypeScript tracks it all.
Watch context accumulate through the chain
import { Delete } from '@justscale/http';
import { parseAuth, loadProfile } from './middleware';
// Guard checks if user is admin
const isAdmin = (ctx: { user: User }) => ctx.user.role === 'admin';
const AdminController = createController('/admin', {
routes: () => ({
deleteUser: Delete('/users/:id') .use(parseAuth) // Adds: { user } .use(loadProfile) // Adds: { profile } .guard(isAdmin) // Checks: user.role .handle(({ user, profile, params, res }) => {
// TypeScript knows all context properties!
res.json({ deleted: params.id });
}), }),
});Bundle common middleware chains with .apply()
deleteUser: Delete('/users/:id')
.use(parseAuth)
.use(loadProfile)
.guard(isAdmin)
.handle(...),
updateUser: Put('/users/:id')
.use(parseAuth)
.use(loadProfile)
.guard(isAdmin)
.handle(...),
getStats: Get('/stats')
.use(parseAuth)
.use(loadProfile)
.guard(isAdmin)
.handle(...),// Bundle once
const adminOnly = bundle()
.use(parseAuth)
.use(loadProfile)
.guard(isAdmin);
deleteUser: Delete('/users/:id')
.apply(adminOnly).handle(...),
updateUser: Put('/users/:id')
.apply(adminOnly).handle(...),
getStats: Get('/stats')
.apply(adminOnly).handle(...),Bundles preserve types. Context from parseAuth and loadProfile flows through to your handler.
Get started in minutes. Your types will thank you.
npm install @justscale/core @justscale/http