Rank
70
AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents
Traction
No public download signal
Freshness
Updated 2d ago
Xpersona Agent
Node.js & TypeScript Production Engineering Node.js & TypeScript Production Engineering Complete methodology for building production-grade Node.js backends with TypeScript. Covers architecture, frameworks, error handling, database patterns, security, testing, observability, and deployment. --- Quick Health Check (/16) Run through these 8 signals — score 0 (missing) or 2 (present): | # | Signal | Check | |---|--------|-------| | 1 | Strict TypeScript | "strict"
clawhub skill install skills:1kalin:afrexai-nodejs-productionOverall rank
#62
Adoption
No public adoption signal
Trust
Unknown
Freshness
Feb 25, 2026
Freshness
Last checked Feb 25, 2026
Best For
afrexai-nodejs-production is best for both workflows where OpenClaw compatibility matters.
Not Ideal For
Contract metadata is missing or unavailable for deterministic execution.
Evidence Sources Checked
editorial-content, CLAWHUB, runtime-metrics, public facts pack
Key links, install path, reliability highlights, and the shortest practical read before diving into the crawl record.
Overview
Node.js & TypeScript Production Engineering Node.js & TypeScript Production Engineering Complete methodology for building production-grade Node.js backends with TypeScript. Covers architecture, frameworks, error handling, database patterns, security, testing, observability, and deployment. --- Quick Health Check (/16) Run through these 8 signals — score 0 (missing) or 2 (present): | # | Signal | Check | |---|--------|-------| | 1 | Strict TypeScript | "strict" Capability contract not published. No trust telemetry is available yet. Last updated 4/15/2026.
Trust score
Unknown
Compatibility
OpenClaw
Freshness
Feb 25, 2026
Vendor
Openclaw
Artifacts
0
Benchmarks
0
Last release
Unpublished
Install & run
clawhub skill install skills:1kalin:afrexai-nodejs-productionSetup complexity is LOW. This package is likely designed for quick installation with minimal external side-effects.
Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data.
Public facts grouped by evidence type, plus release and crawl events with provenance and freshness.
Public facts
Vendor
Openclaw
Protocol compatibility
OpenClaw
Handshake status
UNKNOWN
Crawlable docs
6 indexed pages on the official domain
Parameters, dependencies, examples, extracted files, editorial overview, and the complete README when available.
Captured outputs
Extracted files
0
Examples
6
Snippets
0
Languages
typescript
Parameters
text
src/
├── index.ts # Entry point — bootstrap only
├── app.ts # App factory (createApp)
├── config/
│ ├── env.ts # Environment validation (Zod)
│ └── database.ts # DB connection config
├── routes/
│ ├── index.ts # Route registry
│ ├── users.ts # /users routes
│ └── orders.ts # /orders routes
├── services/
│ ├── user.service.ts # Business logic
│ └── order.service.ts
├── repositories/
│ ├── user.repo.ts # Data access (Drizzle/Prisma)
│ └── order.repo.ts
├── middleware/
│ ├── auth.ts # Authentication
│ ├── validate.ts # Request validation
│ ├── error-handler.ts # Global error handler
│ └── request-id.ts # Correlation ID
├── errors/
│ └── index.ts # Custom error classes
├── types/
│ └── index.ts # Shared types
├── utils/
│ └── index.ts # Pure utility functions
├── jobs/ # Background jobs/queues
│ └── email.job.ts
└── __tests__/ # Tests mirror src/ structure
├── services/
└── routes/
drizzle/ # Database migrations
├── 0001_create_users.sql
└── meta/
tsconfig.json
package.json
Dockerfile
docker-compose.yml
.env.examplejson
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": ["ES2022"],
"outDir": "dist",
"rootDir": "src",
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"exactOptionalPropertyTypes": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"skipLibCheck": true,
"esModuleInterop": true
},
"include": ["src"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}typescript
// types/branded.ts
declare const __brand: unique symbol;
type Brand<T, B extends string> = T & { [__brand]: B };
export type UserId = Brand<string, 'UserId'>;
export type OrderId = Brand<string, 'OrderId'>;
export type Email = Brand<string, 'Email'>;
export function UserId(id: string): UserId { return id as UserId; }
export function Email(email: string): Email {
if (!email.includes('@')) throw new ValidationError('Invalid email');
return email as Email;
}typescript
// config/env.ts
import { z } from 'zod';
const EnvSchema = z.object({
NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
PORT: z.coerce.number().int().min(1).max(65535).default(3000),
DATABASE_URL: z.string().url(),
REDIS_URL: z.string().url().optional(),
JWT_SECRET: z.string().min(32),
JWT_EXPIRES_IN: z.string().default('15m'),
LOG_LEVEL: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'),
CORS_ORIGINS: z.string().transform(s => s.split(',')).default('*'),
RATE_LIMIT_MAX: z.coerce.number().default(100),
RATE_LIMIT_WINDOW_MS: z.coerce.number().default(60_000),
});
export type Env = z.infer<typeof EnvSchema>;
// Validate at import time — fail fast
const parsed = EnvSchema.safeParse(process.env);
if (!parsed.success) {
console.error('❌ Invalid environment variables:', parsed.error.flatten().fieldErrors);
process.exit(1);
}
export const env = parsed.data;typescript
// errors/index.ts
export class AppError extends Error {
constructor(
message: string,
public readonly code: string,
public readonly statusCode: number,
public readonly details?: Record<string, unknown>,
) {
super(message);
this.name = this.constructor.name;
Error.captureStackTrace(this, this.constructor);
}
}
export class ValidationError extends AppError {
constructor(message: string, details?: Record<string, unknown>) {
super(message, 'VALIDATION_ERROR', 400, details);
}
}
export class NotFoundError extends AppError {
constructor(resource: string, id: string) {
super(`${resource} not found: ${id}`, 'NOT_FOUND', 404, { resource, id });
}
}
export class UnauthorizedError extends AppError {
constructor(message = 'Authentication required') {
super(message, 'UNAUTHORIZED', 401);
}
}
export class ForbiddenError extends AppError {
constructor(message = 'Insufficient permissions') {
super(message, 'FORBIDDEN', 403);
}
}
export class ConflictError extends AppError {
constructor(message: string, details?: Record<string, unknown>) {
super(message, 'CONFLICT', 409, details);
}
}
export class RateLimitError extends AppError {
constructor(retryAfterMs: number) {
super('Too many requests', 'RATE_LIMITED', 429, { retryAfterMs });
}
}typescript
// middleware/error-handler.ts
import type { ErrorHandler } from 'hono';
import { AppError } from '../errors/index.js';
import { logger } from '../utils/logger.js';
export const errorHandler: ErrorHandler = (err, c) => {
const requestId = c.get('requestId');
if (err instanceof AppError) {
if (err.statusCode >= 500) {
logger.error({ err, requestId }, 'Server error');
} else {
logger.warn({ err, requestId }, 'Client error');
}
return c.json({
error: { code: err.code, message: err.message, details: err.details },
}, err.statusCode as any);
}
// Unexpected errors — don't leak internals
logger.error({ err, requestId }, 'Unhandled error');
return c.json({
error: { code: 'INTERNAL_ERROR', message: 'An unexpected error occurred' },
}, 500);
};Editorial read
Docs source
CLAWHUB
Editorial quality
ready
Node.js & TypeScript Production Engineering Node.js & TypeScript Production Engineering Complete methodology for building production-grade Node.js backends with TypeScript. Covers architecture, frameworks, error handling, database patterns, security, testing, observability, and deployment. --- Quick Health Check (/16) Run through these 8 signals — score 0 (missing) or 2 (present): | # | Signal | Check | |---|--------|-------| | 1 | Strict TypeScript | "strict"
Complete methodology for building production-grade Node.js backends with TypeScript. Covers architecture, frameworks, error handling, database patterns, security, testing, observability, and deployment.
Run through these 8 signals — score 0 (missing) or 2 (present):
| # | Signal | Check |
|---|--------|-------|
| 1 | Strict TypeScript | "strict": true in tsconfig, no any escape hatches |
| 2 | Structured errors | Custom error classes with codes, not string throws |
| 3 | Input validation | Zod/Valibot on every external boundary |
| 4 | Database migrations | Version-controlled, reversible, CI-enforced |
| 5 | Health endpoints | /health (liveness) + /ready (readiness) with dependency checks |
| 6 | Structured logging | JSON logs with request IDs, no console.log in prod |
| 7 | Test coverage | >80% unit, integration tests for critical paths |
| 8 | Graceful shutdown | SIGTERM handler drains connections before exit |
Score interpretation: 0-6 = critical gaps, 8-10 = needs work, 12-14 = solid, 16 = production-grade.
| Framework | Best For | Throughput | Ecosystem | Learning Curve | TypeScript | |-----------|----------|-----------|-----------|----------------|------------| | Hono | Edge/serverless, lightweight APIs | ⭐⭐⭐⭐⭐ | Growing fast | Low | Native | | Fastify | High-perf monoliths, JSON APIs | ⭐⭐⭐⭐⭐ | Mature | Medium | Excellent | | Express | Legacy, max middleware ecosystem | ⭐⭐⭐ | Massive | Low | Via @types | | NestJS | Enterprise, large teams, DI-heavy | ⭐⭐⭐⭐ | Large | High | Native | | Elysia | Bun-first, type-safe APIs | ⭐⭐⭐⭐⭐ | Small | Low | Native | | tRPC | Full-stack TS, type-safe RPC | N/A (layer) | Growing | Medium | Native |
Decision rules:
src/
├── index.ts # Entry point — bootstrap only
├── app.ts # App factory (createApp)
├── config/
│ ├── env.ts # Environment validation (Zod)
│ └── database.ts # DB connection config
├── routes/
│ ├── index.ts # Route registry
│ ├── users.ts # /users routes
│ └── orders.ts # /orders routes
├── services/
│ ├── user.service.ts # Business logic
│ └── order.service.ts
├── repositories/
│ ├── user.repo.ts # Data access (Drizzle/Prisma)
│ └── order.repo.ts
├── middleware/
│ ├── auth.ts # Authentication
│ ├── validate.ts # Request validation
│ ├── error-handler.ts # Global error handler
│ └── request-id.ts # Correlation ID
├── errors/
│ └── index.ts # Custom error classes
├── types/
│ └── index.ts # Shared types
├── utils/
│ └── index.ts # Pure utility functions
├── jobs/ # Background jobs/queues
│ └── email.job.ts
└── __tests__/ # Tests mirror src/ structure
├── services/
└── routes/
drizzle/ # Database migrations
├── 0001_create_users.sql
└── meta/
tsconfig.json
package.json
Dockerfile
docker-compose.yml
.env.example
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": ["ES2022"],
"outDir": "dist",
"rootDir": "src",
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"exactOptionalPropertyTypes": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"skipLibCheck": true,
"esModuleInterop": true
},
"include": ["src"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}
any — use unknown and narrow, or define proper typesnoUncheckedIndexedAccess: true — forces null checks on array/object accesstype UserId = string & { __brand: 'UserId' }type User = z.infer<typeof UserSchema>{ status: 'active'; data: T } | { status: 'error'; error: E }satisfies over as — preserves narrowed types: config satisfies Configconst Status = { ACTIVE: 'active', INACTIVE: 'inactive' } as const// types/branded.ts
declare const __brand: unique symbol;
type Brand<T, B extends string> = T & { [__brand]: B };
export type UserId = Brand<string, 'UserId'>;
export type OrderId = Brand<string, 'OrderId'>;
export type Email = Brand<string, 'Email'>;
export function UserId(id: string): UserId { return id as UserId; }
export function Email(email: string): Email {
if (!email.includes('@')) throw new ValidationError('Invalid email');
return email as Email;
}
// config/env.ts
import { z } from 'zod';
const EnvSchema = z.object({
NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
PORT: z.coerce.number().int().min(1).max(65535).default(3000),
DATABASE_URL: z.string().url(),
REDIS_URL: z.string().url().optional(),
JWT_SECRET: z.string().min(32),
JWT_EXPIRES_IN: z.string().default('15m'),
LOG_LEVEL: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'),
CORS_ORIGINS: z.string().transform(s => s.split(',')).default('*'),
RATE_LIMIT_MAX: z.coerce.number().default(100),
RATE_LIMIT_WINDOW_MS: z.coerce.number().default(60_000),
});
export type Env = z.infer<typeof EnvSchema>;
// Validate at import time — fail fast
const parsed = EnvSchema.safeParse(process.env);
if (!parsed.success) {
console.error('❌ Invalid environment variables:', parsed.error.flatten().fieldErrors);
process.exit(1);
}
export const env = parsed.data;
process.env directly elsewhereenv object, not process.env.env.example always current — document every var with description + defaultNODE_ENV for branching, never feature flags in env// errors/index.ts
export class AppError extends Error {
constructor(
message: string,
public readonly code: string,
public readonly statusCode: number,
public readonly details?: Record<string, unknown>,
) {
super(message);
this.name = this.constructor.name;
Error.captureStackTrace(this, this.constructor);
}
}
export class ValidationError extends AppError {
constructor(message: string, details?: Record<string, unknown>) {
super(message, 'VALIDATION_ERROR', 400, details);
}
}
export class NotFoundError extends AppError {
constructor(resource: string, id: string) {
super(`${resource} not found: ${id}`, 'NOT_FOUND', 404, { resource, id });
}
}
export class UnauthorizedError extends AppError {
constructor(message = 'Authentication required') {
super(message, 'UNAUTHORIZED', 401);
}
}
export class ForbiddenError extends AppError {
constructor(message = 'Insufficient permissions') {
super(message, 'FORBIDDEN', 403);
}
}
export class ConflictError extends AppError {
constructor(message: string, details?: Record<string, unknown>) {
super(message, 'CONFLICT', 409, details);
}
}
export class RateLimitError extends AppError {
constructor(retryAfterMs: number) {
super('Too many requests', 'RATE_LIMITED', 429, { retryAfterMs });
}
}
// middleware/error-handler.ts
import type { ErrorHandler } from 'hono';
import { AppError } from '../errors/index.js';
import { logger } from '../utils/logger.js';
export const errorHandler: ErrorHandler = (err, c) => {
const requestId = c.get('requestId');
if (err instanceof AppError) {
if (err.statusCode >= 500) {
logger.error({ err, requestId }, 'Server error');
} else {
logger.warn({ err, requestId }, 'Client error');
}
return c.json({
error: { code: err.code, message: err.message, details: err.details },
}, err.statusCode as any);
}
// Unexpected errors — don't leak internals
logger.error({ err, requestId }, 'Unhandled error');
return c.json({
error: { code: 'INTERNAL_ERROR', message: 'An unexpected error occurred' },
}, 500);
};
throw new SomeError(message)// routes/users.ts
import { z } from 'zod';
import { zValidator } from '@hono/zod-validator';
const CreateUserSchema = z.object({
email: z.string().email().max(255).toLowerCase(),
name: z.string().min(1).max(100).trim(),
role: z.enum(['user', 'admin']).default('user'),
});
const PaginationSchema = z.object({
cursor: z.string().optional(),
limit: z.coerce.number().int().min(1).max(100).default(20),
});
const UserIdParamSchema = z.object({
id: z.string().uuid(),
});
// Usage with Hono
app.post('/users', zValidator('json', CreateUserSchema), async (c) => {
const body = c.req.valid('json'); // Fully typed!
const user = await userService.create(body);
return c.json({ data: user }, 201);
});
app.get('/users', zValidator('query', PaginationSchema), async (c) => {
const { cursor, limit } = c.req.valid('query');
const result = await userService.list({ cursor, limit });
return c.json({ data: result.items, nextCursor: result.nextCursor });
});
.trim(), .toLowerCase(), .default() in Zod, not in servicesPaginationSchema, DateRangeSchema, SortSchema| ORM | Best For | Type Safety | Migration | Query Builder | Learning Curve | |-----|----------|-------------|-----------|---------------|----------------| | Drizzle | SQL-first, edge, performance | ⭐⭐⭐⭐⭐ | Built-in | SQL-like | Low | | Prisma | Rapid dev, schema-first | ⭐⭐⭐⭐ | Built-in | Custom DSL | Low | | Kysely | SQL purists, complex queries | ⭐⭐⭐⭐⭐ | External | Type-safe SQL | Medium | | TypeORM | Legacy, decorator-style | ⭐⭐⭐ | Built-in | ORM-style | Medium |
Decision: Drizzle for new projects (matches SQL mental model, best TypeScript inference, edge-compatible).
// drizzle/schema.ts
import { pgTable, text, timestamp, uuid, varchar, boolean, index } from 'drizzle-orm/pg-core';
export const users = pgTable('users', {
id: uuid('id').primaryKey().defaultRandom(),
email: varchar('email', { length: 255 }).notNull().unique(),
name: varchar('name', { length: 100 }).notNull(),
role: text('role', { enum: ['user', 'admin'] }).notNull().default('user'),
isActive: boolean('is_active').notNull().default(true),
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
}, (table) => [
index('idx_users_email').on(table.email),
index('idx_users_created').on(table.createdAt),
]);
// repositories/user.repo.ts
import { eq, desc, gt } from 'drizzle-orm';
import { db } from '../config/database.js';
import { users } from '../../drizzle/schema.js';
import type { UserId } from '../types/branded.js';
import { NotFoundError } from '../errors/index.js';
export class UserRepository {
async findById(id: UserId) {
const [user] = await db.select().from(users).where(eq(users.id, id)).limit(1);
if (!user) throw new NotFoundError('User', id);
return user;
}
async list(opts: { cursor?: string; limit: number }) {
const query = db.select().from(users).orderBy(desc(users.createdAt)).limit(opts.limit + 1);
if (opts.cursor) query.where(gt(users.id, opts.cursor));
const rows = await query;
const hasMore = rows.length > opts.limit;
return { items: rows.slice(0, opts.limit), nextCursor: hasMore ? rows[opts.limit - 1].id : undefined };
}
async create(data: { email: string; name: string; role?: string }) {
const [user] = await db.insert(users).values(data).returning();
return user;
}
async update(id: UserId, data: Partial<{ name: string; role: string; isActive: boolean }>) {
const [user] = await db.update(users).set({ ...data, updatedAt: new Date() }).where(eq(users.id, id)).returning();
if (!user) throw new NotFoundError('User', id);
return user;
}
}
drizzle-kit generate → commit → drizzle-kit migrate in CIpg pool (min: 2, max: 10 per process) or serverless driver for edgedb.transaction(async (tx) => { ... })better-sqlite3 locally)// middleware/auth.ts
import { jwt } from 'hono/jwt';
import { env } from '../config/env.js';
import type { UserId } from '../types/branded.js';
type JwtPayload = { sub: UserId; role: 'user' | 'admin'; iat: number; exp: number };
export const authenticate = jwt({ secret: env.JWT_SECRET });
export const requireRole = (...roles: string[]) => {
return async (c: any, next: any) => {
const payload = c.get('jwtPayload') as JwtPayload;
if (!roles.includes(payload.role)) {
throw new ForbiddenError(`Required role: ${roles.join(' or ')}`);
}
await next();
};
};
| # | Item | Priority |
|---|------|----------|
| 1 | Helmet/security headers (CSP, HSTS, X-Frame) | P0 |
| 2 | Rate limiting per IP + per user | P0 |
| 3 | Input validation on every endpoint | P0 |
| 4 | CORS configured (not * in prod) | P0 |
| 5 | JWT short-lived (15m) + refresh token rotation | P0 |
| 6 | Password hashing (argon2id, cost ≥ 3) | P0 |
| 7 | SQL injection prevention (parameterized queries) | P0 |
| 8 | Request size limits (1MB default) | P1 |
| 9 | Dependency audit (npm audit, Snyk) | P1 |
| 10 | API key scoping (read-only, write, admin) | P1 |
// utils/logger.ts
import pino from 'pino';
import { env } from '../config/env.js';
export const logger = pino({
level: env.LOG_LEVEL,
...(env.NODE_ENV === 'development' && { transport: { target: 'pino-pretty' } }),
serializers: { err: pino.stdSerializers.err },
redact: ['req.headers.authorization', '*.password', '*.token', '*.secret'],
formatters: {
level: (label) => ({ level: label }),
},
});
// middleware/request-id.ts
import { randomUUID } from 'node:crypto';
export const requestId = () => {
return async (c: any, next: any) => {
const id = c.req.header('x-request-id') || randomUUID();
c.set('requestId', id);
c.header('x-request-id', id);
await next();
};
};
// middleware/request-logger.ts
import { logger } from '../utils/logger.js';
export const requestLogger = () => {
return async (c: any, next: any) => {
const start = performance.now();
const requestId = c.get('requestId');
await next();
const duration = Math.round(performance.now() - start);
const level = c.res.status >= 500 ? 'error' : c.res.status >= 400 ? 'warn' : 'info';
logger[level]({
requestId,
method: c.req.method,
path: c.req.path,
status: c.res.status,
durationMs: duration,
userAgent: c.req.header('user-agent'),
}, `${c.req.method} ${c.req.path} ${c.res.status} ${duration}ms`);
};
};
// routes/health.ts
app.get('/health', (c) => c.json({ status: 'ok', timestamp: new Date().toISOString() }));
app.get('/ready', async (c) => {
const checks = {
database: false,
redis: false,
};
try {
await db.execute(sql`SELECT 1`);
checks.database = true;
} catch {}
try {
await redis.ping();
checks.redis = true;
} catch {}
const ready = Object.values(checks).every(Boolean);
return c.json({ status: ready ? 'ready' : 'degraded', checks }, ready ? 200 : 503);
});
| Level | Coverage Target | Tools | What to Test | |-------|----------------|-------|-------------| | Unit | >80% | Vitest | Services, utils, pure logic | | Integration | Critical paths | Vitest + testcontainers | Routes → DB round-trip | | E2E | Happy paths | Vitest + supertest | Full HTTP request cycle | | Contract | API boundaries | Vitest | Request/response shapes |
// vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true,
environment: 'node',
include: ['src/**/*.test.ts'],
coverage: { provider: 'v8', reporter: ['text', 'lcov'], thresholds: { lines: 80, branches: 75 } },
setupFiles: ['./src/__tests__/setup.ts'],
pool: 'forks', // Isolation for DB tests
},
});
// __tests__/services/user.service.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { UserService } from '../../services/user.service.js';
import type { UserRepository } from '../../repositories/user.repo.js';
describe('UserService', () => {
let service: UserService;
let repo: jest.Mocked<UserRepository>;
beforeEach(() => {
repo = { findById: vi.fn(), create: vi.fn(), update: vi.fn(), list: vi.fn() } as any;
service = new UserService(repo);
});
it('creates user with normalized email', async () => {
repo.create.mockResolvedValue({ id: '1', email: 'test@example.com', name: 'Test' } as any);
const result = await service.create({ email: 'Test@Example.COM', name: 'Test' });
expect(repo.create).toHaveBeenCalledWith(expect.objectContaining({ email: 'test@example.com' }));
expect(result.email).toBe('test@example.com');
});
});
// __tests__/routes/users.test.ts
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { createApp } from '../../app.js';
import { testDb, migrate, cleanup } from '../helpers/db.js';
describe('POST /users', () => {
let app: any;
beforeAll(async () => {
await migrate(testDb);
app = createApp({ db: testDb });
});
afterAll(async () => { await cleanup(testDb); });
it('creates user and returns 201', async () => {
const res = await app.request('/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: 'new@example.com', name: 'New User' }),
});
expect(res.status).toBe(201);
const body = await res.json();
expect(body.data.email).toBe('new@example.com');
});
it('rejects invalid email with 400', async () => {
const res = await app.request('/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: 'not-an-email', name: 'Bad' }),
});
expect(res.status).toBe(400);
});
});
it('rejects expired JWT with 401')pool: 'forks' for DB tests// index.ts
import { serve } from '@hono/node-server';
import { createApp } from './app.js';
import { logger } from './utils/logger.js';
import { env } from './config/env.js';
import { db } from './config/database.js';
const app = createApp();
const server = serve({ fetch: app.fetch, port: env.PORT });
logger.info({ port: env.PORT }, 'Server started');
const shutdown = async (signal: string) => {
logger.info({ signal }, 'Shutdown signal received');
// Stop accepting new connections
server.close(() => { logger.info('HTTP server closed'); });
// Drain existing work (give 10s)
const timeout = setTimeout(() => {
logger.error('Forced shutdown after timeout');
process.exit(1);
}, 10_000);
try {
// Close DB pool, Redis, queues, etc.
await db.$client.end();
logger.info('Database pool closed');
clearTimeout(timeout);
process.exit(0);
} catch (err) {
logger.error({ err }, 'Error during shutdown');
process.exit(1);
}
};
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
// Catch unhandled errors
process.on('unhandledRejection', (err) => {
logger.fatal({ err }, 'Unhandled rejection');
process.exit(1);
});
# Build stage
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --ignore-scripts
COPY tsconfig.json ./
COPY src/ src/
COPY drizzle/ drizzle/
RUN npm run build
RUN npm ci --omit=dev --ignore-scripts
# Production stage
FROM node:22-alpine
RUN apk add --no-cache tini dumb-init
WORKDIR /app
COPY --from=builder /app/dist dist/
COPY --from=builder /app/drizzle drizzle/
COPY --from=builder /app/node_modules node_modules/
COPY --from=builder /app/package.json .
ENV NODE_ENV=production
USER node
EXPOSE 3000
ENTRYPOINT ["tini", "--"]
CMD ["node", "dist/index.js"]
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env: { POSTGRES_DB: test, POSTGRES_PASSWORD: test }
ports: ['5432:5432']
options: >-
--health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 22, cache: npm }
- run: npm ci
- run: npm run lint
- run: npm run typecheck
- run: npm test -- --coverage
env: { DATABASE_URL: 'postgresql://postgres:test@localhost:5432/test' }
- run: npm run build
P0 — Mandatory:
NODE_ENV=productiontsc --noEmit passes)P1 — Recommended:
npm audit)| # | Technique | Impact | Effort | |---|-----------|--------|--------| | 1 | Connection pooling (DB + Redis) | High | Low | | 2 | Response caching (Redis/in-memory) | High | Medium | | 3 | Query optimization (indexes, N+1) | High | Medium | | 4 | JSON serialization (fast-json-stringify) | Medium | Low | | 5 | Compression middleware | Medium | Low | | 6 | Streaming responses for large payloads | Medium | Medium | | 7 | Worker threads for CPU-bound work | High | High | | 8 | HTTP/2 + keep-alive | Low | Low |
// N+1 prevention — batch with dataloader or SQL JOIN
// ❌ Bad: for loop with individual queries
for (const order of orders) {
order.user = await db.query.users.findFirst({ where: eq(users.id, order.userId) });
}
// ✅ Good: single query with join
const ordersWithUsers = await db
.select()
.from(orders)
.leftJoin(users, eq(orders.userId, users.id))
.where(inArray(orders.id, orderIds));
// In-memory caching for hot data
import { LRUCache } from 'lru-cache';
const cache = new LRUCache<string, any>({ max: 1000, ttl: 60_000 });
async function getCachedUser(id: string) {
const cached = cache.get(id);
if (cached) return cached;
const user = await userRepo.findById(id);
cache.set(id, user);
return user;
}
// jobs/email.job.ts
import { Queue, Worker } from 'bullmq';
import { env } from '../config/env.js';
import { logger } from '../utils/logger.js';
const connection = { url: env.REDIS_URL };
export const emailQueue = new Queue('email', { connection });
export const emailWorker = new Worker('email', async (job) => {
const { to, subject, body } = job.data;
logger.info({ jobId: job.id, to }, 'Sending email');
// Send via provider
await sendEmail({ to, subject, body });
}, {
connection,
concurrency: 5,
limiter: { max: 10, duration: 1000 }, // 10 per second
});
emailWorker.on('failed', (job, err) => {
logger.error({ jobId: job?.id, err }, 'Email job failed');
});
removeOnComplete and removeOnFail TTLs// app.ts — compose dependencies explicitly
export function createApp(deps?: { db?: Database; redis?: Redis }) {
const database = deps?.db ?? defaultDb;
const app = new Hono();
// Compose service graph
const userRepo = new UserRepository(database);
const userService = new UserService(userRepo);
// Mount routes with injected services
app.route('/users', createUserRoutes(userService));
return app;
}
// middleware/rate-limit.ts (using hono-rate-limiter)
import { rateLimiter } from 'hono-rate-limiter';
export const apiRateLimit = rateLimiter({
windowMs: 60_000,
limit: 100,
keyGenerator: (c) => c.get('jwtPayload')?.sub || c.req.header('x-forwarded-for') || 'anonymous',
message: { error: { code: 'RATE_LIMITED', message: 'Too many requests' } },
});
import { createNodeWebSocket } from '@hono/node-ws';
const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app });
app.get('/ws', upgradeWebSocket((c) => ({
onOpen(evt, ws) { logger.info('WebSocket connected'); },
onMessage(evt, ws) {
const data = JSON.parse(evt.data.toString());
// Handle message
ws.send(JSON.stringify({ type: 'ack', id: data.id }));
},
onClose() { logger.info('WebSocket disconnected'); },
})));
| Layer | Recommended | Alternative | |-------|-------------|-------------| | Runtime | Node.js 22 LTS | Bun | | Framework | Hono | Fastify | | Language | TypeScript (strict) | — | | Validation | Zod | Valibot | | ORM | Drizzle | Prisma | | Database | PostgreSQL | SQLite (dev) | | Cache | Redis / Upstash | LRU in-memory | | Auth | JWT + refresh | Lucia, Better Auth | | Queue | BullMQ | pg-boss | | Testing | Vitest | — | | Logging | Pino | — | | Linting | Biome | ESLint + Prettier | | CI/CD | GitHub Actions | — | | Deploy | Docker + Railway/Fly | Vercel (serverless) |
any, branded IDs, Zod-derived types| # | Mistake | Fix |
|---|---------|-----|
| 1 | console.log in production | Use Pino with JSON output |
| 2 | any type everywhere | unknown + type narrowing |
| 3 | No input validation | Zod middleware on every route |
| 4 | OFFSET pagination | Cursor-based with keyset |
| 5 | No graceful shutdown | SIGTERM handler with drain timeout |
| 6 | Hardcoded config | Zod-validated env at startup |
| 7 | Fat controllers | Thin routes → services → repositories |
| 8 | No error hierarchy | Custom AppError with codes |
| 9 | Testing only happy paths | Test 400/401/404/409/500 explicitly |
| 10 | No request tracing | Request ID middleware + propagation |
| Dimension | Weight | What to Assess |
|-----------|--------|----------------|
| Type safety | 20% | Strict TS, no any, branded types |
| Error handling | 15% | Custom errors, global handler, no leaks |
| Testing | 15% | Coverage >80%, integration tests, error paths |
| Security | 15% | Auth, validation, rate limiting, headers |
| Observability | 10% | Structured logging, health checks, metrics |
| Performance | 10% | Connection pooling, caching, N+1 prevention |
| Code structure | 10% | Layer separation, file size limits, DI |
| Deployment | 5% | Docker, CI/CD, graceful shutdown |
@org/types, @org/db, @org/validation"@org/types": "workspace:*".ts files alongside .js)console.log with Pino one file at a time⚡ Built by AfrexAI — AI-powered business automation.
Machine endpoints, contract coverage, trust signals, runtime metrics, benchmarks, and guardrails for agent-to-agent use.
Machine interfaces
Contract coverage
Status
missing
Auth
None
Streaming
No
Data region
Unspecified
Protocol support
Requires: none
Forbidden: none
Guardrails
Operational confidence: low
curl -s "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nodejs-production/snapshot"
curl -s "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nodejs-production/contract"
curl -s "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nodejs-production/trust"
Operational fit
Trust signals
Handshake
UNKNOWN
Confidence
unknown
Attempts 30d
unknown
Fallback rate
unknown
Runtime metrics
Observed P50
unknown
Observed P95
unknown
Rate limit
unknown
Estimated cost
unknown
Do not use if
Raw contract, invocation, trust, capability, facts, and change-event payloads for machine-side inspection.
Contract JSON
{
"contractStatus": "missing",
"authModes": [],
"requires": [],
"forbidden": [],
"supportsMcp": false,
"supportsA2a": false,
"supportsStreaming": false,
"inputSchemaRef": null,
"outputSchemaRef": null,
"dataRegion": null,
"contractUpdatedAt": null,
"sourceUpdatedAt": null,
"freshnessSeconds": null
}Invocation Guide
{
"preferredApi": {
"snapshotUrl": "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nodejs-production/snapshot",
"contractUrl": "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nodejs-production/contract",
"trustUrl": "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nodejs-production/trust"
},
"curlExamples": [
"curl -s \"https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nodejs-production/snapshot\"",
"curl -s \"https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nodejs-production/contract\"",
"curl -s \"https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nodejs-production/trust\""
],
"jsonRequestTemplate": {
"query": "summarize this repo",
"constraints": {
"maxLatencyMs": 2000,
"protocolPreference": [
"OPENCLEW"
]
}
},
"jsonResponseTemplate": {
"ok": true,
"result": {
"summary": "...",
"confidence": 0.9
},
"meta": {
"source": "CLAWHUB",
"generatedAt": "2026-04-17T02:38:40.202Z"
}
},
"retryPolicy": {
"maxAttempts": 3,
"backoffMs": [
500,
1500,
3500
],
"retryableConditions": [
"HTTP_429",
"HTTP_503",
"NETWORK_TIMEOUT"
]
}
}Trust JSON
{
"status": "unavailable",
"handshakeStatus": "UNKNOWN",
"verificationFreshnessHours": null,
"reputationScore": null,
"p95LatencyMs": null,
"successRate30d": null,
"fallbackRate": null,
"attempts30d": null,
"trustUpdatedAt": null,
"trustConfidence": "unknown",
"sourceUpdatedAt": null,
"freshnessSeconds": null
}Capability Matrix
{
"rows": [
{
"key": "OPENCLEW",
"type": "protocol",
"support": "unknown",
"confidenceSource": "profile",
"notes": "Listed on profile"
},
{
"key": "both",
"type": "capability",
"support": "supported",
"confidenceSource": "profile",
"notes": "Declared in agent profile metadata"
}
],
"flattenedTokens": "protocol:OPENCLEW|unknown|profile capability:both|supported|profile"
}Facts JSON
[
{
"factKey": "docs_crawl",
"category": "integration",
"label": "Crawlable docs",
"value": "6 indexed pages on the official domain",
"href": "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fskills%2Ftree%2Fmain%2Fskills%2Fasleep123%2Fcaldav-calendar",
"sourceUrl": "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fskills%2Ftree%2Fmain%2Fskills%2Fasleep123%2Fcaldav-calendar",
"sourceType": "search_document",
"confidence": "medium",
"observedAt": "2026-04-15T05:03:46.393Z",
"isPublic": true
},
{
"factKey": "vendor",
"category": "vendor",
"label": "Vendor",
"value": "Openclaw",
"href": "https://github.com/openclaw/skills/tree/main/skills/1kalin/afrexai-nodejs-production",
"sourceUrl": "https://github.com/openclaw/skills/tree/main/skills/1kalin/afrexai-nodejs-production",
"sourceType": "profile",
"confidence": "medium",
"observedAt": "2026-04-15T00:45:39.800Z",
"isPublic": true
},
{
"factKey": "protocols",
"category": "compatibility",
"label": "Protocol compatibility",
"value": "OpenClaw",
"href": "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nodejs-production/contract",
"sourceUrl": "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nodejs-production/contract",
"sourceType": "contract",
"confidence": "medium",
"observedAt": "2026-04-15T00:45:39.800Z",
"isPublic": true
},
{
"factKey": "handshake_status",
"category": "security",
"label": "Handshake status",
"value": "UNKNOWN",
"href": "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nodejs-production/trust",
"sourceUrl": "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nodejs-production/trust",
"sourceType": "trust",
"confidence": "medium",
"observedAt": null,
"isPublic": true
}
]Change Events JSON
[
{
"eventType": "docs_update",
"title": "Docs refreshed: Sign in to GitHub · GitHub",
"description": "Fresh crawlable documentation was indexed for the official domain.",
"href": "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fskills%2Ftree%2Fmain%2Fskills%2Fasleep123%2Fcaldav-calendar",
"sourceUrl": "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fskills%2Ftree%2Fmain%2Fskills%2Fasleep123%2Fcaldav-calendar",
"sourceType": "search_document",
"confidence": "medium",
"observedAt": "2026-04-15T05:03:46.393Z",
"isPublic": true
}
]Sponsored
Ads related to afrexai-nodejs-production and adjacent AI workflows.