@carlos-tzin/tzin 1.0.1 → 1.0.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.3 — Quality pass before wider adoption
4
+
5
+ No API changes. Focused on proving the stable claim in CI and on the
6
+ type surface.
7
+
8
+ ### Testing & coverage
9
+
10
+ - Unit suites for `cache.ts` and `rate-limit.ts` (30 tests) — previously the
11
+ only modules without direct coverage
12
+ - Coverage gates in CI: `npm run test:coverage` requires ≥70% lines, functions,
13
+ statements and branches across `src/` (baseline 73.6%)
14
+ - `vitest.config.ts` with the v8 provider; `coverage/` git-ignored
15
+
16
+ ### CI matrix
17
+
18
+ - Node `20 / 22 / 24` — previously only 22 and 24; Node 20 is the documented
19
+ floor and is now exercised
20
+ - Cloudflare Workers probe (`miniflare`) runs on every push, not just releases
21
+ - Benchmark job (`lookup`, `pipeline`, `http`) runs in CI with minimal rounds
22
+ to catch runtime regressions early
23
+
24
+ ### Type-surface cleanup
25
+
26
+ - Public `RouteImpl<any>` occurrences replaced by the new erasable
27
+ `AnyRoute` type — `createApp`, MCP tools, OpenAPI, llms.txt, channels and
28
+ route-table printing now take `AnyRoute[]` while `impl()` keeps full
29
+ per-endpoint typing
30
+ - Browser client callbacks (`on`) and internal `any` returns typed as
31
+ `unknown`; `client()` proxy input uses a typed `ClientInput`
32
+ - New exports: `AnyRoute`, `RouteResult`
33
+
3
34
  ## 1.0.1 — Repo moved to Tzinny-dev
4
35
 
5
36
  Metadata-only release after the source repository moved from
package/README.md CHANGED
@@ -7,9 +7,11 @@
7
7
 
8
8
  [![CI](https://github.com/Tzinny-dev/tzin/actions/workflows/ci.yml/badge.svg)](https://github.com/Tzinny-dev/tzin/actions/workflows/ci.yml)
9
9
  [![npm](https://img.shields.io/npm/v/@carlos-tzin/tzin)](https://www.npmjs.com/package/@carlos-tzin/tzin)
10
+ [![Donate](https://img.shields.io/badge/Donate-PayPal-00457C?logo=paypal&logoColor=white)](https://paypal.me/carlostzin)
10
11
 
11
- **Status: experimental, pre-1.0.** The core works end-to-end and the scaling thesis is
12
- measured (see [Benchmarks](#benchmarks)), but this is not yet production software.
12
+ **Status: stable (1.0.x).** The core works end-to-end (see [Benchmarks](#benchmarks));
13
+ 1.0.0 shipped the stable API, and 1.0.2 adds test coverage gates, a wider CI
14
+ matrix and a public type-clean surface.
13
15
 
14
16
  ```sh
15
17
  npm install @carlos-tzin/tzin
@@ -1,4 +1,4 @@
1
- import { type RouteImpl } from './contract.js';
1
+ import { type AnyRoute } from './contract.js';
2
2
  import type { Hub } from './hub.js';
3
3
  import type { Presence } from './presence.js';
4
4
  export interface ChannelOptions {
@@ -11,4 +11,4 @@ export interface ChannelOptions {
11
11
  * POST /channels/:topic/heartbeat presence join/refresh { member, meta? }
12
12
  * POST /channels/:topic/leave presence leave { member }
13
13
  */
14
- export declare function channelRoutes(hub: Hub, options?: ChannelOptions): RouteImpl<any>[];
14
+ export declare function channelRoutes(hub: Hub, options?: ChannelOptions): AnyRoute[];
@@ -33,7 +33,7 @@ export type Unsubscribe = () => void;
33
33
  export interface Channel {
34
34
  readonly topic: string;
35
35
  /** Listen to a named event; returns an unsubscribe function. */
36
- on(event: string, cb: (data: any) => void): Unsubscribe;
36
+ on(event: string, cb: (data: unknown) => void): Unsubscribe;
37
37
  /** Broadcast to every subscriber of this channel. */
38
38
  push(event: string, data?: unknown): Promise<{
39
39
  delivered: number;
@@ -62,6 +62,23 @@ export interface RouteImpl<C extends AnyContract = AnyContract> {
62
62
  }
63
63
  /** Bind an implementation to a contract. The compiler checks inputs AND outputs. */
64
64
  export declare function impl<const C extends AnyContract>(c: C, handler: Handler<C>): RouteImpl<C>;
65
+ /** A handler's resolved reply with the per-endpoint generics erased. */
66
+ export type RouteResult = {
67
+ status: number;
68
+ body: unknown;
69
+ } | RawResult;
70
+ /**
71
+ * A route with its contract generics erased, for heterogeneous registries —
72
+ * `createApp`, OpenAPI/MCP/llms generators, docs tools. Each concrete
73
+ * `RouteImpl<C>` satisfies it (impl keeps inputs/outputs fully typed); the
74
+ * erased handler is only invoked by dispatchers, which supply validated
75
+ * sections via a cast (the `never` input makes accidental direct calls a
76
+ * compile error).
77
+ */
78
+ export interface AnyRoute {
79
+ contract: AnyContract;
80
+ handler: (input: never) => RouteResult | Promise<RouteResult>;
81
+ }
65
82
  /** Thrown inside handlers -> converted to an HTTP error response. */
66
83
  export declare class HttpError extends Error {
67
84
  readonly status: number;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { contract, impl, HttpError, type HttpMethod, type ContractDef, type AnyContract, type PathParamNames, type HandlerInput, type SectionsOf, type ResponseOf, type Handler, type RouteImpl, } from './contract.js';
1
+ export { contract, impl, HttpError, type HttpMethod, type ContractDef, type AnyContract, type PathParamNames, type HandlerInput, type SectionsOf, type ResponseOf, type Handler, type RouteImpl, type AnyRoute, type RouteResult, } from './contract.js';
2
2
  export { createApp, type App } from './server.js';
3
3
  export { client, type ClientOf, type ClientResult, type CallerFn } from './client.js';
4
4
  export { generateOpenApi } from './openapi.js';
package/dist/llms.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import type { RouteImpl } from './contract.js';
1
+ import type { AnyRoute } from './contract.js';
2
2
  export interface ApiMeta {
3
3
  title?: string;
4
4
  description?: string;
5
5
  version?: string;
6
6
  }
7
7
  /** llms.txt: the discoverable, human-readable index of the API. */
8
- export declare function renderLlmsTxt(routes: RouteImpl<any>[], meta?: ApiMeta): string;
8
+ export declare function renderLlmsTxt(routes: AnyRoute[], meta?: ApiMeta): string;
9
9
  /** llms-full.txt: same index plus each endpoint's declared JSON Schemas. */
10
- export declare function renderLlmsFullTxt(routes: RouteImpl<any>[], meta?: ApiMeta): string;
10
+ export declare function renderLlmsFullTxt(routes: AnyRoute[], meta?: ApiMeta): string;
package/dist/llms.js CHANGED
@@ -32,8 +32,9 @@ export function renderLlmsFullTxt(routes, meta = {}) {
32
32
  ...(c.description ? [`${c.description}`, ''] : []),
33
33
  ];
34
34
  for (const section of ['params', 'query', 'headers', 'cookies', 'body']) {
35
- if (section in c && c[section]) {
36
- lines.push(`\`${section}\` schema:`, '', '```json', JSON.stringify(c[section]), '```', '');
35
+ const schema = c[section];
36
+ if (schema) {
37
+ lines.push(`\`${section}\` schema:`, '', '```json', JSON.stringify(schema), '```', '');
37
38
  }
38
39
  }
39
40
  for (const [status, schema] of Object.entries(c.responses)) {
package/dist/mcp.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import type { App } from './server.js';
2
- import type { RouteImpl } from './contract.js';
2
+ import type { AnyRoute } from './contract.js';
3
3
  /**
4
4
  * One endpoint = one MCP tool.
5
5
  * The inputSchema is assembled from the contract's declared sections —
6
6
  * TypeBox schemas are already JSON Schema, so there is no conversion layer.
7
7
  */
8
- export declare function toTool(route: RouteImpl<any>): Record<string, unknown>;
9
- export declare function listTools(routes: RouteImpl<any>[]): Record<string, unknown>[];
8
+ export declare function toTool(route: AnyRoute): Record<string, unknown>;
9
+ export declare function listTools(routes: AnyRoute[]): Record<string, unknown>[];
10
10
  export interface RpcRequest {
11
11
  jsonrpc?: string;
12
12
  id?: string | number | null;
package/dist/openapi.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import type { RouteImpl } from './contract.js';
1
+ import type { AnyRoute } from './contract.js';
2
2
  /**
3
3
  * OpenAPI 3.1 document generated from contracts.
4
4
  * Zero conversion layer: TypeBox == JSON Schema == OpenAPI component vocabulary.
5
5
  */
6
- export declare function generateOpenApi(routes: RouteImpl<any>[], info?: {
6
+ export declare function generateOpenApi(routes: AnyRoute[], info?: {
7
7
  title: string;
8
8
  version: string;
9
9
  }): Record<string, unknown>;
package/dist/server.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { type RouteImpl } from './contract.js';
1
+ import { type AnyRoute } from './contract.js';
2
2
  import { type Middleware } from './middleware.js';
3
3
  import type { ProvidedEntry } from './provide.js';
4
4
  import { type ApiMeta } from './llms.js';
5
5
  export interface App {
6
- routes: RouteImpl<any>[];
6
+ routes: AnyRoute[];
7
7
  fetch(req: Request): Promise<Response>;
8
8
  /**
9
9
  * Same dispatch as fetch(), without constructing undici Responses for
@@ -42,4 +42,4 @@ export declare function fastResponseHeaders(res: Response): Record<string, strin
42
42
  * stay lazy; real Request objects carry a plain signal.
43
43
  */
44
44
  export declare function signalSource(req: Request): AbortSignal | (() => AbortSignal | undefined) | undefined;
45
- export declare function createApp(routes: RouteImpl<any>[], options?: AppOptions): App;
45
+ export declare function createApp(routes: AnyRoute[], options?: AppOptions): App;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carlos-tzin/tzin",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
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",
@@ -85,6 +85,7 @@
85
85
  "build": "tsc -p tsconfig.build.json",
86
86
  "prepublishOnly": "npm run build && npm test",
87
87
  "test": "vitest run",
88
+ "test:coverage": "vitest run --coverage",
88
89
  "typecheck": "tsc --noEmit",
89
90
  "typecheck:ours": "tsc -p bench/tsconfig.ours.json --noEmit --extendedDiagnostics",
90
91
  "typecheck:hono": "tsc -p bench/tsconfig.hono.json --noEmit --extendedDiagnostics",
@@ -103,7 +104,9 @@
103
104
  "@hono/node-server": "^2.1.1",
104
105
  "@types/node": "^26.2.0",
105
106
  "@types/ws": "^8.18.1",
107
+ "@vitest/coverage-v8": "^2.1.9",
106
108
  "autocannon": "^8.0.0",
109
+ "esbuild": "^0.28.0",
107
110
  "express": "^5.2.1",
108
111
  "hono": "^4.0.0",
109
112
  "miniflare": "^5.20260820.0-alpha",