@carlos-tzin/tzin 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -38
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,13 @@
|
|
|
11
11
|
measured (see [Benchmarks](#benchmarks)), but this is not yet production software.
|
|
12
12
|
|
|
13
13
|
```sh
|
|
14
|
-
npm install tzin
|
|
14
|
+
npm install @carlos-tzin/tzin
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or scaffold a new project:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npx create-tzin my-app
|
|
15
21
|
```
|
|
16
22
|
|
|
17
23
|
## Why another framework?
|
|
@@ -29,8 +35,8 @@ The TypeScript backend landscape is crowded — and still leaves real gaps:
|
|
|
29
35
|
tzin's answer: **declare a contract once**, get everything else for free.
|
|
30
36
|
|
|
31
37
|
```ts
|
|
32
|
-
import { t } from 'tzin'
|
|
33
|
-
import { contract, impl, createApp } from 'tzin'
|
|
38
|
+
import { t } from '@carlos-tzin/tzin'
|
|
39
|
+
import { contract, impl, createApp } from '@carlos-tzin/tzin'
|
|
34
40
|
|
|
35
41
|
const getUser = contract({
|
|
36
42
|
method: 'GET',
|
|
@@ -146,7 +152,7 @@ contracts that generate your OpenAPI document also expose your endpoints as tool
|
|
|
146
152
|
for AI agents:
|
|
147
153
|
|
|
148
154
|
```ts
|
|
149
|
-
import { startStdioMcp } from 'tzin'
|
|
155
|
+
import { startStdioMcp } from '@carlos-tzin/tzin'
|
|
150
156
|
|
|
151
157
|
const app = createApp(routes)
|
|
152
158
|
startStdioMcp(app) // newline-delimited JSON-RPC on stdio
|
|
@@ -184,7 +190,7 @@ Phoenix-style channels, mounted as ordinary routes — SSE down, POST up, so it
|
|
|
184
190
|
runs on every runtime including Workers:
|
|
185
191
|
|
|
186
192
|
```ts
|
|
187
|
-
import { Hub, Presence, channelRoutes } from 'tzin'
|
|
193
|
+
import { Hub, Presence, channelRoutes } from '@carlos-tzin/tzin'
|
|
188
194
|
|
|
189
195
|
const hub = new Hub()
|
|
190
196
|
const presence = new Presence(hub, 30_000)
|
|
@@ -201,7 +207,7 @@ ghost clients disappear even after crashes. The in-memory `Hub` is one process;
|
|
|
201
207
|
multi-node deployments wire hubs together over a message bus:
|
|
202
208
|
|
|
203
209
|
```ts
|
|
204
|
-
import { Hub } from 'tzin'
|
|
210
|
+
import { Hub } from '@carlos-tzin/tzin'
|
|
205
211
|
import { LocalBus, type MessageBus } from 'tzin/bus'
|
|
206
212
|
|
|
207
213
|
// Any PUBLISH/SUBSCRIBE transport maps onto this 2-method interface:
|
|
@@ -252,8 +258,8 @@ exactly like Node/Bun (workerd drops sends that come from another request's
|
|
|
252
258
|
context, which is why plain fetch handlers can't relay between sockets):
|
|
253
259
|
|
|
254
260
|
```ts
|
|
255
|
-
import { toDurableWorker, toWorker, TzinChannels } from 'tzin'
|
|
256
|
-
import { Hub, Presence, channelRoutes, wsChannels, createApp } from 'tzin'
|
|
261
|
+
import { toDurableWorker, toWorker, TzinChannels } from '@carlos-tzin/tzin'
|
|
262
|
+
import { Hub, Presence, channelRoutes, wsChannels, createApp } from '@carlos-tzin/tzin'
|
|
257
263
|
|
|
258
264
|
export { TzinChannels } // workerd discovers DO classes among exports
|
|
259
265
|
|
|
@@ -289,22 +295,6 @@ HTTP ✓, WS upgrade ✓, roster ✓, broadcast across connections ✓, leave di
|
|
|
289
295
|
Request-scoped middleware can override. No decorators, no reflection, no
|
|
290
296
|
container configuration files.
|
|
291
297
|
|
|
292
|
-
## Roadmap
|
|
293
|
-
|
|
294
|
-
- [x] Spike: contracts, router, server, typed client, OpenAPI generation
|
|
295
|
-
- [x] Middleware composition (onion-style) with typed per-request context
|
|
296
|
-
- [x] Adapters: Node, Bun (verified e2e), Workers (HTTP + DO-backed WebSockets, verified via miniflare/workerd)
|
|
297
|
-
- [x] Streaming/SSE (`sse()` helper + `raw()` escape hatch)
|
|
298
|
-
- [x] Realtime: Hub (pub/sub), Presence (TTL + diffs), mountable channel routes
|
|
299
|
-
- [x] Native WebSockets for channels: Node + Bun verified, Workers via Durable Objects
|
|
300
|
-
- [x] Multi-node realtime over a `MessageBus` (Redis/Postgres/Durable Objects map onto it)
|
|
301
|
-
- [x] Typed client with status-discriminated unions + zero-dep browser channel client
|
|
302
|
-
- [x] Optional light DI layer (`provide()` → typed singleton seeds in request context)
|
|
303
|
-
- [x] AI-native toolchain: MCP (stdio + Streamable HTTP), OpenAPI 3.1, `/llms.txt`
|
|
304
|
-
- [x] Batteries started: CORS middleware, bearer-auth pattern (see `examples/todo-api.ts`)
|
|
305
|
-
- [ ] Phoenix-style presence replication across nodes
|
|
306
|
-
- [ ] `create-tzin` scaffolding
|
|
307
|
-
|
|
308
298
|
## Development
|
|
309
299
|
|
|
310
300
|
```sh
|
|
@@ -313,20 +303,6 @@ npm test # vitest — runtime + end-to-end client + type assertions
|
|
|
313
303
|
npm run typecheck # strict tsc across src/test/bench fixtures
|
|
314
304
|
```
|
|
315
305
|
|
|
316
|
-
### Production-shaped example
|
|
317
|
-
|
|
318
|
-
`examples/todo-api.ts` is the full story in one runnable file: bearer-token auth
|
|
319
|
-
as onion middleware, typed context DI between middleware and handlers,
|
|
320
|
-
app-scoped injected store, ownership checks, query coercion, and the generated
|
|
321
|
-
`/openapi.json` + `/llms.txt` + `POST /mcp` surface from the same contracts.
|
|
322
|
-
|
|
323
|
-
```sh
|
|
324
|
-
npx tsx examples/todo-api.ts
|
|
325
|
-
TOKEN=$(curl -s localhost:4644/auth/login -H 'content-type: application/json' \
|
|
326
|
-
-d '{"username":"ada","password":"lovelace"}' | node -pe 'JSON.parse(require("fs").readFileSync(0)).token')
|
|
327
|
-
curl -s localhost:4644/todos -H "authorization: Bearer $TOKEN"
|
|
328
|
-
```
|
|
329
|
-
|
|
330
306
|
### Dev server
|
|
331
307
|
|
|
332
308
|
```sh
|
|
@@ -343,6 +319,17 @@ tzin dev · 2 routes
|
|
|
343
319
|
POST /users create_user
|
|
344
320
|
```
|
|
345
321
|
|
|
322
|
+
### Examples
|
|
323
|
+
|
|
324
|
+
| Example | Runtime | What it shows |
|
|
325
|
+
|---|---|---|
|
|
326
|
+
| `examples/node-demo.ts` | Node | Minimal HTTP server with contracts |
|
|
327
|
+
| `examples/bun-demo.ts` | Bun | Bun.serve with validation |
|
|
328
|
+
| `examples/todo-api.ts` | Node | Full CRUD: auth middleware, DI, OpenAPI, MCP |
|
|
329
|
+
| `examples/mcp-demo.ts` | Node | MCP server over stdio |
|
|
330
|
+
| `examples/ws-demo.ts` | Bun | WebSocket channels with presence |
|
|
331
|
+
| `examples/worker-channels.ts` | Workers | Cloudflare DO-backed channels |
|
|
332
|
+
|
|
346
333
|
## License
|
|
347
334
|
|
|
348
335
|
MIT — see [LICENSE](./LICENSE).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@carlos-tzin/tzin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Contract-first TypeScript framework. Types that scale, realtime channels with presence, and an MCP server for every API.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "The tzin authors",
|