Install
$ agentstack add skill-j4flmao-agent-skills-oak ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Oak Backend
Purpose
Define Oak backend application architecture: Deno-native HTTP server, middleware composition, router pattern, and context management with typed state, composable middleware pipeline, and type-safe routing.
Agent Protocol
Trigger
User request includes: oak, oak backend, deno oak, oak middleware, oak router, deno http, oak context, oak typescript.
Input Context
- Deno version (1.40+)
- Oak version (13.x)
- Language (TypeScript)
- Database (Deno KV, MongoDB via denomongo, PostgreSQL via denopostgres)
- Templating (eta, deno mustache)
- Deployment (Deno Deploy, self-hosted)
Output Artifact
A markdown document containing:
- Project structure
- Router setup (Router class)
- Middleware composition (use, compose)
- Context (c.state, c.cookies, c.send)
- Error handling middleware
- State management (context state)
- Environment configuration (Deno.env)
- Testing (Deno.test, superdeno)
Response Format
Produce the artifact directly. No preamble, no postamble, no explanations. No filler, no hedging. Compress output.
Completion Criteria
- Router separates route definitions from app setup
- Middleware pipeline composed with app.use()
- Error middleware catches all exceptions
- State typed via OakMiddleware type parameter
- Tests use superdeno or fetch-based requests
- Lockfile generated and committed
Max Response Length
4096 tokens
Architecture Decision Trees
Oak vs Hono vs std/http
| Criterion | Oak | Hono | std/http | |-----------|-----|------|----------| | Middleware ecosystem | Rich (cors, auth, rate-limit, static) | Growing (cors, etag, jwt) | Manual | | TypeScript context typing | Generic State param | c.req.valid() | Manual | | Router pattern | Router({ prefix }) | Chained .get().post() | Switch/match | | File upload | ctx.request.body({ type: 'form-data' }) | c.req.parseBody() | Manual | | WebSocket | oak_websocket | Built-in hono/ws | Manual | | Community | Mature (12.x, stable) | Growing (4.x) | Std lib |
Decision: Complex middleware needs → Oak. TypeScript validation-first → Hono. Max throughput/minimal → std/http.
Route Organization Strategy
| Scale | Pattern | Structure | |-------|---------|-----------| | Small () { const orders = await orderService.findAll() ctx.response.body = orders }
async getById(ctx: RouterContext) { const id = ctx.params.id! const order = await orderService.findById(id) if (!order) { ctx.response.status = 404 ctx.response.body = { error: 'Order not found' } return } ctx.response.body = order }
async create(ctx: RouterContext) { const body = await ctx.request.body().value const order = await orderService.create(body) ctx.response.status = 201 ctx.response.body = order } }
### Step 5: Middleware Pipeline
```typescript
// src/middleware/error.ts
import type { Middleware } from 'oak'
export const errorMiddleware: Middleware = async (ctx, next) => {
try {
await next()
} catch (err) {
ctx.response.status = err.status ?? 500
ctx.response.body = {
success: false,
error: {
code: err.code ?? 'INTERNAL_ERROR',
message: err.message ?? 'Unexpected error',
},
}
ctx.response.type = 'json'
}
}
// src/middleware/logger.ts
import type { Middleware } from 'oak'
export const loggerMiddleware: Middleware = async (ctx, next) => {
const start = Date.now()
await next()
const ms = Date.now() - start
console.log(`${ctx.request.method} ${ctx.request.url.pathname} - ${ms}ms`)
}
Step 6: Typed State Management
// src/types/index.ts
export interface AppState {
userId: string
role: 'admin' | 'user'
requestId: string
}
// src/middleware/auth.ts
import type { Middleware } from 'oak'
import type { AppState } from '../types/index.ts'
export const authMiddleware: Middleware = async (ctx, next) => {
const token = ctx.request.headers.get('Authorization')?.slice(7)
if (!token) {
ctx.response.status = 401
ctx.response.body = { error: 'Unauthorized' }
return
}
const payload = await verifyJwt(token)
ctx.state.userId = payload.sub
ctx.state.role = payload.role
ctx.state.requestId = crypto.randomUUID()
await next()
}
Step 7: Validation with Zod
// src/middleware/validate.ts
import { z } from 'zod/mod.ts'
import type { Middleware } from 'oak'
export function validate(schema: z.ZodSchema): Middleware {
return async (ctx, next) => {
const body = ctx.request.body().value
const result = schema.safeParse(body)
if (!result.success) {
ctx.response.status = 400
ctx.response.body = {
success: false,
error: {
code: 'VALIDATION_ERROR',
details: result.error.issues,
},
}
return
}
ctx.state.validatedBody = result.data
await next()
}
}
Step 8: Testing
// tests/orders_test.ts
import { createApp } from '../src/app.ts'
import { assertEquals, assertExists } from 'std/testing/asserts.ts'
Deno.test('POST /api/orders creates order', async () => {
const app = createApp()
const listener = app.listen({ port: 0 })
const port = (await listener).port
const res = await fetch(`http://localhost:${port}/api/orders`, {
method: 'POST',
body: JSON.stringify(validPayload),
headers: { 'Content-Type': 'application/json' },
})
assertEquals(res.status, 201)
listener.close()
})
Deno.test('GET /api/orders/:id returns 404 for missing', async () => {
const app = createApp()
const listener = app.listen({ port: 0 })
const { port } = await listener
const res = await fetch(`http://localhost:${port}/api/orders/nonexistent`)
assertEquals(res.status, 404)
listener.close()
})
Implementation Patterns
Pattern: Composite Router (Versioned API)
// src/router/index.ts
import { Router } from 'oak'
import { orderRouter } from './orders.ts'
import { userRouter } from './users.ts'
import { healthRouter } from './health.ts'
const api = new Router({ prefix: '/api/v1' })
api.use('/orders', orderRouter.routes(), orderRouter.allowedMethods())
api.use('/users', userRouter.routes(), userRouter.allowedMethods())
const router = new Router()
router.use('/health', healthRouter.routes(), healthRouter.allowedMethods())
router.use('/api/v1', api.routes(), api.allowedMethods())
export { router }
Pattern: Static File Serving
import { send } from 'oak/send.ts'
// Serve static files
router.get('/static/:path+', async (ctx) => {
await send(ctx, ctx.params.path!, {
root: `${Deno.cwd()}/public`,
maxage: 86400,
})
})
Pattern: CORS with Dynamic Origins
const allowedOrigins = ['https://app.example.com', 'https://admin.example.com']
app.use(async (ctx, next) => {
const origin = ctx.request.headers.get('Origin')
if (origin && allowedOrigins.includes(origin)) {
ctx.response.headers.set('Access-Control-Allow-Origin', origin)
ctx.response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
ctx.response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization')
}
if (ctx.request.method === 'OPTIONS') {
ctx.response.status = 204
return
}
await next()
})
Production Considerations
Error Visibility
- Log all 5xx errors with full stack traces to stderr
- Use
ctx.response.type = 'json'before setting body to ensure content-type - Add
X-Request-Idheader to every response for tracing - Structure error responses consistently:
{ success: false, error: { code, message, details? } }
Performance Tuning
- Oak Router uses radix tree for path matching — keep prefix depth reasonable
- Avoid
JSON.parse/stringifyin hot middleware — Oak handles this internally - Use
ctx.send()for large file responses instead of reading into memory - Connection pooling for database — max 10-20 connections per Deno instance
- Compile with
deno compile --v8-flags=--max-old-space-size=512for production
Deployment
- Deno Deploy: entrypoint is
src/app.tsexportingapp.handlenotapp.listen - Docker: user
deno:alpineimage, run as non-root user - PM2 alternative: systemd service with
Restart=always
Anti-Patterns
| Anti-Pattern | Why | Fix | |-------------|-----|-----| | Inline routes in app.ts | Not testable, violates SRP | Separate router files | | Mixing state and middleware | State is per-request, not app-wide | Use app.state for startup info only | | ctx.request.body() multiple reads | Body stream is consumed once | Call once, store in context state | | Missing allowedMethods() | Returns 404 instead of 405 on wrong method | Always add router.allowedMethods() | | Hardcoded CORS origins | Security issue in production | Read from env var or config | | No type on Application | ctx.state is any | Always parameterize Application |
Security Considerations
- Always validate
Content-Typeheader — reject unexpected types - Set
Deno.permissionswith exact--allow-*flags per deployment - Use
secure: trueon cookies in production (HTTPS only) - Rate limit by IP or token — store counters in Deno KV
- Sanitize
ctx.params— Oak does not auto-escape/validate path params - CORS: never
*with credentials; use explicit origin list or regex matching
Testing Strategies
Unit Testing Services
Deno.test('calculateOrderTotal', () => {
const result = calculateTotal([{ price: 10, qty: 2 }, { price: 5, qty: 3 }])
assertEquals(result, 35)
})
Integration Testing with Database
Use in-memory KV for test isolation. Mock external HTTP calls via std/testing/mock.ts. Test error paths explicitly — validation errors, auth failures, 404s, 500s.
Rules
- TypeScript strict mode — all files .ts extension.
- Router instances separate from Application — never inline routes.
- Middleware pipeline: error → logger → auth → router.
- Context state for per-request data (user, requestId).
- Oak Router prefix for route grouping — never manual path concatenation.
- Deno.env for all configuration — never hardcoded values.
- deno.json for imports — import_map.json for legacy projects.
- Always add
router.allowedMethods()after each router. - Never read
ctx.request.bodymore than once per request.
References
- references/deno-runtime-guide.md — Deno Runtime Guide
- references/oak-middleware.md — Oak Middleware
- references/oak-performance.md — Oak Performance Optimization
- references/oak-routing-deployment.md — Oak Routing and Deployment
- references/oak-setup.md — Oak Setup Guide
- references/oak-testing.md — Oak Testing
Handoff
Hand off to backend/universal/api-response/SKILL.md for API response standards.
Implementation Patterns
Factory Pattern for Module Creation
function createModule(config: ModuleConfig): T { const dependencies = initializeDependencies(config); const module = new Module(dependencies); module.hooks.onInit(); return module as T; }
Builder Pattern for Complex Configuration
class ConfigBuilder { private config: AppConfig = new AppConfig(); withDatabase(url: string): ConfigBuilder { ... } withCache(ttl: number): ConfigBuilder { ... } withLogging(level: string): ConfigBuilder { ... } build(): AppConfig { return this.config; } }
Production Considerations
Deployment Checklist
- [ ] Production build with optimizations enabled
- [ ] Environment variables configured per environment
- [ ] Health check endpoint responds correctly
- [ ] Error tracking and monitoring integrated
- [ ] Logging level configured (not debug in production)
- [ ] Resource limits configured
- [ ] Database migrations applied
- [ ] Static assets built and served from CDN or cache
- [ ] Feature flags toggled appropriately
- [ ] Rollback plan documented and tested
Monitoring and Alerting
| Metric | Threshold | Severity | Action | |--------|-----------|----------|--------| | Error rate | > 1% | Critical | Rollback or fix | | p95 latency | > 500ms | Warning | Profile and optimize | | Uptime | 80% | Warning | Check for leaks | | CPU usage | > 80% | Warning | Scale up or optimize |
Rules
- Prefer composition over inheritance
- Favor immutable data structures
- Use dependency injection for testability
- Keep functions pure when possible — no side effects
- Fail fast with clear error messages
- Don't repeat yourself (DRY) — extract shared logic
- Keep it simple (KISS) — avoid unnecessary complexity
- You aren't gonna need it (YAGNI) — build what's required
- Separate concerns — single responsibility per module
- Code to interfaces, not implementations
- Write self-documenting code — clear names over comments
- Prefer standard library over third-party dependencies
- Handle errors explicitly — no silent failures
- Validate inputs at boundaries
- Log at appropriate levels (debug, info, warn, error)
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: j4flmao
- Source: j4flmao/agent-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.