@contractspec/lib.contracts-runtime-server-rest 3.7.5 → 3.7.7

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 CHANGED
@@ -1,166 +1,68 @@
1
1
  # @contractspec/lib.contracts-runtime-server-rest
2
2
 
3
- REST runtime adapters for exposing ContractSpec operations over HTTP.
3
+ **REST server runtime adapters for ContractSpec contracts.**
4
4
 
5
- Website: https://contractspec.io/
5
+ ## What It Provides
6
6
 
7
- ## Why this package exists
7
+ - **Layer**: lib.
8
+ - **Consumers**: bundles, all REST apps.
9
+ - Related ContractSpec packages include `@contractspec/lib.contracts-spec`, `@contractspec/lib.schema`, `@contractspec/tool.bun`, `@contractspec/tool.typescript`.
10
+ - Related ContractSpec packages include `@contractspec/lib.contracts-spec`, `@contractspec/lib.schema`, `@contractspec/tool.bun`, `@contractspec/tool.typescript`.
8
11
 
9
- This package is the REST adapter layer extracted from `@contractspec/lib.contracts`.
12
+ ## Installation
10
13
 
11
- It lets you take an `OperationSpecRegistry` and expose it in multiple server environments with consistent behavior:
14
+ `npm install @contractspec/lib.contracts-runtime-server-rest`
12
15
 
13
- - framework-agnostic fetch handler
14
- - Express adapter
15
- - Elysia adapter
16
- - Next.js App Router adapter
17
- - Next.js Pages Router adapter
16
+ or
18
17
 
19
- ## Package boundary (important)
18
+ `bun add @contractspec/lib.contracts-runtime-server-rest`
20
19
 
21
- Use this package for:
20
+ ## Usage
22
21
 
23
- - HTTP transport projection of operation specs.
24
- - Shared REST concerns (route derivation, input parsing, CORS, error mapping).
25
- - Helper utilities reused by GraphQL runtime (`contracts-adapter-input`, `contracts-adapter-hydration`).
22
+ Import the root entrypoint from `@contractspec/lib.contracts-runtime-server-rest`, or choose a documented subpath when you only need one part of the package surface.
26
23
 
27
- Do not use this package for:
24
+ ## Architecture
28
25
 
29
- - Defining operation contracts (use `@contractspec/lib.contracts-spec`).
30
- - Building GraphQL schema (use `@contractspec/lib.contracts-runtime-server-graphql`).
26
+ - `src/contracts-adapter-hydration.ts` is part of the package's public or composition surface.
27
+ - `src/contracts-adapter-input.ts` is part of the package's public or composition surface.
28
+ - `src/index.ts` is the root public barrel and package entrypoint.
29
+ - `src/rest-elysia.ts` is part of the package's public or composition surface.
30
+ - `src/rest-express.ts` is part of the package's public or composition surface.
31
+ - `src/rest-generic.ts` is part of the package's public or composition surface.
32
+ - `src/rest-next-app.ts` is part of the package's public or composition surface.
31
33
 
32
- ## Installation
34
+ ## Public Entry Points
35
+
36
+ - Export `.` resolves through `./src/index.ts`.
37
+ - Export `./contracts-adapter-hydration` resolves through `./src/contracts-adapter-hydration.ts`.
38
+ - Export `./contracts-adapter-input` resolves through `./src/contracts-adapter-input.ts`.
39
+ - Export `./rest-elysia` resolves through `./src/rest-elysia.ts`.
40
+ - Export `./rest-express` resolves through `./src/rest-express.ts`.
41
+ - Export `./rest-generic` resolves through `./src/rest-generic.ts`.
42
+ - Export `./rest-next-app` resolves through `./src/rest-next-app.ts`.
43
+ - Export `./rest-next-pages` resolves through `./src/rest-next-pages.ts`.
44
+
45
+ ## Local Commands
46
+
47
+ - `bun run dev` — contractspec-bun-build dev
48
+ - `bun run build` — bun run prebuild && bun run build:bundle && bun run build:types
49
+ - `bun run lint` — bun run lint:fix
50
+ - `bun run lint:check` — biome check .
51
+ - `bun run lint:fix` — biome check --write --unsafe --only=nursery/useSortedClasses . && biome check --write .
52
+ - `bun run typecheck` — tsc --noEmit
53
+ - `bun run publish:pkg` — bun publish --tolerate-republish --ignore-scripts --verbose
54
+ - `bun run publish:pkg:canary` — bun publish:pkg --tag canary
55
+ - `bun run clean` — rm -rf dist
56
+ - `bun run build:bundle` — contractspec-bun-build transpile
57
+ - `bun run build:types` — contractspec-bun-build types
58
+ - `bun run prebuild` — contractspec-bun-build prebuild
59
+
60
+ ## Recent Updates
61
+
62
+ - Replace eslint+prettier by biomejs to optimize speed.
63
+
64
+ ## Notes
33
65
 
34
- ```bash
35
- npm install @contractspec/lib.contracts-runtime-server-rest @contractspec/lib.contracts-spec
36
- # or
37
- bun add @contractspec/lib.contracts-runtime-server-rest @contractspec/lib.contracts-spec
38
- ```
39
-
40
- Install whichever peer framework you use (`express`, `elysia`, `next`).
41
-
42
- ## Export map
43
-
44
- - Generic handler:
45
- - `createFetchHandler`
46
- - `RestOptions`
47
- - Framework adapters:
48
- - `expressRouter`
49
- - `elysiaPlugin`
50
- - `makeNextAppHandler`
51
- - `makeNextPagesHandler`
52
- - Shared adapter internals:
53
- - `createInputTypeBuilder`
54
- - `hydrateResourceIfNeeded`
55
- - `parseReturns`
56
-
57
- ## Quick start (framework-agnostic)
58
-
59
- ```ts
60
- import { createFetchHandler } from "@contractspec/lib.contracts-runtime-server-rest";
61
- import type { HandlerCtx } from "@contractspec/lib.contracts-spec";
62
- import type { OperationSpecRegistry } from "@contractspec/lib.contracts-spec/operations/registry";
63
-
64
- declare const operations: OperationSpecRegistry;
65
-
66
- const handler = createFetchHandler(
67
- operations,
68
- (request): HandlerCtx => ({
69
- actor: "user",
70
- channel: "web",
71
- traceId: request.headers.get("x-trace-id") ?? undefined,
72
- }),
73
- {
74
- basePath: "/api/contracts",
75
- cors: true,
76
- prettyJson: 2,
77
- }
78
- );
79
-
80
- const response = await handler(
81
- new Request("https://example.com/api/contracts/workspace/get/v1.0.0")
82
- );
83
- console.log(response.status);
84
- ```
85
-
86
- ## Framework examples
87
-
88
- ### Express
89
-
90
- ```ts
91
- import express from "express";
92
- import { expressRouter } from "@contractspec/lib.contracts-runtime-server-rest/rest-express";
93
-
94
- declare const operations: import("@contractspec/lib.contracts-spec/operations/registry").OperationSpecRegistry;
95
-
96
- const app = express();
97
- app.use(express.json());
98
-
99
- app.use(
100
- expressRouter(
101
- express,
102
- operations,
103
- () => ({ actor: "user", channel: "web" }),
104
- { basePath: "/api/contracts", cors: true }
105
- )
106
- );
107
- ```
108
-
109
- ### Next.js App Router
110
-
111
- ```ts
112
- import { makeNextAppHandler } from "@contractspec/lib.contracts-runtime-server-rest/rest-next-app";
113
-
114
- declare const operations: import("@contractspec/lib.contracts-spec/operations/registry").OperationSpecRegistry;
115
-
116
- const handler = makeNextAppHandler(
117
- operations,
118
- () => ({ actor: "user", channel: "web" }),
119
- { basePath: "/api/contracts" }
120
- );
121
-
122
- export const GET = handler;
123
- export const POST = handler;
124
- export const OPTIONS = handler;
125
- ```
126
-
127
- ## Runtime behavior details
128
-
129
- - Default method mapping:
130
- - query -> `GET`
131
- - command -> `POST`
132
- - Default path mapping:
133
- - `/<operation.key with dots replaced by slashes>/v<version>`
134
- - GET input parsing:
135
- - if `input` query param exists, parse it as JSON
136
- - otherwise use query params as flat object
137
- - POST input parsing:
138
- - supports `application/json` and `application/x-www-form-urlencoded`
139
- - Error mapping defaults:
140
- - validation errors -> `400`
141
- - `PolicyDenied*` errors -> `403`
142
- - unknown errors -> `500`
143
- - unsupported content type -> `415`
144
-
145
- You can override error serialization using `RestOptions.onError`.
146
-
147
- ## AI assistant guidance
148
-
149
- When generating code:
150
-
151
- - Define operation specs first in `@contractspec/lib.contracts-spec`.
152
- - Start with `createFetchHandler` for deterministic behavior, then choose framework wrappers.
153
- - Keep `basePath` explicit to avoid route ambiguity in generated handlers.
154
-
155
- When debugging:
156
-
157
- - If a route is 404, verify operation key/version and derived path.
158
- - If input parsing fails on GET, check whether caller sends `input=` JSON vs plain query params.
159
-
160
- ## Split migration from deprecated monolith
161
-
162
- - `@contractspec/lib.contracts/server/rest-generic` -> `@contractspec/lib.contracts-runtime-server-rest/rest-generic`
163
- - `@contractspec/lib.contracts/server/rest-express` -> `@contractspec/lib.contracts-runtime-server-rest/rest-express`
164
- - `@contractspec/lib.contracts/server/rest-elysia` -> `@contractspec/lib.contracts-runtime-server-rest/rest-elysia`
165
- - `@contractspec/lib.contracts/server/rest-next-app` -> `@contractspec/lib.contracts-runtime-server-rest/rest-next-app`
166
- - `@contractspec/lib.contracts/server/rest-next-pages` -> `@contractspec/lib.contracts-runtime-server-rest/rest-next-pages`
66
+ - High blast radius — all REST APIs depend on this package.
67
+ - Framework adapters (Elysia, Express, Next.js) must stay independent of each other.
68
+ - Do not introduce cross-adapter coupling.
@@ -1,7 +1,7 @@
1
- import type { Elysia } from 'elysia';
2
- import { type RestOptions } from './rest-generic';
3
1
  import type { OperationSpecRegistry } from '@contractspec/lib.contracts-spec/operations/registry';
4
2
  import type { HandlerCtx } from '@contractspec/lib.contracts-spec/types';
3
+ import type { Elysia } from 'elysia';
4
+ import { type RestOptions } from './rest-generic';
5
5
  export declare function elysiaPlugin(app: Elysia, reg: OperationSpecRegistry, ctxFactory: (c: {
6
6
  request: Request;
7
7
  store: unknown;
@@ -1,7 +1,7 @@
1
- import type { Request as ExpressReq, Router } from 'express';
2
- import { type RestOptions } from './rest-generic';
3
1
  import type { OperationSpecRegistry } from '@contractspec/lib.contracts-spec/operations/registry';
4
2
  import type { HandlerCtx } from '@contractspec/lib.contracts-spec/types';
3
+ import type { Request as ExpressReq, Router } from 'express';
4
+ import { type RestOptions } from './rest-generic';
5
5
  export declare function expressRouter(express: {
6
6
  Router: () => Router;
7
7
  }, reg: OperationSpecRegistry, ctxFactory: (req: ExpressReq) => HandlerCtx, options?: RestOptions): Router;
@@ -1,4 +1,4 @@
1
- import { type RestOptions } from './rest-generic';
2
1
  import type { OperationSpecRegistry } from '@contractspec/lib.contracts-spec/operations/registry';
3
2
  import type { HandlerCtx } from '@contractspec/lib.contracts-spec/types';
3
+ import { type RestOptions } from './rest-generic';
4
4
  export declare function makeNextAppHandler(reg: OperationSpecRegistry, ctxFactory: (req: Request) => HandlerCtx, options?: RestOptions): (req: Request) => Promise<Response>;
@@ -1,5 +1,5 @@
1
- import type { NextApiRequest, NextApiResponse } from 'next';
2
- import { type RestOptions } from './rest-generic';
3
1
  import type { OperationSpecRegistry } from '@contractspec/lib.contracts-spec/operations/registry';
4
2
  import type { HandlerCtx } from '@contractspec/lib.contracts-spec/types';
3
+ import type { NextApiRequest, NextApiResponse } from 'next';
4
+ import { type RestOptions } from './rest-generic';
5
5
  export declare function makeNextPagesHandler(reg: OperationSpecRegistry, ctxFactory: (req: NextApiRequest) => HandlerCtx, options?: RestOptions): (req: NextApiRequest, res: NextApiResponse) => Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contractspec/lib.contracts-runtime-server-rest",
3
- "version": "3.7.5",
3
+ "version": "3.7.7",
4
4
  "description": "REST server runtime adapters for ContractSpec contracts",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
@@ -9,8 +9,8 @@
9
9
  "publish:pkg:canary": "bun publish:pkg --tag canary",
10
10
  "clean": "rm -rf dist",
11
11
  "lint": "bun run lint:fix",
12
- "lint:fix": "eslint src --fix",
13
- "lint:check": "eslint src",
12
+ "lint:fix": "biome check --write --unsafe --only=nursery/useSortedClasses . && biome check --write .",
13
+ "lint:check": "biome check .",
14
14
  "build": "bun run prebuild && bun run build:bundle && bun run build:types",
15
15
  "build:bundle": "contractspec-bun-build transpile",
16
16
  "build:types": "contractspec-bun-build types",
@@ -24,19 +24,19 @@
24
24
  "directory": "packages/libs/contract-runtime-server-rest"
25
25
  },
26
26
  "dependencies": {
27
- "@contractspec/lib.contracts-spec": "3.7.5",
28
- "@contractspec/lib.schema": "3.7.5"
27
+ "@contractspec/lib.contracts-spec": "4.0.0",
28
+ "@contractspec/lib.schema": "3.7.6"
29
29
  },
30
30
  "peerDependencies": {
31
31
  "@pothos/core": "^4.9.1",
32
- "elysia": "^1.4.27",
32
+ "elysia": "^1.4.28",
33
33
  "express": "^5.2.1",
34
- "next": "16.1.6"
34
+ "next": "16.2.0"
35
35
  },
36
36
  "devDependencies": {
37
- "@contractspec/tool.typescript": "3.7.5",
37
+ "@contractspec/tool.typescript": "3.7.6",
38
38
  "typescript": "^5.9.3",
39
- "@contractspec/tool.bun": "3.7.5"
39
+ "@contractspec/tool.bun": "3.7.6"
40
40
  },
41
41
  "files": [
42
42
  "dist",