Launching today
ZinTrust
TypeScript MVC framework for high-performance APIs for edge
8 followers
TypeScript MVC framework for high-performance APIs for edge
8 followers
The zero-dependency TypeScript MVC framework for high-performance APIs, clean architecture, and microservices. Node.js & Cloudflare Workers compatible.






How does ZinTrust handle middleware composition across multiple Workers, especially when some run on the edge and others on Node? Curious if there's a shared pattern or if you end up writing it twice.
@zmragetrktzpl
Yes — the same middleware source code runs unchanged on edge (Cloudflare Workers/serverless) and Node. There is one shared, runtime-agnostic middleware interface and composition model. The runtime differences are handled under the hood by adapters. You do not write two versions.
The middleware code and composition are fully portable. However, some middlewares need to persist state across requests. On Node, you can sometimes use in-memory storage. On edge runtimes (stateless Workers), every request may land on a different isolate, so you must configure a shared backend.
ZinTrust provides driver options so you can keep the same middleware registration while swapping the storage:
Rate Limiting (rateLimit, authRateLimit, etc.):
Supports memory | redis | kv | db
Set RATE_LIMIT_STORE=kv (or redis via the proxy) for edge.
Configured globally in config/middleware.ts or per middleware instance.
JWT Auth + Sessions/Revocation:
JwtAuthMiddleware can validate against JwtSessions.isActive().
Drivers: database | redis | kv | kv-remote | memory
Configure with JWT_SESSION_DRIVER=kv or JWT_REVOCATION_DRIVER=redis.
Use this when you need to revoke a token or "logout all devices". Pure stateless JWT (no driver) works without any shared store.
Traditional Sessions (SessionMiddleware):
Currently uses an in-memory Map by default.
For durable sessions across edge Workers, most teams switch to stateless JWT (no server-side session storage needed) or implement a Cache-backed custom store.
CSRF protection often rides on top of sessions, so the same guidance applies.
Other stateful middleware (custom auth caches, feature flags tied to user, etc.):
Use Cache.store('redis'), Cache.store('kv'), or direct DB/KV access inside your middleware.
Example configuration for edge:
The middleware functions themselves stay the same. Only the driver (chosen via env or options) changes depending on whether you are on Node or edge.
how does it handle database integrations out of the box, or do i need to bring my own client setup?
@nimeta4h7
ZinTrust gives you multiple supported options you can pick. It is not locked in. You configure the driver via DB_CONNECTION + config/database.ts. Install only the adapter package for the DB you choose (via zin add or npm i).
Supported drivers (pick any)
Driver
Adapter package (if needed)
Client used
Notes / When to use
mysql
@zintrust/db-mysql
mysql2
Default in examples. Full featured.
postgresql
@zintrust/db-postgres
pg
Full featured.
sqlite
@zintrust/db-sqlite (optional)
better-sqlite3
Built-in adapter; good for local/dev.
sqlserver
@zintrust/db-sqlserver
(mssql via setup)
Supported via plugin/adapter.
d1 / d1-remote
@zintrust/db-d1
Cloudflare D1 binding
Native CF, no TCP.
aurora-data-api
@zintrust/client-rds-data
AWS RDS Data API
For Aurora Serverless (set DB_CONNECTION=aurora-data-api).
Run zin add db:mysql (or db:postgres, a:mysql, etc.) — this installs the adapter and registers the driver automatically.
The adapter packages are separate, so you only pull mysql2 or pg for the DB you actually use.
Core already includes mysql2 + pg at the framework level for proxy runtimes and convenience.
Configuration (multi-DB supported, not locked)
Use Model.db('postgresql') or useDatabase(..., 'name') to target a specific connection. All standard methods (query builder, transactions, migrations, seeding, relations) work against any registered connection.
Serverless + TCP databases (mysql/postgres/sqlserver)
Serverless runtimes cannot open raw TCP sockets by default.
Options (both supported out of the box):
Cloudflare sockets (direct, experimental): ENABLE_CLOUDFLARE_SOCKETS=true + the db adapter package. The adapter packages detect Workers runtime and use cloudflare:sockets.
Included HTTP proxy (recommended, stable):
USE_MYSQL_PROXY=true
MYSQL_PROXY_URL=http://... (same pattern for POSTGRES_PROXY_URL, SQLSERVER_PROXY_URL)
You can run the proxy (ships with the CLI and runtime) using any of these methods:
zin proxy:mysql (or --watch)
docker compose -f docker-compose.proxy.yml up (includes mysql, postgres, sqlserver proxies + gateway)
Cloudflare Containers proxy gateway (zin init:containers-proxy)
Proxy runs in normal Node (has full TCP + real mysql2/pg), Worker talks HTTP to it.
Optional: request signing (MYSQL_PROXY_REQUIRE_SIGNING), custom headers, statement registry mode.
D1 does not need a proxy.
Bring your own client/custom setup
Yes, fully supported — you are not locked to the provided adapters.
Inject your own mysql2: before boot, set globalThis.__zintrustMysqlModule = yourModule (the adapter checks for it).
Custom driver/adapter: implement IDatabaseAdapter (methods: connect, disconnect, query, queryOne, ping, transaction, rawQuery, ensureMigrationsTable, getType, isConnected, getPlaceholder) then:
Use any connection name + your driver in config.
You can still use Models, QueryBuilder, migrations, etc. against it.
Or bypass entirely and talk to your DB client directly for special cases.
What the ORM / framework uses
All paths go through the registered adapter for the connection:
Models (User.create, User.where().get())
QueryBuilder
Database.transaction(...)
Raw queries (when USE_RAW_QRY=true)
Migrations + seeders
Read replicas (readHosts), pooling config, SSL, etc.
Same application code works on Node, Cloudflare Worker, Docker, AWS Lambda, or serverless — only the driver + env + (for edge) proxy changes.
Summary of choices (you pick)
Direct client on Node/Docker/VPS: just pick driver + install adapter package.
Edge (Workers): D1 (zero proxy) or sockets or the built-in proxy (it provides the proxy command + signing).
Bring your own: inject module or register custom adapter.
Multiple DBs of mixed types: fully supported.
No vendor lock-in on the DB side. The proxies are optional tooling I include so you don't have to build the HTTP-to-TCP bridge yourself when targeting Workers.