expediate 1.0.4 → 1.0.6
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 +138 -0
- package/CONTRIBUTING.md +150 -0
- package/LICENSE +16 -16
- package/README.md +330 -444
- package/dist/apis.d.ts +504 -27
- package/dist/apis.d.ts.map +1 -1
- package/dist/apis.js +618 -107
- package/dist/apis.js.map +1 -1
- package/dist/cjs/index.js +4066 -0
- package/dist/cjs/package.json +1 -0
- package/dist/git.d.ts +72 -9
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +129 -74
- package/dist/git.js.map +1 -1
- package/dist/http-objects.d.ts +26 -0
- package/dist/http-objects.d.ts.map +1 -0
- package/dist/http-objects.js +588 -0
- package/dist/http-objects.js.map +1 -0
- package/dist/index.d.ts +18 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -24
- package/dist/index.js.map +1 -1
- package/dist/jwt-auth.d.ts +158 -57
- package/dist/jwt-auth.d.ts.map +1 -1
- package/dist/jwt-auth.js +447 -207
- package/dist/jwt-auth.js.map +1 -1
- package/dist/middleware.d.ts +476 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +647 -0
- package/dist/middleware.js.map +1 -0
- package/dist/mimetypes.json +882 -1
- package/dist/misc.d.ts +268 -25
- package/dist/misc.d.ts.map +1 -1
- package/dist/misc.js +449 -168
- package/dist/misc.js.map +1 -1
- package/dist/openapi.d.ts +433 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +624 -0
- package/dist/openapi.js.map +1 -0
- package/dist/router-types.d.ts +760 -0
- package/dist/router-types.d.ts.map +1 -0
- package/dist/router-types.js +23 -0
- package/dist/router-types.js.map +1 -0
- package/dist/router.d.ts +37 -201
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +502 -244
- package/dist/router.js.map +1 -1
- package/dist/static.d.ts +3 -3
- package/dist/static.d.ts.map +1 -1
- package/dist/static.js +164 -105
- package/dist/static.js.map +1 -1
- package/docs/THREAT_MODEL.md +52 -0
- package/docs/api-builder-v2-design.md +644 -0
- package/docs/api-builder-v3-design.md +397 -0
- package/docs/api-builder.md +454 -0
- package/docs/benchmark.md +27 -0
- package/docs/body-parsing.md +223 -0
- package/docs/errors.md +359 -0
- package/docs/expediate.png +0 -0
- package/docs/git.md +139 -0
- package/docs/jwt-auth.md +251 -0
- package/docs/logo.svg +12 -0
- package/docs/middleware.md +264 -0
- package/docs/openapi.md +180 -0
- package/docs/router.md +356 -0
- package/docs/static.md +128 -0
- package/docs/wiki.json +123 -0
- package/package.json +47 -8
- package/.npmignore +0 -16
package/dist/apis.d.ts
CHANGED
|
@@ -1,16 +1,87 @@
|
|
|
1
|
-
import type { RouterRequest, Router } from './router.js';
|
|
1
|
+
import type { RouterRequest, RouterResponse, Router, Middleware } from './router.js';
|
|
2
|
+
import './openapi.js';
|
|
3
|
+
import type { SpecOptions, SpecFormat, OpenApiDocument, OperationMeta, JsonSchema } from './openapi.js';
|
|
4
|
+
/**
|
|
5
|
+
* Context object passed as the first argument to every service method handler.
|
|
6
|
+
*
|
|
7
|
+
* Replaces the old flat `params` map: route parameters, URL query parameters,
|
|
8
|
+
* and other request-scoped data are now namespaced to avoid collisions and to
|
|
9
|
+
* make each data source explicit.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* GET: {
|
|
14
|
+
* '/items/:id': function (ctx: ApiContext) {
|
|
15
|
+
* const id = ctx.params.id; // ':id' from the path pattern
|
|
16
|
+
* const fmt = ctx.query.url.format; // '?format=json' from the query string
|
|
17
|
+
* return getItem(id, fmt);
|
|
18
|
+
* },
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @template TUser - The shape of the authenticated user payload (e.g.
|
|
23
|
+
* `TokenPayload` from the JWT plugin). Defaults to
|
|
24
|
+
* `unknown`, forcing explicit typing for safe access.
|
|
25
|
+
* @template TState - The shape of the guard-produced `state` bag.
|
|
26
|
+
*/
|
|
27
|
+
export interface ApiContext<TUser = unknown, TState = Record<string, unknown>> {
|
|
28
|
+
/** Route and URL query parameters, separated by origin. */
|
|
29
|
+
query: {
|
|
30
|
+
/**
|
|
31
|
+
* Named parameters captured from the route pattern.
|
|
32
|
+
*
|
|
33
|
+
* For example, a route registered as `/items/:id` matched against
|
|
34
|
+
* `/items/42` produces `{ id: '42' }`.
|
|
35
|
+
*/
|
|
36
|
+
route: Record<string, string>;
|
|
37
|
+
/**
|
|
38
|
+
* Parameters decoded from the URL query string.
|
|
39
|
+
*
|
|
40
|
+
* Repeated keys are preserved as string arrays.
|
|
41
|
+
* For example, `?q=hello&tag=a&tag=b` → `{ q: 'hello', tag: ['a', 'b'] }`.
|
|
42
|
+
*/
|
|
43
|
+
url: Record<string, string | string[]>;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Shorthand alias for {@link ApiContext.query}.route — the named parameters
|
|
47
|
+
* captured from the route pattern. This is the dominant access pattern;
|
|
48
|
+
* the namespaced form remains available for collision cases.
|
|
49
|
+
*/
|
|
50
|
+
params: Record<string, string>;
|
|
51
|
+
/**
|
|
52
|
+
* The request path as seen by this API router, after any prefix stripping
|
|
53
|
+
* performed by a parent `use()` mount.
|
|
54
|
+
*/
|
|
55
|
+
path: string;
|
|
56
|
+
/**
|
|
57
|
+
* Authentication data attached to the request, if present.
|
|
58
|
+
*
|
|
59
|
+
* Populated when a middleware (e.g. a JWT `authenticate` middleware) sets
|
|
60
|
+
* `req.user` before the service method is called. `undefined` when no
|
|
61
|
+
* authentication data has been attached.
|
|
62
|
+
*/
|
|
63
|
+
user?: TUser;
|
|
64
|
+
/**
|
|
65
|
+
* Values produced by guards (loaded resources, resolved roles, …).
|
|
66
|
+
*
|
|
67
|
+
* Each guard that returns an object has that object shallow-merged into
|
|
68
|
+
* this bag before the next guard (or the handler) runs. Starts as `{}`
|
|
69
|
+
* for every request.
|
|
70
|
+
*/
|
|
71
|
+
state: TState;
|
|
72
|
+
}
|
|
2
73
|
/**
|
|
3
74
|
* An API error thrown (or rejected) by a service method.
|
|
4
75
|
*
|
|
5
76
|
* When a service method throws or rejects with an object of this shape, the
|
|
6
77
|
* framework translates it into an HTTP error response automatically:
|
|
7
|
-
* - `
|
|
78
|
+
* - `status` → HTTP status code (defaults to `500`).
|
|
8
79
|
* - `data` → JSON-serialised response body (takes precedence over `message`).
|
|
9
80
|
* - `message` → Plain-text response body.
|
|
10
81
|
*/
|
|
11
82
|
export interface ApiError {
|
|
12
83
|
/** HTTP status code to send (e.g. `404`, `503`). Defaults to `500`. */
|
|
13
|
-
|
|
84
|
+
status?: number;
|
|
14
85
|
/** Structured error payload; serialised to JSON when present. */
|
|
15
86
|
data?: unknown;
|
|
16
87
|
/** Human-readable error message used when `data` is absent. */
|
|
@@ -21,21 +92,23 @@ export interface ApiError {
|
|
|
21
92
|
*
|
|
22
93
|
* Called with `this` bound to the current service instance.
|
|
23
94
|
*
|
|
24
|
-
* @param
|
|
25
|
-
*
|
|
26
|
-
* @
|
|
27
|
-
*
|
|
95
|
+
* @param ctx - Request context containing route parameters, URL query
|
|
96
|
+
* parameters, the request path, and optional auth data.
|
|
97
|
+
* See {@link ApiContext}.
|
|
98
|
+
* @param body - Parsed request body (populated by a body-parsing middleware
|
|
99
|
+
* such as `json()`).
|
|
28
100
|
* @returns The value to send as the JSON response body, a `Promise` of the
|
|
29
101
|
* same, or `undefined` / `null` / any falsy value to send **201 No
|
|
30
102
|
* Content** (useful for mutations that produce no response body).
|
|
31
103
|
*/
|
|
32
|
-
export type ServiceMethod<TInstance = ServiceInstance> = (this: TInstance,
|
|
104
|
+
export type ServiceMethod<TInstance = ServiceInstance, TResponse = any, TBody = any> = (this: TInstance, ctx: ApiContext, body?: TBody) => TResponse | Promise<TResponse>;
|
|
33
105
|
/**
|
|
34
106
|
* The runtime state object that backs a service instance.
|
|
35
107
|
*
|
|
36
|
-
* Produced by `service.data()`
|
|
37
|
-
* `service.methods` before `service.setup()`
|
|
38
|
-
* property carries the scope key when `data()` is
|
|
108
|
+
* Produced by `service.data()` (which returns `Partial<TInstance>`) and
|
|
109
|
+
* extended with the methods from `service.methods` before `service.setup()`
|
|
110
|
+
* is called. A hidden `$key` property carries the scope key when `data()` is
|
|
111
|
+
* not supplied.
|
|
39
112
|
*/
|
|
40
113
|
export type ServiceInstance = Record<string, unknown> & {
|
|
41
114
|
/** The scope key used to identify this instance (set by the framework). */
|
|
@@ -47,16 +120,222 @@ export type ServiceInstance = Record<string, unknown> & {
|
|
|
47
120
|
* Methods declared here are copied onto the instance object, bound to `this`,
|
|
48
121
|
* so they can call each other and read/write instance state naturally.
|
|
49
122
|
*/
|
|
50
|
-
export type ServiceMethods<TInstance extends ServiceInstance = ServiceInstance> =
|
|
51
|
-
[name: string]: (this: TInstance, ...args: unknown[]) => unknown;
|
|
52
|
-
};
|
|
123
|
+
export type ServiceMethods<TInstance extends ServiceInstance = ServiceInstance> = Record<string, (this: TInstance, ...args: unknown[]) => unknown>;
|
|
53
124
|
/**
|
|
54
125
|
* A route map: keys are Express-style path patterns, values are handler
|
|
55
126
|
* functions that are invoked with `this` bound to the service instance.
|
|
56
127
|
*/
|
|
57
|
-
export type RouteMap<TInstance extends ServiceInstance = ServiceInstance> =
|
|
58
|
-
|
|
59
|
-
|
|
128
|
+
export type RouteMap<TInstance extends ServiceInstance = ServiceInstance> = Record<string, ServiceMethod<TInstance>>;
|
|
129
|
+
/**
|
|
130
|
+
* A pre-handler hook running in the `ctx` world.
|
|
131
|
+
*
|
|
132
|
+
* Guards attach at three levels — API (`ServiceDefinition.guards`),
|
|
133
|
+
* controller (`ControllerDefinition.guards`), and route
|
|
134
|
+
* (`OperationMeta.guards` via `describe()`) — and run outermost-first:
|
|
135
|
+
*
|
|
136
|
+
* ```
|
|
137
|
+
* auth.authenticate → auth.check → api guards → controller guards → route guards → handler
|
|
138
|
+
* ```
|
|
139
|
+
*
|
|
140
|
+
* A guard may:
|
|
141
|
+
* - **throw / reject** an {@link ApiError} → translated to an HTTP error response;
|
|
142
|
+
* - **return an object** → shallow-merged into `ctx.state`;
|
|
143
|
+
* - **return void** → pure check.
|
|
144
|
+
*
|
|
145
|
+
* Guards are loosely typed on purpose (`ctx.user` is `any` here); declare
|
|
146
|
+
* `ApiContext<TUser, TState>` explicitly in handlers for strict typing.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* const requireAdmin: Guard = (ctx) => {
|
|
151
|
+
* if (!ctx.user?.isAdmin) throw { status: 403, message: 'Admin access required' };
|
|
152
|
+
* return { admin: true }; // → ctx.state.admin
|
|
153
|
+
* };
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
export type Guard = (ctx: ApiContext<any, Record<string, unknown>>, req: RouterRequest) => void | Record<string, unknown> | Promise<void | Record<string, unknown>>;
|
|
157
|
+
/**
|
|
158
|
+
* A group of routes sharing a path prefix, default OpenAPI tags, guards, and
|
|
159
|
+
* a default permission requirement.
|
|
160
|
+
*
|
|
161
|
+
* Controllers are *route organisation*, not isolation boundaries: handlers in
|
|
162
|
+
* every controller run with `this` bound to the same service instance (the
|
|
163
|
+
* instance lifecycle — `scope` / `data` / `setup` / `methods` — stays at the
|
|
164
|
+
* {@link ServiceDefinition} level).
|
|
165
|
+
*
|
|
166
|
+
* @template TInstance - The shape of the service's state object.
|
|
167
|
+
*/
|
|
168
|
+
export interface ControllerDefinition<TInstance extends ServiceInstance = ServiceInstance> {
|
|
169
|
+
/** Path prefix prepended to every route in this controller (may contain params). */
|
|
170
|
+
prefix?: string;
|
|
171
|
+
/** Default OpenAPI tags applied to routes that do not declare their own. */
|
|
172
|
+
tags?: string[];
|
|
173
|
+
/** Guards run before every handler of this controller (see {@link Guard}). */
|
|
174
|
+
guards?: Guard[];
|
|
175
|
+
/**
|
|
176
|
+
* Default permission requirement for every route of this controller.
|
|
177
|
+
* Route-level `OperationMeta.permission` overrides it. When set, the
|
|
178
|
+
* pipeline runs `auth.check(ctx, required)` before the guards.
|
|
179
|
+
*/
|
|
180
|
+
permission?: string | string[];
|
|
181
|
+
/** Route handlers for `GET` requests (paths relative to `prefix`). */
|
|
182
|
+
GET?: RouteMap<TInstance>;
|
|
183
|
+
/** Route handlers for `POST` requests (paths relative to `prefix`). */
|
|
184
|
+
POST?: RouteMap<TInstance>;
|
|
185
|
+
/** Route handlers for `PUT` requests (paths relative to `prefix`). */
|
|
186
|
+
PUT?: RouteMap<TInstance>;
|
|
187
|
+
/** Route handlers for `DELETE` requests (paths relative to `prefix`). */
|
|
188
|
+
DELETE?: RouteMap<TInstance>;
|
|
189
|
+
/** Route handlers for `PATCH` requests (paths relative to `prefix`). */
|
|
190
|
+
PATCH?: RouteMap<TInstance>;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Identity helper for type inference and discoverability when declaring a
|
|
194
|
+
* {@link ControllerDefinition} in its own file.
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```ts
|
|
198
|
+
* export const wikiController = defineController({
|
|
199
|
+
* prefix: '/p/:proj/wiki',
|
|
200
|
+
* tags: ['Wiki'],
|
|
201
|
+
* permission: 'wiki.read',
|
|
202
|
+
* GET: { '/tree': (ctx) => listPages(ctx.params.proj) },
|
|
203
|
+
* });
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
export declare function defineController<TInstance extends ServiceInstance = ServiceInstance>(c: ControllerDefinition<TInstance>): ControllerDefinition<TInstance>;
|
|
207
|
+
/**
|
|
208
|
+
* Authentication / authorization binding connecting an auth layer (typically
|
|
209
|
+
* the JWT plugin) to the API Builder pipeline.
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```ts
|
|
213
|
+
* const jwt = createJwtPlugin({ accessTokenSecret: SECRET });
|
|
214
|
+
* const api = apiBuilder({
|
|
215
|
+
* auth: { authenticate: jwt.authenticate }, // default check() reads ctx.user.permissions
|
|
216
|
+
* controllers: [ ... ],
|
|
217
|
+
* });
|
|
218
|
+
* ```
|
|
219
|
+
*
|
|
220
|
+
* @template TUser - The shape of the authenticated user payload.
|
|
221
|
+
*/
|
|
222
|
+
export interface AuthBinding<TUser = unknown> {
|
|
223
|
+
/**
|
|
224
|
+
* Router middleware run before any guard or handler — typically
|
|
225
|
+
* `jwtPlugin.authenticate`. Registered by `apiBuilder` on its internal
|
|
226
|
+
* router, so the client no longer wires it per-mount.
|
|
227
|
+
*/
|
|
228
|
+
authenticate?: Middleware;
|
|
229
|
+
/**
|
|
230
|
+
* Enforce a permission requirement for the current request.
|
|
231
|
+
*
|
|
232
|
+
* Default implementation: require `ctx.user` (else `401`) and check that
|
|
233
|
+
* `ctx.user.permissions` contains **all** required entries (else `403`) —
|
|
234
|
+
* i.e. the exact semantics of `jwtPlugin.requirePermission`, but in the
|
|
235
|
+
* `ctx` world. Override for resource-scoped models (per-project roles,
|
|
236
|
+
* ownership, …); the override may load resources and share them through
|
|
237
|
+
* `ctx.state`.
|
|
238
|
+
*
|
|
239
|
+
* Failure is signalled by throwing / rejecting an {@link ApiError}.
|
|
240
|
+
*/
|
|
241
|
+
check?: (ctx: ApiContext<TUser>, required: string[]) => void | Promise<void>;
|
|
242
|
+
/**
|
|
243
|
+
* OpenAPI security scheme emitted into `components.securitySchemes.bearerAuth`
|
|
244
|
+
* when at least one route declares a `permission`.
|
|
245
|
+
*
|
|
246
|
+
* Default: `{ type: 'http', scheme: 'bearer', bearerFormat: 'JWT' }`.
|
|
247
|
+
*/
|
|
248
|
+
scheme?: Record<string, unknown>;
|
|
249
|
+
/**
|
|
250
|
+
* Name of the vendor extension listing the required permissions on each
|
|
251
|
+
* secured operation in the generated OpenAPI document.
|
|
252
|
+
*
|
|
253
|
+
* Default: `'x-required-permissions'`.
|
|
254
|
+
*/
|
|
255
|
+
permissionsExtension?: string;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Validation controls for {@link apiBuilder}.
|
|
259
|
+
*
|
|
260
|
+
* Used both as the factory's optional second argument and as the object form of
|
|
261
|
+
* the {@link ServiceDefinition.validate} field. When passed as the second
|
|
262
|
+
* argument it is authoritative and overrides `service.validate`:
|
|
263
|
+
*
|
|
264
|
+
* ```ts
|
|
265
|
+
* apiBuilder(service); // follows service.validate
|
|
266
|
+
* apiBuilder(service, {}); // validate requests (default), not responses
|
|
267
|
+
* apiBuilder(service, { validateRequests: false }); // validate nothing
|
|
268
|
+
* apiBuilder(service, { validateResponses: true }); // requests + responses (500 on mismatch)
|
|
269
|
+
* apiBuilder(service, { validateResponses: 'warn' }); // requests + responses (log only, no 500)
|
|
270
|
+
* ```
|
|
271
|
+
*/
|
|
272
|
+
export interface ApiBuilderOptions {
|
|
273
|
+
/**
|
|
274
|
+
* Validate incoming request bodies against each route's declared
|
|
275
|
+
* `OperationMeta.requestBody` schema. Failures produce `400` with
|
|
276
|
+
* `{ message, fieldErrors }`.
|
|
277
|
+
*
|
|
278
|
+
* @default true — pass `false` to cancel the incoming-data check.
|
|
279
|
+
*/
|
|
280
|
+
validateRequests?: boolean;
|
|
281
|
+
/**
|
|
282
|
+
* Validate each handler's return value against the route's declared
|
|
283
|
+
* `OperationMeta.responses['200']` schema before it is sent.
|
|
284
|
+
*
|
|
285
|
+
* - `true` — a mismatch is a server-contract breach: the off-spec body is
|
|
286
|
+
* **not** sent; instead a `500` with `{ message, fieldErrors }` is returned.
|
|
287
|
+
* - `'warn'` — a mismatch is logged server-side via `console.warn` and the
|
|
288
|
+
* response is sent unchanged (handy in development).
|
|
289
|
+
* - `false` — no response checking.
|
|
290
|
+
*
|
|
291
|
+
* Only truthy returns (sent as `200` JSON) are checked; falsy returns
|
|
292
|
+
* (`201 No Content`) and routes without a declared `200` response schema are
|
|
293
|
+
* skipped.
|
|
294
|
+
*
|
|
295
|
+
* @default false
|
|
296
|
+
*/
|
|
297
|
+
validateResponses?: boolean | 'warn';
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Extra methods attached to the router returned by {@link apiBuilder}.
|
|
301
|
+
*
|
|
302
|
+
* These allow the service's route definitions to be introspected and
|
|
303
|
+
* serialised as an OpenAPI 3.1.0 document.
|
|
304
|
+
*/
|
|
305
|
+
export interface ApiRouterExtensions {
|
|
306
|
+
/**
|
|
307
|
+
* Generate an OpenAPI 3.1.0 document from the service definition.
|
|
308
|
+
*
|
|
309
|
+
* @param opts - Top-level spec options (title, version, basePath, …).
|
|
310
|
+
* @returns A plain-object OpenAPI document ready to be serialised with
|
|
311
|
+
* `JSON.stringify`.
|
|
312
|
+
*/
|
|
313
|
+
spec(opts: SpecOptions): OpenApiDocument;
|
|
314
|
+
/**
|
|
315
|
+
* Return a request handler that serves the OpenAPI spec on `GET`.
|
|
316
|
+
*
|
|
317
|
+
* The spec is generated once and cached as a serialised string on the first
|
|
318
|
+
* call to the returned handler.
|
|
319
|
+
*
|
|
320
|
+
* ```ts
|
|
321
|
+
* // JSON (default)
|
|
322
|
+
* app.get('/openapi.json', itemsApi.specHandler({ title: 'Items API', version: '1.0.0' }));
|
|
323
|
+
*
|
|
324
|
+
* // YAML
|
|
325
|
+
* app.get('/openapi.yaml', itemsApi.specHandler({ title: 'Items API', version: '1.0.0' }, 'yaml'));
|
|
326
|
+
* ```
|
|
327
|
+
*
|
|
328
|
+
* @param opts - Top-level spec options (title, version, basePath, …).
|
|
329
|
+
* @param format - Output format: `'json'` (default) or `'yaml'`.
|
|
330
|
+
* @returns An Express-compatible middleware handler.
|
|
331
|
+
*/
|
|
332
|
+
specHandler(opts: SpecOptions, format?: SpecFormat): (req: RouterRequest, res: RouterResponse) => void;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* The return type of {@link apiBuilder}: a standard {@link Router} augmented
|
|
336
|
+
* with OpenAPI introspection helpers ({@link ApiRouterExtensions}).
|
|
337
|
+
*/
|
|
338
|
+
export type ApiRouter = Router & ApiRouterExtensions;
|
|
60
339
|
/**
|
|
61
340
|
* A service definition object — the single argument to {@link apiBuilder}.
|
|
62
341
|
*
|
|
@@ -90,7 +369,12 @@ export interface ServiceDefinition<TInstance extends ServiceInstance = ServiceIn
|
|
|
90
369
|
*/
|
|
91
370
|
scope?: (req: RouterRequest) => string | null;
|
|
92
371
|
/**
|
|
93
|
-
* Factory that returns the initial
|
|
372
|
+
* Factory that returns the **initial data** portion of a new instance.
|
|
373
|
+
*
|
|
374
|
+
* The return type is `Partial<TInstance>` because the methods declared in
|
|
375
|
+
* {@link ServiceDefinition.methods} are mixed in *after* `data()` is called,
|
|
376
|
+
* completing the instance shape. By the time any route handler or
|
|
377
|
+
* `setup()` runs the instance is fully initialised.
|
|
94
378
|
*
|
|
95
379
|
* When omitted, the instance is initialised as `{ $key: key }`.
|
|
96
380
|
*
|
|
@@ -98,14 +382,18 @@ export interface ServiceDefinition<TInstance extends ServiceInstance = ServiceIn
|
|
|
98
382
|
* global instances, `null` for ephemeral ones, or the string
|
|
99
383
|
* returned by `scope()`).
|
|
100
384
|
*/
|
|
101
|
-
data?: (key: string | null) => TInstance
|
|
385
|
+
data?: (key: string | null) => Partial<TInstance>;
|
|
102
386
|
/**
|
|
103
387
|
* Lifecycle hook called once after an instance is created and its methods
|
|
104
388
|
* are mixed in.
|
|
105
389
|
*
|
|
106
|
-
* May be synchronous or asynchronous
|
|
107
|
-
* `Promise`
|
|
108
|
-
*
|
|
390
|
+
* May be synchronous or **asynchronous**. When asynchronous, the framework
|
|
391
|
+
* now awaits the returned `Promise` before marking the instance as ready:
|
|
392
|
+
* - For **singleton** services, route handlers are only registered (and
|
|
393
|
+
* requests served) once setup resolves. Requests that arrive while setup
|
|
394
|
+
* is in progress receive **503 Service not ready**.
|
|
395
|
+
* - For **keyed / ephemeral** services, the route handler awaits instance
|
|
396
|
+
* creation (including setup) per request before invoking the method.
|
|
109
397
|
*/
|
|
110
398
|
setup?: (this: TInstance) => void | Promise<void>;
|
|
111
399
|
/**
|
|
@@ -116,6 +404,65 @@ export interface ServiceDefinition<TInstance extends ServiceInstance = ServiceIn
|
|
|
116
404
|
* objects to trigger HTTP error responses.
|
|
117
405
|
*/
|
|
118
406
|
methods?: ServiceMethods<TInstance>;
|
|
407
|
+
/**
|
|
408
|
+
* Sub-controllers merged into this API.
|
|
409
|
+
*
|
|
410
|
+
* Each controller's routes are rewritten to `joinPath(prefix, path)`, then
|
|
411
|
+
* all routes of all controllers (plus the root-level route maps below) are
|
|
412
|
+
* concatenated and sorted by specificity **globally**. A duplicate
|
|
413
|
+
* `(verb, joined path)` pair across controllers **throws at build time**.
|
|
414
|
+
*
|
|
415
|
+
* All controllers share the single service instance lifecycle declared at
|
|
416
|
+
* this level — controllers organise routes, they do not isolate state.
|
|
417
|
+
*/
|
|
418
|
+
controllers?: ControllerDefinition<TInstance>[];
|
|
419
|
+
/** Guards run before every handler of the whole API (see {@link Guard}). */
|
|
420
|
+
guards?: Guard[];
|
|
421
|
+
/** Authentication / authorization binding (see {@link AuthBinding}). */
|
|
422
|
+
auth?: AuthBinding;
|
|
423
|
+
/**
|
|
424
|
+
* Enable runtime validation of declared schemas.
|
|
425
|
+
*
|
|
426
|
+
* - `true` — validate request bodies against each route's
|
|
427
|
+
* `OperationMeta.requestBody` schema (`400` with `{ message, fieldErrors }`
|
|
428
|
+
* on failure).
|
|
429
|
+
* - An {@link ApiBuilderOptions} object — fine-grained control over request
|
|
430
|
+
* and response validation.
|
|
431
|
+
*
|
|
432
|
+
* Overridden when an {@link ApiBuilderOptions} object is passed as the second
|
|
433
|
+
* argument to {@link apiBuilder}.
|
|
434
|
+
*/
|
|
435
|
+
validate?: boolean | ApiBuilderOptions;
|
|
436
|
+
/**
|
|
437
|
+
* Reusable JSON Schema components, shared by request validation and spec
|
|
438
|
+
* generation. `$ref: '#/components/schemas/Name'` references in operation
|
|
439
|
+
* metadata are resolved against this map by the validator, and the map is
|
|
440
|
+
* merged into `components.schemas` of the generated OpenAPI document
|
|
441
|
+
* (taking precedence over `SpecOptions.schemas`).
|
|
442
|
+
*/
|
|
443
|
+
schemas?: Record<string, JsonSchema>;
|
|
444
|
+
/**
|
|
445
|
+
* Hook invoked whenever a handler, guard, auth check, or validation step
|
|
446
|
+
* throws or rejects — before the default {@link ApiError} → HTTP translation.
|
|
447
|
+
*
|
|
448
|
+
* Use it to log the failure and/or shape a better response:
|
|
449
|
+
* - **Return nothing** (`undefined`) → the error is left untouched and the
|
|
450
|
+
* built-in translation runs (`{ status, message | data }`, else `500`).
|
|
451
|
+
* Ideal for log-only use.
|
|
452
|
+
* - **Return an {@link ApiError}** → that value is sent instead of the
|
|
453
|
+
* original (e.g. to hide internals behind a generic message, or attach a
|
|
454
|
+
* correlation id).
|
|
455
|
+
* - **Throw** → the thrown value is escalated to the surrounding app's error
|
|
456
|
+
* channel (`router.error()` / `onError`) instead of being answered here,
|
|
457
|
+
* letting a process-wide handler take over.
|
|
458
|
+
*
|
|
459
|
+
* @param err - The caught value (thrown or rejected).
|
|
460
|
+
* @param ctx - The {@link ApiContext} for the failing request.
|
|
461
|
+
* @param req - The underlying request.
|
|
462
|
+
* @returns An {@link ApiError} to override the response, or nothing to keep
|
|
463
|
+
* the default translation.
|
|
464
|
+
*/
|
|
465
|
+
onError?(err: unknown, ctx: ApiContext<any>, req: RouterRequest): void | ApiError;
|
|
119
466
|
/** Route handlers for `GET` requests. */
|
|
120
467
|
GET?: RouteMap<TInstance>;
|
|
121
468
|
/** Route handlers for `POST` requests. */
|
|
@@ -127,6 +474,112 @@ export interface ServiceDefinition<TInstance extends ServiceInstance = ServiceIn
|
|
|
127
474
|
/** Route handlers for `PATCH` requests. */
|
|
128
475
|
PATCH?: RouteMap<TInstance>;
|
|
129
476
|
}
|
|
477
|
+
/** The five HTTP verbs supported by `apiBuilder`. */
|
|
478
|
+
declare const VERBS: readonly ["GET", "POST", "PUT", "DELETE", "PATCH"];
|
|
479
|
+
/** One of the five HTTP verbs supported by `apiBuilder`. */
|
|
480
|
+
export type ApiVerb = typeof VERBS[number];
|
|
481
|
+
/**
|
|
482
|
+
* One merged route entry produced by {@link collectRoutes}.
|
|
483
|
+
*
|
|
484
|
+
* Records per-route provenance — effective tags, composed guard chain, and
|
|
485
|
+
* permission requirement — consumed by both the request pipeline
|
|
486
|
+
* (`apiBuilder`) and the spec generator (`openApiSpec`).
|
|
487
|
+
*
|
|
488
|
+
* @template TInstance - The shape of the service's state object.
|
|
489
|
+
*/
|
|
490
|
+
export interface CollectedRoute<TInstance extends ServiceInstance = ServiceInstance> {
|
|
491
|
+
/** HTTP verb of the route. */
|
|
492
|
+
verb: ApiVerb;
|
|
493
|
+
/** Full path after joining the controller prefix (Express-style pattern). */
|
|
494
|
+
path: string;
|
|
495
|
+
/** The route handler (possibly `describe()`-wrapped). */
|
|
496
|
+
handler: ServiceMethod<TInstance>;
|
|
497
|
+
/** Operation metadata attached via `describe()`, when present. */
|
|
498
|
+
meta?: OperationMeta;
|
|
499
|
+
/** Effective tags: route-level `meta.tags`, else the controller's `tags`. */
|
|
500
|
+
tags?: string[];
|
|
501
|
+
/** Composed guard chain: API guards, then controller guards, then route guards. */
|
|
502
|
+
guards: Guard[];
|
|
503
|
+
/** Normalised permission requirement (route-level overrides controller-level). */
|
|
504
|
+
permission?: string[];
|
|
505
|
+
/** Human-readable controller identifier used in diagnostics. */
|
|
506
|
+
controller: string;
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Join a controller prefix and a route path into a single normalised pattern.
|
|
510
|
+
*
|
|
511
|
+
* Duplicate slashes are collapsed and a trailing slash is stripped (except
|
|
512
|
+
* for the root path), so `joinPath('/p/:proj/wiki', '/')` → `'/p/:proj/wiki'`.
|
|
513
|
+
*
|
|
514
|
+
* Exported for use by `openapi.ts` (multi-definition spec merging); not part
|
|
515
|
+
* of the public package API.
|
|
516
|
+
*
|
|
517
|
+
* @param prefix - The controller prefix (may be empty).
|
|
518
|
+
* @param path - The route path relative to the prefix.
|
|
519
|
+
*/
|
|
520
|
+
export declare function joinPath(prefix: string, path: string): string;
|
|
521
|
+
/**
|
|
522
|
+
* Compute the specificity score of a route pattern.
|
|
523
|
+
*
|
|
524
|
+
* `score = (segment count × 100) − (parameter count × 10)`. Higher scores
|
|
525
|
+
* are registered first so that more precise patterns (more segments, fewer
|
|
526
|
+
* parameters) cannot be shadowed by prefix matches.
|
|
527
|
+
*
|
|
528
|
+
* Exported for use by `openapi.ts` (multi-definition spec merging); not part
|
|
529
|
+
* of the public package API.
|
|
530
|
+
*/
|
|
531
|
+
export declare function routeScore(path: string): number;
|
|
532
|
+
/**
|
|
533
|
+
* Normalise a `permission` declaration (`string | string[]`) to an array,
|
|
534
|
+
* or `undefined` when absent.
|
|
535
|
+
*
|
|
536
|
+
* Exported for use by `openapi.ts` (multi-definition spec merging); not part
|
|
537
|
+
* of the public package API.
|
|
538
|
+
*/
|
|
539
|
+
export declare function normalizePermission(permission: string | string[] | undefined): string[] | undefined;
|
|
540
|
+
/**
|
|
541
|
+
* Build the merged route table for a service definition.
|
|
542
|
+
*
|
|
543
|
+
* The algorithm (see `docs/api-builder-v2-design.md` §4):
|
|
544
|
+
* 1. Normalises the root-level route maps into an anonymous controller
|
|
545
|
+
* (`prefix: ''`) so v1 single-definition services keep working.
|
|
546
|
+
* 2. Rewrites each controller route to `joinPath(prefix, path)`.
|
|
547
|
+
* 3. Concatenates all routes of all controllers, then sorts them by
|
|
548
|
+
* decreasing specificity **globally** (the score is computed on the
|
|
549
|
+
* joined path, so prefix parameters are accounted for).
|
|
550
|
+
* 4. **Throws** on a duplicate `(verb, joined path)` pair, naming both
|
|
551
|
+
* declaring controllers.
|
|
552
|
+
* 5. Records per-route provenance (tags, guards, permission) consumed by
|
|
553
|
+
* both the request pipeline and `openApiSpec()`.
|
|
554
|
+
*
|
|
555
|
+
* Exported for use by `openapi.ts`; not part of the public package API.
|
|
556
|
+
*
|
|
557
|
+
* @param service - The service definition to collect routes from.
|
|
558
|
+
* @returns The merged, globally sorted route table.
|
|
559
|
+
* @throws Error on duplicate `(verb, path)` declarations.
|
|
560
|
+
*/
|
|
561
|
+
export declare function collectRoutes<TInstance extends ServiceInstance = ServiceInstance>(service: ServiceDefinition<TInstance>): CollectedRoute<TInstance>[];
|
|
562
|
+
/**
|
|
563
|
+
* Validate a value against a JSON Schema subset, collecting field errors.
|
|
564
|
+
*
|
|
565
|
+
* Supported keywords: `type`, `required`, `properties`, `items`, `enum`,
|
|
566
|
+
* `pattern`, `minLength` / `maxLength`, `minimum` / `maximum`,
|
|
567
|
+
* `additionalProperties`, `allOf` / `anyOf` / `oneOf`, and `$ref` (resolved
|
|
568
|
+
* against `components`, i.e. `ServiceDefinition.schemas`).
|
|
569
|
+
*
|
|
570
|
+
* Field-error paths are dotted (`name`, `address.city`, `tags.0`); errors on
|
|
571
|
+
* the value itself are keyed `'$'`.
|
|
572
|
+
*
|
|
573
|
+
* Exported for testing; not part of the public package API.
|
|
574
|
+
*
|
|
575
|
+
* @param value - The value to validate.
|
|
576
|
+
* @param schema - The schema to validate against.
|
|
577
|
+
* @param components - Reusable schemas for `$ref` resolution.
|
|
578
|
+
* @param path - Current field path (used in recursion; omit at the root).
|
|
579
|
+
* @param errors - Accumulator (used in recursion; omit at the root).
|
|
580
|
+
* @returns A map of field path → first error message (empty when valid).
|
|
581
|
+
*/
|
|
582
|
+
export declare function validateSchema(value: unknown, schema: JsonSchema, components?: Record<string, JsonSchema>, path?: string, errors?: Record<string, string>): Record<string, string>;
|
|
130
583
|
/**
|
|
131
584
|
* Build an Express-compatible router from a service definition object.
|
|
132
585
|
*
|
|
@@ -138,11 +591,25 @@ export interface ServiceDefinition<TInstance extends ServiceInstance = ServiceIn
|
|
|
138
591
|
* app.use('/api', apiBuilder(myService));
|
|
139
592
|
* ```
|
|
140
593
|
*
|
|
594
|
+
* **Singleton setup lifecycle:**
|
|
595
|
+
* When `service.scope` is absent the service is a singleton. The framework
|
|
596
|
+
* pre-builds the instance eagerly and registers a **503 Service not ready**
|
|
597
|
+
* guard middleware on the router immediately. Route handlers are registered
|
|
598
|
+
* only once `setup()` resolves (or immediately, for sync setup). Any request
|
|
599
|
+
* that arrives before setup completes receives a 503 response.
|
|
600
|
+
*
|
|
601
|
+
* **Keyed / ephemeral setup lifecycle:**
|
|
602
|
+
* Route handlers are registered immediately. For each request,
|
|
603
|
+
* `resolveInstance()` is awaited inside the handler, so `setup()` is always
|
|
604
|
+
* complete before the service method is invoked.
|
|
605
|
+
*
|
|
141
606
|
* **Route handlers** declared in `service.GET`, `service.POST`, etc. are
|
|
142
607
|
* called with `this` bound to the service instance. They receive two
|
|
143
608
|
* arguments:
|
|
144
|
-
* 1. `
|
|
145
|
-
*
|
|
609
|
+
* 1. `ctx` — an {@link ApiContext} object containing `ctx.query.route`
|
|
610
|
+
* (named route parameters), `ctx.query.url` (URL query-string parameters),
|
|
611
|
+
* `ctx.path` (the request path), and `ctx.user` (optional auth data).
|
|
612
|
+
* 2. `body` — the parsed request body from `req.body` (requires a
|
|
146
613
|
* body-parsing middleware such as `json()` to run first).
|
|
147
614
|
*
|
|
148
615
|
* **Return values:**
|
|
@@ -152,15 +619,25 @@ export interface ServiceDefinition<TInstance extends ServiceInstance = ServiceIn
|
|
|
152
619
|
* `Promise` resolving to one → `201 No Content` (useful for mutations).
|
|
153
620
|
*
|
|
154
621
|
* **Error handling:**
|
|
155
|
-
* - Throwing or rejecting with `{
|
|
622
|
+
* - Throwing or rejecting with `{ status, message }` sends the
|
|
156
623
|
* corresponding HTTP error.
|
|
157
|
-
* - Throwing or rejecting with `{
|
|
624
|
+
* - Throwing or rejecting with `{ status, data }` sends the `data` object
|
|
158
625
|
* as a JSON body.
|
|
159
626
|
* - Any other thrown value produces `500 Internal Server Error`.
|
|
160
627
|
*
|
|
628
|
+
* **Validation:**
|
|
629
|
+
* - With no `options`, validation follows the {@link ServiceDefinition.validate}
|
|
630
|
+
* field.
|
|
631
|
+
* - With `options`, request validation defaults **on** (cancel via
|
|
632
|
+
* `{ validateRequests: false }`) and response validation can be enabled with
|
|
633
|
+
* `{ validateResponses: true }` (500 on mismatch) or `{ validateResponses:
|
|
634
|
+
* 'warn' }` (log only). See {@link ApiBuilderOptions}.
|
|
635
|
+
*
|
|
161
636
|
* @param service - The service definition (see {@link ServiceDefinition}).
|
|
637
|
+
* @param options - Optional validation controls (see {@link ApiBuilderOptions}).
|
|
638
|
+
* When provided, it overrides the legacy `service.validate` field.
|
|
162
639
|
* @returns A router instance pre-configured with all declared routes.
|
|
163
640
|
*/
|
|
164
|
-
export declare function apiBuilder<TInstance extends ServiceInstance = ServiceInstance>(service: ServiceDefinition<TInstance
|
|
641
|
+
export declare function apiBuilder<TInstance extends ServiceInstance = ServiceInstance>(service: ServiceDefinition<TInstance>, options?: ApiBuilderOptions): ApiRouter;
|
|
165
642
|
export default apiBuilder;
|
|
166
643
|
//# sourceMappingURL=apis.d.ts.map
|
package/dist/apis.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apis.d.ts","sourceRoot":"","sources":["../src/apis.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"apis.d.ts","sourceRoot":"","sources":["../src/apis.ts"],"names":[],"mappings":"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"}
|