npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

arckode-framework

v1.1.2

Published

AI-first TypeScript/Bun framework. Modular, SOLID, zero magic. The AI reads the composition root and knows everything.

Readme

Arckode Framework

Framework TypeScript/Bun para construir APIs modulares. Diseñado desde el principio para trabajar con IA: arquitectura predecible, límites claros, cero magia.

arckode new mi-api
cd mi-api && bun install
arckode make:auth
arckode make:module Productos
bun run dev

Por qué Arckode

La mayoría de los frameworks están optimizados para que los humanos escriban código. Arckode está optimizado para que la IA genere código correcto sin supervisión constante.

La IA lee el composition-root.ts y sabe todo lo que necesita:

  • Qué módulos existen y qué hacen
  • Cómo se conectan entre sí
  • Qué datos maneja cada uno
  • Qué reglas tienen que cumplir

No hay decoradores, no hay magia de inyección, no hay convenciones implícitas. Todo está explícito en un solo lugar.


Instalación

Requisito: Bun >= 1.0

# 1. Instalar el CLI globalmente — una sola vez por máquina
bun install -g arckode-framework

# 2. Crear tu proyecto
arckode new mi-api

# 3. Entrar al proyecto e instalar dependencias
cd mi-api && bun install

# 4. Configurar entorno
echo 'JWT_SECRET=cambia-esto-en-produccion' > .env

# 5. Iniciar
bun run src/composition-root.ts

El CLI instala arckode-framework como dependencia de tu proyecto automáticamente. No necesitás referenciar rutas del framework — todo se importa como from 'arckode-framework'.


Inicio rápido

arckode new mi-api
cd mi-api && bun install
arckode make:auth           # módulo completo de auth con JWT
arckode make:module Clientes
arckode analyze             # 0 violaciones garantizado
bun run dev                 # hot reload

Conceptos core

Módulo

La unidad básica del sistema. Cada módulo es dueño de sus datos y su lógica. Nunca importa de otro módulo directamente.

modules/productos/
  index.ts          ← puerta pública (solo exports)
  types.ts          ← DTOs y ModelDefinition
  sockets.ts        ← hooks para conectores (opcional)
  actions/
    service.ts      ← lógica de negocio
    controller.ts   ← capa HTTP (sin lógica)
  validators/
    schema.ts       ← validación de entrada
  tests/
    service.test.ts
// modules/productos/index.ts
export function ProductosModule() {
  return createModule({
    name: 'productos',
    version: '1.0.0',
    description: 'Gestión del catálogo de productos',
    contract: {
      actions: ['listar', 'crear', 'actualizar', 'eliminar'],
      events: ['onProductoCreado'],
      tables: ['productos'],
    },
    create({ logger, orm, cache, router }) {
      const repo = new OrmRepository<ProductoDTO>(orm, 'Producto')
      const service = new ProductosService(repo, logger.child('productos'), cache)
      const controller = new ProductosController(service, logger.child('productos'))

      router.get('/productos', (req) => controller.index(req))
      router.post('/productos', (req) => controller.store(req))
      router.put('/productos/:id', (req) => controller.update(req))
      router.delete('/productos/:id', (req) => controller.destroy(req))

      return service  // resolveModule('productos') devuelve esto
    },
  })
}

RepositoryAdapter<T>

Los servicios nunca dependen del ORM directamente. Dependen de la interfaz genérica — el ORM concreto se elige en composition-root.ts.

// ❌ PROHIBIDO — acoplado al ORM, imposible cambiar a MongoDB/Prisma
class ProductosService {
  constructor(private orm: ORM) {}
  listar() { return this.orm.findMany('Producto') }
}

// ✅ CORRECTO — desacoplado, testeable, intercambiable
class ProductosService {
  constructor(private repo: RepositoryAdapter<ProductoDTO>) {}
  listar() { return this.repo.findMany() }
}
// composition-root.ts — se elige la implementación una sola vez
const repo = new OrmRepository<ProductoDTO>(orm, 'Producto')  // SQLite/Postgres
// O mañana:
const repo = new MongoProductoRepo(collection)                 // MongoDB
// El service nunca cambia.

Connector

El único puente entre módulos. Solo delegación — nunca lógica de negocio.

// connectors/pedido-stock.ts
export function conectarPedidoConStock(ctx: ConnectorContext): void {
  const productos = ctx.resolveModule<ProductosService>('productos')

  ctx.resolveModule('pedidos', {
    onPedidoCreado: async (pedido) => {
      await productos.descontarStock(pedido.productoId, pedido.cantidad)
    },
  })
}

Composition Root

El único archivo que conoce todo el sistema. La IA lo lee y entiende la arquitectura completa.

// src/composition-root.ts
import { ConfigStore, ORM, Router, NodeServer, MemoryCache, System, Auth, loadEnv } from 'arckode-framework'
import { SqliteAdapter } from 'arckode-framework/adapters/sqlite'
import { jwtTokenAdapter } from 'arckode-framework/adapters/jwt'
import { ProductoModel } from './modules/productos/types'
import { ProductosModule } from './modules/productos'
import { PedidosModule } from './modules/pedidos'
import { conectarPedidoConStock } from './connectors/pedido-stock'

const env = await loadEnv()  // carga .env + .env.{NODE_ENV}

const config = new ConfigStore()
config.define({
  PORT:       { type: 'number', default: 3000 },
  DB_PATH:    { type: 'string', default: './data/db.sqlite' },
  JWT_SECRET: { type: 'string', required: true },
}).load(env)

const db = new SqliteAdapter({ path: config.get('DB_PATH') })
await db.connect()
const orm = new ORM(db)

orm.define('Producto', ProductoModel)  // cada módulo es dueño de su ModelDefinition
await orm.migrate()

const system = new System({ config, orm, router, http, cache, auth, ... })
system.addModule(ProductosModule())
system.addModule(PedidosModule())
system.addConnector('pedido-stock', conectarPedidoConStock)
await system.start()

CLI — Referencia completa

Proyectos

| Comando | Descripción | |---|---| | arckode new <nombre> | Crear proyecto backend completo | | arckode new:frontend [nombre] | Crear frontend Vue 3 + Vite + TypeScript |

Generadores de backend

| Comando | Descripción | |---|---| | arckode make:auth | Módulo de autenticación completo (login, register, JWT, perfil) | | arckode make:module <Nombre> | Módulo con service, controller, types, validators, tests | | arckode make:connector <nombre> <mod1> <mod2> | Conector entre módulos | | arckode make:seed <Nombre> | Seed de datos | | arckode make:migration <nombre> | Migración SQL con up() y down() | | arckode make:helper <nombre> | Helper puro (sin efectos secundarios) | | arckode make:adapter <Adapter> <Interfaz> | Adapter de librería externa |

Generadores de frontend

| Comando | Descripción | |---|---| | arckode make:page <Nombre> | Módulo frontend (API client + composable + página + router) | | arckode generate:api [frontend-path] | Genera API clients desde módulos del backend |

Base de datos

| Comando | Descripción | |---|---| | arckode db:migrate | Ejecutar migraciones pendientes (src/migrations/) | | arckode db:migrate down | Revertir la última migración | | arckode db:seed | Listar seeds disponibles |

Análisis y diagnóstico

| Comando | Descripción | |---|---| | arckode analyze | Detecta 15+ tipos de violaciones de arquitectura | | arckode routes | Lista todas las rutas registradas (análisis estático) |


Adapters

Base de datos

// SQLite — desarrollo y apps de baja escala
import { SqliteAdapter } from 'arckode-framework/adapters/sqlite'
const db = new SqliteAdapter({ path: './data/app.sqlite' })

// PostgreSQL — producción
import { PostgresAdapter } from 'arckode-framework/adapters/postgres'
const db = new PostgresAdapter({ connectionString: process.env.DATABASE_URL, poolMax: 10 })

Cache

// En memoria — desarrollo (se pierde al reiniciar)
const cache = new MemoryCache()

// Redis — producción
import { RedisCacheAdapter } from 'arckode-framework/adapters/redis-cache'
const cache = new RedisCacheAdapter({ url: process.env.REDIS_URL })
await cache.connect()

Módulos opcionales

Queue

import { QueueService, MemoryQueueAdapter } from 'arckode-framework/queue'

const queue = new QueueService(new MemoryQueueAdapter())

queue.register('enviar-email', async (job) => {
  await mail.send(job.data as EmailData)
})

await queue.dispatch('enviar-email', { to: '[email protected]', subject: 'Bienvenido' })
await queue.dispatch('enviar-email', { ... }, { delay: 5000, maxAttempts: 3 })

Events (pub-sub)

import { EventBus } from 'arckode-framework/events'

const events = new EventBus()
events.on('pedido.creado', async (pedido) => { ... })
events.emit('pedido.creado', pedido)

WebSockets

import { WsServer } from 'arckode-framework/ws'

const ws = new WsServer()
ws.on('connection', (client) => { client.send({ type: 'welcome' }) })
ws.broadcast({ type: 'stock-bajo', productoId: id })

Mail

import { MailService } from 'arckode-framework/mail'
import { SmtpAdapter } from 'arckode-framework/mail/smtp'

const mail = new MailService(new SmtpAdapter({ host: 'smtp.gmail.com', port: 587, ... }))
await mail.send({ to: '[email protected]', subject: 'Bienvenido', html: '<p>Hola</p>' })

Storage

import { StorageService } from 'arckode-framework/storage'
import { LocalAdapter } from 'arckode-framework/storage/local'

const storage = new StorageService(new LocalAdapter({ path: './uploads' }))
const url = await storage.save('avatars/user.png', fileBuffer)

Middlewares

import { cors, rateLimit, requestLogger, timeout, compression, bodyLimit } from 'arckode-framework/middlewares'

// Globales
router.use(cors({ origins: ['https://miapp.com'] }))
router.use(rateLimit({ windowMs: 60_000, max: 100 }))
router.use(requestLogger(logger))
router.use(compression())

// Por ruta
router.get('/admin', handler, [auth.authenticate('admin'), timeout(3000)])
router.post('/upload', handler, [bodyLimit(10 * 1024 * 1024)])  // 10MB

Auth

const auth = new Auth(jwtTokenAdapter, process.env.JWT_SECRET, logger)

// Crear token
const token = await auth.createToken({ id: user.id, role: 'admin' })

// Hashear password (scrypt — sin dependencias externas)
const hash = await auth.hashPassword(password)
const ok   = await auth.comparePassword(password, hash)

// Proteger rutas
router.get('/perfil', handler, [auth.authenticate()])          // cualquier usuario autenticado
router.get('/admin',  handler, [auth.authenticate('admin')])   // solo admins
router.delete('/users/:id', handler, [auth.authenticate('admin', 'superadmin')])

Variables de entorno

loadEnv() carga .env base y .env.{NODE_ENV} con override por stage. process.env siempre tiene prioridad máxima.

# .env
PORT=3000
DB_PATH=./data/dev.sqlite
LOG_LEVEL=debug

# .env.production
DB_PATH=./data/prod.sqlite
LOG_LEVEL=warn
NODE_ENV=production bun run src/composition-root.ts
# Lee .env → sobrescribe con .env.production → process.env tiene prioridad

Testing

import { createTestClient, createRecordingOrm } from 'arckode-framework/testing'
import { OrmRepository } from 'arckode-framework'

// ORM que registra llamadas en memoria — sin base de datos real
const orm = createRecordingOrm()
const repo = new OrmRepository<ProductoDTO>(orm, 'Producto')
const service = new ProductosService(repo, logger, cache)

// Cliente HTTP que hace requests al Router sin levantar un server real
const client = createTestClient(router)

test('listar productos vacío', async () => {
  const res = await client.get('/productos')
  expect(res.status).toBe(200)
  expect(res.body).toEqual([])
})

test('crear producto', async () => {
  const res = await client.post('/productos', {
    body: { nombre: 'Laptop', precio: 1500, stock: 10 },
  })
  expect(res.status).toBe(201)
  expect(res.body.nombre).toBe('Laptop')
})

Análisis de arquitectura

arckode analyze
══════════════════════════════════════════════
  Arckode — Análisis de Arquitectura
══════════════════════════════════════════════

VIOLACIONES ENCONTRADAS: 2

[Acoplamiento]
  ❌ modules/pedidos/actions/service.ts:12
     Importa directamente de otro módulo (CLAUDE #1)
     → Usar un conector en /connectors/

[Portabilidad]
  ❌ modules/clientes/actions/service.ts:8
     El service inyecta ORM directamente (CLAUDE #18)
     → Usar RepositoryAdapter<ClienteDTO>

| Categoría | Violations detectadas | |---|---| | Estructura | MISSING_INDEX, MISSING_TYPES, MISSING_SERVICE, MISSING_CONTROLLER, MISSING_TESTS | | Acoplamiento | DIRECT_MODULE_IMPORT | | Diseño | BUSINESS_LOGIC_IN_CONTROLLER, CONTROLLER_MISSING_VALIDATION, EMPTY_MODULE_DESCRIPTION | | Calidad | TESTS_WITHOUT_CASES, GOD_SERVICE | | Seguridad | IDOR_RISK, HARDCODED_SECRET, INSECURE_PASSWORD | | Performance | N_PLUS_ONE_RISK | | Portabilidad | SERVICE_DEPENDS_ON_ORM |


Ejemplos incluidos

| Ejemplo | Descripción | |---|---| | examples/ecommerce/ | Productos, pedidos, conector de stock, auth | | examples/completo/ | Auth, productos, pedidos, mail, storage, queue, WebSockets |


Documentación adicional

| Archivo | Contenido | |---|---| | CLAUDE.md | 18 reglas inmutables — el contrato que la IA sigue | | kernel/framework.ts | Fuente completa del kernel (la IA lo lee entero) | | kernel/testing.ts | Utilidades de testing | | kernel/middlewares.ts | Middlewares disponibles |


Cómo funciona la distribución

Para usuarios del framework

# Instalar CLI una vez
bun install -g arckode-framework

# Crear proyecto — el CLI genera todo: composition-root.ts, CLAUDE.md, .env, package.json
arckode new mi-tienda --db=postgres

# CLAUDE.md se genera automáticamente en tu proyecto con las 18 reglas del framework.
# La IA lo lee primero antes de escribir cualquier línea de código.

# Actualizar el framework en tu proyecto
bun update arckode-framework

Para la IA (flujo de trabajo)

Cuando la IA trabaja en un proyecto con Arckode, hace esto en orden:

1. Lee CLAUDE.md         → entiende las 18 reglas que NO puede violar
2. Lee composition-root.ts → entiende todos los módulos, conectores y dependencias
3. Corre arckode analyze  → verifica que el estado actual tiene 0 violaciones
4. Genera código          → siguiendo la estructura exacta del framework
5. Corre arckode analyze  → verifica que sus cambios no introdujeron violaciones
6. Corre bun test         → verifica que nada se rompió

Para el autor del framework (actualizaciones)

# 1. Hacer los cambios
# 2. Correr tests y typecheck
bun test && bun run typecheck

# 3. Subir la versión en package.json (semver)
#    1.0.0 → 1.0.1  patch: bugfix
#    1.0.0 → 1.1.0  minor: feature nueva, retrocompatible
#    1.0.0 → 2.0.0  major: breaking change

# 4. Publicar
npm publish

# Los usuarios actualizan corriendo en su proyecto:
bun update arckode-framework

Adapters opcionales

Arckode solo instala lo que usás. Cada adapter tiene su dependencia peer:

| Adapter | Instalar | |---|---| | SQLite | bun add better-sqlite3 | | PostgreSQL | bun add pg | | MySQL | bun add mysql2 | | Redis (cache) | bun add redis | | Mail (SMTP) | bun add nodemailer |

El framework core (kernel/framework.ts) no depende de ninguna librería externa — solo de Node.js/Bun nativo.


Licencia

MIT