@sentzunhat/zacatl
Version:
A modular, high-performance TypeScript microservice framework for Node.js, featuring layered architecture, dependency injection, and robust validation for building scalable APIs and distributed systems.
470 lines (367 loc) β’ 15.1 kB
Markdown
# Zacatl Framework
[](https://www.npmjs.com/package/@sentzunhat/zacatl)
[](https://www.npmjs.com/package/@sentzunhat/zacatl)
[](https://opensource.org/licenses/MIT)
[](https://www.typescriptlang.org/)
[](https://nodejs.org/)
[](https://github.com/sentzunhat/zacatl/actions/workflows/publish-dry.yml)
[](#tests)
[](https://img.shields.io/badge/Coverage-72.16%25-orange.svg)
**Universal TypeScript framework for building CLI tools, desktop apps, APIs, and distributed systems.**
Zacatl enforces clean, layered architecture with dependency injection, validation, and comprehensive error handlingβdesigned for both human developers and AI agents to collaborate effectively.
## β¨ Key Features
- **π― Multi-Context Architecture** - Single codebase for CLI, Desktop, and Server applications
- **ποΈ Layered/Hexagonal Architecture** - Clean separation with Application, Domain, Infrastructure, and Platform layers
- **π Dependency Injection** - Built-in DI container using `tsyringe`
- **β
Type-Safe Validation** - Full Zod schema support (with planned Yup and optional validation)
- **π‘οΈ Structured Error Handling** - 7 custom error types with correlation IDs
- **ποΈ Pluggable ORM Adapters** - Sequelize, Mongoose, built-in SQLite (Node 24+), or build your own
- **π Multi-Language Support** - Pluggable i18n with filesystem/memory adapters
- **π Adapter Pattern** - Easy integration with any database or service
- **π§ͺ Comprehensive Testing** - See the badges above for the current test count and coverage; Vitest
- **π Production Ready** - Structured logging, monitoring, and error tracking
## π― Multi-Context Support
Build **CLI tools**, **Desktop apps**, and **HTTP servers** with the same architecture:
> **Platform availability:** CLI and Desktop platform adapters are planned; the HTTP server platform is the primary supported runtime. See [Service Module](./docs/service/README.md) for platform status and availability.
```typescript
import { Service, ServiceType } from "@sentzunhat/zacatl";
// CLI Application
const cli = new Service({
type: ServiceType.CLI,
layers: {
application: { entryPoints: { cli: { commands: [...] } } },
domain: { services: [...] },
infrastructure: { repositories: [...] },
},
platforms: {
cli: { name: "my-tool", version: "1.0.0" },
},
});
// Desktop Application
const desktop = new Service({
type: ServiceType.DESKTOP,
layers: {
application: { entryPoints: { ipc: { handlers: [...] } } },
domain: { services: [...] },
infrastructure: { repositories: [...] },
},
platforms: {
desktop: { window: { title: "My App", width: 1024, height: 768 }, platform: "neutralino" },
},
});
// HTTP Server (default)
const server = new Service({
type: ServiceType.SERVER, // Optional: defaults to SERVER
layers: {
application: { entryPoints: { rest: { hooks: [...], routes: [...] } } },
domain: { services: [...] },
infrastructure: { repositories: [...] },
},
platforms: {
server: {
name: "my-service",
server: { type: ServerType.SERVER, vendor: ServerVendor.FASTIFY, instance: fastify }
},
},
});
```
## Platform Support Status
| Platform | Status |
| -------- | ------------------- |
| Server | Stable |
| CLI | Planned (stub only) |
| Desktop | Planned (stub only) |
## Service Configuration (notable options)
- `run.auto`: When `true`, the `Service` will attempt to start automatically when `start()` is invoked without additional manual orchestration. Defaults to `false` when omitted. This option is part of the `ConfigService` root config; see the `service` docs for full configuration examples.
## Public API Surface
The following modules are considered the stable, public surface of Zacatl:
- `configuration`
- `service`
- `dependency-injection`
- `error`
- `logs`
- `localization`
- `third-party/*`
## What Zacatl Does NOT Do
- Zacatl is not an end-user UI framework; Desktop and CLI adapters are planned and currently implemented as minimal stubs.
## Architectural Guarantees
- Layered / hexagonal architecture with strict inward dependency flow.
- Public API surface is stable; internal modules may change between minor versions.
## π Documentation
Full documentation lives in **[`docs/`](./docs/README.md)**.
- **[Architecture Overview](./docs/guidelines/framework-overview.md)** - System design and module map
- **[Release Notes](./docs/changelog.md)** - Version history and changes
- **[Service Module](./docs/service/README.md)** - Service configuration and platform APIs
- **[Dependency Injection](./docs/dependency-injection/README.md)** - DI patterns and container usage
- **[Configuration](./docs/configuration/README.md)** - Configuration loading
- **[Errors](./docs/error/README.md)** - Error types and usage
- **[Logs](./docs/logs/README.md)** - Logging adapters and patterns
- **[Localization](./docs/localization/README.md)** - i18n usage and adapters
- **[Third-Party + ORM](./docs/third-party/README.md)** - Re-exports and ORM guidance
- **[ESLint](./docs/eslint/README.md)** - Shared ESLint configuration
- **[Utils](./docs/utils/README.md)** - Utility helpers and path aliases
- **[Examples](./examples/)** - Production-ready example applications
## π± Ethical Use (Non-binding)
Zacatl is MIT-licensed (permissive). Please donβt use it to harm people.
## π Quick Start
### Install
```bash
npm install @sentzunhat/zacatl
```
> All supported ORMs and platforms (`mongoose`, `sequelize`, `express`, `fastify`, `better-sqlite3`) are bundled β a single install is enough. Only SQL dialect drivers need a separate install:
```bash
npm install pg pg-hstore # PostgreSQL
npm install mysql2 # MySQL
```
Validate your environment with:
```bash
npm run check:peers
```
### Hello World HTTP Service
```typescript
import Fastify from 'fastify';
import { Service } from '@sentzunhat/zacatl';
const fastify = Fastify();
const service = new Service({
type: ServiceType.SERVER,
layers: {
application: {
entryPoints: { rest: { hooks: [], routes: [] } },
},
domain: { services: [] },
infrastructure: { repositories: [] },
},
platforms: {
server: {
name: 'hello-service',
server: {
type: ServerType.SERVER,
vendor: ServerVendor.FASTIFY,
instance: fastify,
},
},
},
});
await service.start({ port: 3000 });
```
### CLI / Desktop Application
```typescript
import { Service, resolveDependency } from '@sentzunhat/zacatl';
class MyService {
doSomething = async () => console.log('Hello from CLI!');
}
const service = new Service({
type: ServiceType.CLI,
layers: {
domain: { services: [MyService] },
},
platforms: {
cli: { name: 'my-cli', version: '1.0.0' },
},
});
await service.start();
const myService = resolveDependency<MyService>('MyService');
await myService.doSomething();
```
## ποΈ Architecture Layers
Zacatl implements **layered (hexagonal) architecture**:
```
βββββββββββββββββββββββββββββββββββββββββββ
β Application Layer β HTTP handlers, validation, routes
βββββββββββββββββββββββββββββββββββββββββββ€
β Domain Layer β Business logic, services, models
βββββββββββββββββββββββββββββββββββββββββββ€
β Infrastructure Layer β Repositories, database adapters
βββββββββββββββββββββββββββββββββββββββββββ€
β Platform Layer β DI container, service startup
βββββββββββββββββββββββββββββββββββββββββββ
```
Each layer has a single responsibility, and dependencies flow strictly inward.
## πΎ Database Adapters
### Sequelize
```typescript
import { Sequelize } from 'sequelize';
import { Service } from '@sentzunhat/zacatl';
const sequelize = new Sequelize('postgresql://user:pass@localhost/db');
const service = new Service({
type: ServiceType.SERVER,
layers: {
application: { entryPoints: { rest: { hooks: [], routes: [] } } },
domain: { services: [] },
infrastructure: { repositories: [] },
},
platforms: {
server: {
name: 'my-service',
server: {
type: ServerType.SERVER,
vendor: ServerVendor.FASTIFY,
instance: fastify,
},
databases: [
{
vendor: DatabaseVendor.SEQUELIZE,
instance: sequelize,
},
],
},
},
});
```
### MongoDB (Mongoose)
```typescript
import mongoose from 'mongoose';
import { Service } from '@sentzunhat/zacatl';
const service = new Service({
type: ServiceType.SERVER,
layers: {
application: { entryPoints: { rest: { hooks: [], routes: [] } } },
domain: { services: [] },
infrastructure: { repositories: [] },
},
platforms: {
server: {
name: 'my-service',
server: {
type: ServerType.SERVER,
vendor: ServerVendor.FASTIFY,
instance: fastify,
},
databases: [
{
vendor: DatabaseVendor.MONGOOSE,
instance: mongoose,
connectionString: 'mongodb://localhost/mydb',
},
],
},
},
});
```
### Custom Repository Pattern
Implement `IRepository<T>` for any database:
```typescript
import { IRepository } from '@sentzunhat/zacatl';
class MyRepository<T> implements IRepository<T> {
findById = async (id: string): Promise<T | null> => {
/* ... */
};
findMany = async (filter: Record<string, unknown>): Promise<T[]> => {
/* ... */
};
create = async (data: T): Promise<T> => {
/* ... */
};
update = async (id: string, data: Partial<T>): Promise<void> => {
/* ... */
};
delete = async (id: string): Promise<void> => {
/* ... */
};
exists = async (id: string): Promise<boolean> => {
/* ... */
};
}
```
## π Internationalization
```typescript
import { createI18n, FilesystemAdapter } from '@sentzunhat/zacatl';
const i18n = createI18n();
const greeting = i18n.t('greeting'); // Loads from src/localization/locales/
await i18n.setLanguage('es');
const saludo = i18n.t('greeting'); // Translations loaded automatically
```
Place translation files in `src/localization/locales/`:
```json
// en.json
{ "greeting": "Hello {{name}}", "errors": { "notFound": "Not found" } }
```
```json
// es.json
{ "greeting": "Hola {{name}}", "errors": { "notFound": "No encontrado" } }
```
## β
Validation with Zod
```typescript
import { z } from 'zod';
import { loadConfig } from '@sentzunhat/zacatl';
const AppConfigSchema = z.object({
server: z.object({
port: z.number().min(1).max(65535),
host: z.string(),
}),
logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
});
const config = loadConfig('./config/app.yaml', 'yaml', AppConfigSchema);
```
> **Coming Soon**: Yup support and optional validation for maximum flexibility. See [Roadmap: Schema Validation Flexibility](docs/roadmap/index.md#schema-validation-flexibility-v0040--v010).
## π‘οΈ Error Handling
Zacatl includes 7 custom error types with built-in correlation IDs:
```typescript
import {
BadRequestError,
NotFoundError,
UnauthorizedError,
ForbiddenError,
ValidationError,
InternalServerError,
BadResourceError,
} from '@sentzunhat/zacatl';
throw new ValidationError({ message: 'Email is required' });
throw new NotFoundError({ message: 'User not found', metadata: { userId: 123 } });
```
## π§ͺ Testing
Zacatl's test count and coverage are shown in the badges at the top of this README. Run the commands below to run tests and generate coverage:
```bash
npm test # Run all tests
npm run test:coverage # Coverage report
```
## π¦ What's Included
```
src/
βββ configuration/ # Config loading & validation
βββ dependency-injection/ # DI container and helpers
βββ error/ # Error types
βββ eslint/ # Shared ESLint configs
βββ localization/ # i18n adapters and helpers
βββ logs/ # Logging adapters
βββ service/ # Service layers and platforms
βββ third-party/ # Re-exported dependencies
βββ utils/ # Utility helpers
```
## π οΈ Development
### Building
```bash
npm run build # Compile TypeScript to build-src-esm/ and build-src-cjs/
npm run build:watch # Watch mode
```
### Code Quality
```bash
npm run lint # Run ESLint
npm run type:check # TypeScript checking
```
## π Requirements
- **Node.js**: 24.14.0 or higher (LTS)
- **npm**: 11.0.0 or higher (bundled with Node 24)
- **TypeScript**: 5.9+ (we use 5.9.3)
## π License
[MIT License](./LICENSE) Β© 2025 Zacatl Contributors
## π€ Contributing
1. Open an issue describing the change.
2. Create a branch tied to it: `git checkout -b issue-<number>/type/description`
- Examples: `issue-42/feat/add-forbidden-error`, `issue-5/docs/update-readme`
3. Add tests for your changes.
4. Update documentation.
5. Commit with [Conventional Commits](https://www.conventionalcommits.org/): `git commit -m 'feat(error): add ForbiddenError'`
6. Push and open a PR referencing the issue.
See [CONTRIBUTING.md](./CONTRIBUTING.md) for the full guide.
> **Local install tip:** use `npm install --ignore-scripts` to skip lifecycle scripts when you only want to install deps.
## π Support
- π [Documentation](./docs/guidelines/framework-overview.md)
- π [Issue Tracker](https://github.com/sentzunhat/zacatl/issues)
- π¬ [Discussions](https://github.com/sentzunhat/zacatl/discussions)
## π About
Zacatl is built for developers who value clean architecture, type safety, and test-driven development. It's equally useful for humans and AI agents building production services.
**Repository**: https://github.com/sentzunhat/zacatl
**npm**: https://www.npmjs.com/package/@sentzunhat/zacatl
## π€ Acknowledgments
This framework was built with assistance from **GitHub Copilot** and friendly ML/LLM models, demonstrating effective human-AI collaboration in software development.