@daloyjs/core 1.0.0-beta.5 → 1.0.0-beta.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 +2 -1
- package/dist/adapters/bun.d.ts +13 -1
- package/dist/adapters/bun.js +8 -1
- package/dist/adapters/cloudflare.d.ts +7 -1
- package/dist/adapters/cloudflare.js +6 -1
- package/dist/adapters/deno.d.ts +11 -1
- package/dist/adapters/deno.js +8 -1
- package/dist/adapters/fastly.d.ts +12 -2
- package/dist/adapters/fastly.js +12 -2
- package/dist/adapters/lambda.d.ts +37 -1
- package/dist/adapters/lambda.js +6 -1
- package/dist/adapters/node.d.ts +12 -1
- package/dist/adapters/node.js +7 -1
- package/dist/adapters/vercel.d.ts +13 -1
- package/dist/adapters/vercel.js +12 -1
- package/dist/app.d.ts +67 -17
- package/dist/app.js +97 -31
- package/dist/banner.d.ts +6 -0
- package/dist/banner.js +6 -0
- package/dist/cli.d.ts +35 -0
- package/dist/cli.js +23 -1
- package/dist/combine.d.ts +8 -0
- package/dist/combine.js +8 -0
- package/dist/compression.d.ts +3 -0
- package/dist/compression.js +3 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.js +4 -0
- package/dist/conn-info.d.ts +35 -2
- package/dist/conn-info.js +35 -2
- package/dist/contract.d.ts +2 -0
- package/dist/contract.js +2 -0
- package/dist/cookie.d.ts +12 -0
- package/dist/cookie.js +12 -0
- package/dist/dependency.d.ts +4 -0
- package/dist/dependency.js +3 -0
- package/dist/discriminator.d.ts +13 -0
- package/dist/discriminator.js +23 -1
- package/dist/docs.d.ts +78 -0
- package/dist/docs.js +21 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.js +14 -0
- package/dist/etag.d.ts +2 -0
- package/dist/etag.js +2 -0
- package/dist/fetch-guard.d.ts +7 -0
- package/dist/fetch-guard.js +7 -0
- package/dist/fetch-resilience.d.ts +4 -0
- package/dist/fetch-resilience.js +4 -0
- package/dist/http-signatures.d.ts +32 -0
- package/dist/http-signatures.js +30 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/ip-restriction.d.ts +40 -3
- package/dist/ip-restriction.js +35 -3
- package/dist/jwk.d.ts +12 -1
- package/dist/jwk.js +6 -0
- package/dist/jwt.d.ts +14 -0
- package/dist/jwt.js +10 -0
- package/dist/load-shedding.d.ts +3 -0
- package/dist/load-shedding.js +3 -0
- package/dist/logger.d.ts +13 -0
- package/dist/logger.js +3 -0
- package/dist/mcp.d.ts +574 -0
- package/dist/mcp.js +623 -0
- package/dist/middleware.d.ts +68 -0
- package/dist/middleware.js +17 -0
- package/dist/mtls.d.ts +19 -2
- package/dist/mtls.js +12 -2
- package/dist/multipart.d.ts +42 -5
- package/dist/multipart.js +41 -5
- package/dist/openapi.d.ts +15 -9
- package/dist/openapi.js +6 -9
- package/dist/rate-limit-redis.d.ts +21 -2
- package/dist/rate-limit-redis.js +17 -2
- package/dist/safe-redirect.d.ts +6 -0
- package/dist/safe-redirect.js +6 -0
- package/dist/sbom.cdx.json +9 -9
- package/dist/sbom.spdx.json +5 -5
- package/dist/scheduler.d.ts +4 -0
- package/dist/schema.d.ts +25 -0
- package/dist/security-schemes.d.ts +50 -0
- package/dist/security-schemes.js +6 -0
- package/dist/security.d.ts +33 -0
- package/dist/security.js +28 -10
- package/dist/session.d.ts +34 -5
- package/dist/session.js +31 -5
- package/dist/streaming.d.ts +19 -0
- package/dist/streaming.js +16 -0
- package/dist/subdomains.d.ts +4 -0
- package/dist/subdomains.js +4 -0
- package/dist/time-claims.d.ts +22 -2
- package/dist/time-claims.js +6 -0
- package/dist/tracing.d.ts +12 -0
- package/dist/tracing.js +6 -0
- package/dist/types.d.ts +70 -1
- package/dist/waf.js +21 -1
- package/dist/webhook-delivery.d.ts +6 -0
- package/dist/webhook-delivery.js +5 -0
- package/dist/websocket.d.ts +137 -4
- package/dist/websocket.js +105 -4
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -509,7 +509,7 @@ The core only ever sees `Request → Response`. Adapters live at the edge.
|
|
|
509
509
|
|
|
510
510
|
## Status
|
|
511
511
|
|
|
512
|
-
DaloyJS is now in the **`1.0.0` beta** (`1.0.0-beta.
|
|
512
|
+
DaloyJS is now in the **`1.0.0` beta** (`1.0.0-beta.7`). The public API is feature-complete and stable for the 1.0 line; from `1.0.0` onward, breaking changes follow SemVer and deprecations get at least one minor cycle. Small adjustments are still possible before the `1.0.0` GA if beta feedback surfaces something. The framework is already in use for production trials.
|
|
513
513
|
|
|
514
514
|
**Release quality bar.** Every release ships with **≥90% line + function coverage and ≥90% branch coverage**, strict TypeScript, OpenSSF Scorecard, CodeQL + Opengrep dual SAST, zizmor workflow linting, and npm provenance. Coverage was relaxed from a former 100% gate so complex security work isn't blocked chasing throwaway tests for unreachable defensive branches or tsx source-map phantoms; see [AGENTS.md](AGENTS.md) for the policy.
|
|
515
515
|
|
|
@@ -520,6 +520,7 @@ DaloyJS is now in the **`1.0.0` beta** (`1.0.0-beta.5`). The public API is featu
|
|
|
520
520
|
- Zero-config OpenAPI `info` autofill from `package.json` (Node / Bun) or `deno.json` / `deno.jsonc` (Deno); explicit `openapi.info` values always win.
|
|
521
521
|
- RFC 7231 + RFC 5789 HTTP-method allowlist enforced inside `app.route()` (WebDAV, `TRACE`, `CONNECT` rejected at the framework boundary).
|
|
522
522
|
- AI-friendly route metadata via optional `meta: { examples, extensions, summary, description, tags }`; examples are validated against your schemas at build time, surfaced as OpenAPI `examples` + `x-daloy-*` extensions, and dumped as `routes.json` / `routes.yaml` via `daloy inspect --ai`.
|
|
523
|
+
- Dependency-free MCP Streamable HTTP server helpers at `@daloyjs/core/mcp`: `createMcpHandler()` exposes tools (with `outputSchema`, `annotations`, and icons), resources, RFC 6570 resource templates, and prompts (with required-argument enforcement) over JSON-RPC 2.0 and validates `Origin` against DNS rebinding (with an `allowedOrigins` allowlist), while `mcpRoutes("/mcp", handler)` mounts the POST / GET / OPTIONS Daloy routes — with the JSON-RPC envelope schema surfaced in OpenAPI — for a dedicated MCP service with the same auth, rate-limit, body-limit, and timeout middleware as any other app.
|
|
523
524
|
- API lifecycle and breaking-change detection: mark routes `deprecated` or give them a `sunset` date to emit RFC 8594 `Deprecation` / `Sunset` headers and an `x-sunset` OpenAPI extension, then gate CI with `diffOpenAPI()` / the `daloy diff` command, which fail on a breaking change versus the last published spec.
|
|
524
525
|
- In-process test client (`app.request()`), contract-test runner (gated in CI via `daloy inspect --check` and shipped as a default test in every `create-daloy` template), in-process typed client, and Hey API codegen via `pnpm gen`.
|
|
525
526
|
|
package/dist/adapters/bun.d.ts
CHANGED
|
@@ -18,7 +18,9 @@ export interface BunTLSOptions {
|
|
|
18
18
|
}
|
|
19
19
|
/** Options forwarded to `Bun.serve` by {@link serve}. */
|
|
20
20
|
export interface BunServeOptions {
|
|
21
|
+
/** TCP port to listen on. Ignored when `unix` is set. Defaults to `3000`. */
|
|
21
22
|
port?: number;
|
|
23
|
+
/** Interface to bind. Ignored when `unix` is set. Defaults to `"0.0.0.0"`. */
|
|
22
24
|
hostname?: string;
|
|
23
25
|
/** Maximum request body bytes (Bun-level cap). Default: 16 MiB. */
|
|
24
26
|
maxRequestBodySize?: number;
|
|
@@ -33,9 +35,19 @@ export interface BunServeOptions {
|
|
|
33
35
|
}
|
|
34
36
|
/** Handle returned by {@link serve} for shutdown and listener introspection. */
|
|
35
37
|
export interface BunServerHandle {
|
|
38
|
+
/** Port the server is actually listening on (as reported by Bun). */
|
|
36
39
|
port: number;
|
|
40
|
+
/** Server URL as reported by `Bun.serve` (e.g. for startup logging), if available. */
|
|
37
41
|
url: URL | undefined;
|
|
42
|
+
/** Graceful stop: drains {@link App.shutdown} hooks first, then force-stops the Bun server. */
|
|
38
43
|
stop: () => Promise<void>;
|
|
39
44
|
}
|
|
40
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* Start `Bun.serve` bound to the given {@link App}, wiring HTTP and WebSocket routes.
|
|
47
|
+
*
|
|
48
|
+
* @param app - The DaloyJS {@link App} whose `fetch` (and WebSocket routes) serve requests.
|
|
49
|
+
* @param opts - Listener options forwarded to `Bun.serve`; see {@link BunServeOptions}.
|
|
50
|
+
* @returns A {@link BunServerHandle} exposing the bound `port`, `url`, and a graceful `stop()`.
|
|
51
|
+
* @throws Error when the Bun runtime (`globalThis.Bun.serve`) is not detected.
|
|
52
|
+
*/
|
|
41
53
|
export declare function serve(app: App, opts?: BunServeOptions): BunServerHandle;
|
package/dist/adapters/bun.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { WS_READY_STATE, WS_CLOSE_CODE, WS_MAX_CONTROL_PAYLOAD, encodeSendPayload, parseSubprotocols, validateSelectedSubprotocol, checkWebSocketOrigin, WebSocketProtocolError, } from "../websocket.js";
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Start `Bun.serve` bound to the given {@link App}, wiring HTTP and WebSocket routes.
|
|
4
|
+
*
|
|
5
|
+
* @param app - The DaloyJS {@link App} whose `fetch` (and WebSocket routes) serve requests.
|
|
6
|
+
* @param opts - Listener options forwarded to `Bun.serve`; see {@link BunServeOptions}.
|
|
7
|
+
* @returns A {@link BunServerHandle} exposing the bound `port`, `url`, and a graceful `stop()`.
|
|
8
|
+
* @throws Error when the Bun runtime (`globalThis.Bun.serve`) is not detected.
|
|
9
|
+
*/
|
|
3
10
|
export function serve(app, opts = {}) {
|
|
4
11
|
const Bun = globalThis.Bun;
|
|
5
12
|
if (!Bun?.serve)
|
|
@@ -18,12 +18,18 @@
|
|
|
18
18
|
import type { App } from "../app.js";
|
|
19
19
|
/** Module shape expected by the Cloudflare Workers runtime as `export default`. */
|
|
20
20
|
export interface ExportedFetchHandler<Env = unknown> {
|
|
21
|
+
/** Worker entry point: forwards the request to {@link App.fetch}. `env`/`ctx` are accepted but unused by the adapter. */
|
|
21
22
|
fetch: (request: Request, env?: Env, ctx?: ExecutionContextLike) => Promise<Response>;
|
|
22
23
|
}
|
|
23
24
|
interface ExecutionContextLike {
|
|
24
25
|
waitUntil?: (promise: Promise<unknown>) => void;
|
|
25
26
|
passThroughOnException?: () => void;
|
|
26
27
|
}
|
|
27
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* Wrap an {@link App} in the `{ fetch }` object expected by Cloudflare Workers and other web-standard hosts.
|
|
30
|
+
*
|
|
31
|
+
* @param app - The DaloyJS {@link App} that serves each incoming request.
|
|
32
|
+
* @returns An {@link ExportedFetchHandler} suitable as the module's `export default`.
|
|
33
|
+
*/
|
|
28
34
|
export declare function toFetchHandler<Env = unknown>(app: App): ExportedFetchHandler<Env>;
|
|
29
35
|
export {};
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Wrap an {@link App} in the `{ fetch }` object expected by Cloudflare Workers and other web-standard hosts.
|
|
3
|
+
*
|
|
4
|
+
* @param app - The DaloyJS {@link App} that serves each incoming request.
|
|
5
|
+
* @returns An {@link ExportedFetchHandler} suitable as the module's `export default`.
|
|
6
|
+
*/
|
|
2
7
|
export function toFetchHandler(app) {
|
|
3
8
|
return {
|
|
4
9
|
fetch: (req) => app.fetch(req),
|
package/dist/adapters/deno.d.ts
CHANGED
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
import type { App } from "../app.js";
|
|
10
10
|
/** Options forwarded to `Deno.serve` by {@link serve}. */
|
|
11
11
|
export interface DenoServeOptions {
|
|
12
|
+
/** TCP port to listen on. Defaults to `3000`. */
|
|
12
13
|
port?: number;
|
|
14
|
+
/** Interface to bind. Defaults to `"0.0.0.0"`. */
|
|
13
15
|
hostname?: string;
|
|
14
16
|
/** Optional external signal that triggers graceful shutdown. */
|
|
15
17
|
signal?: AbortSignal;
|
|
@@ -31,7 +33,15 @@ export interface DenoServeOptions {
|
|
|
31
33
|
}
|
|
32
34
|
/** Handle returned by {@link serve}; call `shutdown()` to drain. */
|
|
33
35
|
export interface DenoServerHandle {
|
|
36
|
+
/** Graceful shutdown: drains {@link App.shutdown} hooks, then stops the Deno server. Idempotent. */
|
|
34
37
|
shutdown: () => Promise<void>;
|
|
35
38
|
}
|
|
36
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* Start `Deno.serve` bound to the given {@link App} with graceful-shutdown wiring.
|
|
41
|
+
*
|
|
42
|
+
* @param app - The DaloyJS {@link App} whose `fetch` serves each request.
|
|
43
|
+
* @param opts - Listener/TLS/shutdown options; see {@link DenoServeOptions}.
|
|
44
|
+
* @returns A {@link DenoServerHandle} whose `shutdown()` drains in-flight requests.
|
|
45
|
+
* @throws Error when the Deno runtime (`globalThis.Deno.serve`) is not detected.
|
|
46
|
+
*/
|
|
37
47
|
export declare function serve(app: App, opts?: DenoServeOptions): DenoServerHandle;
|
package/dist/adapters/deno.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Start `Deno.serve` bound to the given {@link App} with graceful-shutdown wiring.
|
|
3
|
+
*
|
|
4
|
+
* @param app - The DaloyJS {@link App} whose `fetch` serves each request.
|
|
5
|
+
* @param opts - Listener/TLS/shutdown options; see {@link DenoServeOptions}.
|
|
6
|
+
* @returns A {@link DenoServerHandle} whose `shutdown()` drains in-flight requests.
|
|
7
|
+
* @throws Error when the Deno runtime (`globalThis.Deno.serve`) is not detected.
|
|
8
|
+
*/
|
|
2
9
|
export function serve(app, opts = {}) {
|
|
3
10
|
const D = globalThis.Deno;
|
|
4
11
|
const denoServe = D?.serve;
|
|
@@ -18,7 +18,17 @@
|
|
|
18
18
|
* multipart helpers that rely on `node:stream`).
|
|
19
19
|
*/
|
|
20
20
|
import type { App } from "../app.js";
|
|
21
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* Wrap an {@link App} in a `(req) => Promise<Response>` function suitable for Fastly Compute.
|
|
23
|
+
*
|
|
24
|
+
* @param app - The DaloyJS {@link App} that serves each incoming request.
|
|
25
|
+
* @returns A web-standard handler delegating to {@link App.fetch}.
|
|
26
|
+
*/
|
|
22
27
|
export declare function toFastlyHandler(app: App): (req: Request) => Promise<Response>;
|
|
23
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* Register a Fastly Compute `fetch` event listener that delegates to the given {@link App}.
|
|
30
|
+
*
|
|
31
|
+
* @param app - The DaloyJS {@link App} that serves each incoming request.
|
|
32
|
+
* @throws Error when `globalThis.addEventListener` is missing (not a Fastly Compute runtime).
|
|
33
|
+
*/
|
|
24
34
|
export declare function installFastlyListener(app: App): void;
|
package/dist/adapters/fastly.js
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Wrap an {@link App} in a `(req) => Promise<Response>` function suitable for Fastly Compute.
|
|
3
|
+
*
|
|
4
|
+
* @param app - The DaloyJS {@link App} that serves each incoming request.
|
|
5
|
+
* @returns A web-standard handler delegating to {@link App.fetch}.
|
|
6
|
+
*/
|
|
2
7
|
export function toFastlyHandler(app) {
|
|
3
8
|
return (req) => app.fetch(req);
|
|
4
9
|
}
|
|
5
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Register a Fastly Compute `fetch` event listener that delegates to the given {@link App}.
|
|
12
|
+
*
|
|
13
|
+
* @param app - The DaloyJS {@link App} that serves each incoming request.
|
|
14
|
+
* @throws Error when `globalThis.addEventListener` is missing (not a Fastly Compute runtime).
|
|
15
|
+
*/
|
|
6
16
|
export function installFastlyListener(app) {
|
|
7
17
|
const g = globalThis;
|
|
8
18
|
if (typeof g.addEventListener !== "function") {
|
|
@@ -13,28 +13,45 @@ import type { App } from "../app.js";
|
|
|
13
13
|
* The adapter performs no Node-only I/O, so it is safe in any runtime that
|
|
14
14
|
* provides the standard `Request`/`Response`/`atob`/`btoa` globals.
|
|
15
15
|
*/
|
|
16
|
+
/** API Gateway REST API event (payload format v1.0). */
|
|
16
17
|
export interface LambdaEventV1 {
|
|
18
|
+
/** Payload format version; `"1.0"` or absent for REST API events. */
|
|
17
19
|
version?: "1.0" | string;
|
|
20
|
+
/** URL path of the request (e.g. `/users/42`). */
|
|
18
21
|
path?: string;
|
|
22
|
+
/** HTTP method (e.g. `GET`). */
|
|
19
23
|
httpMethod?: string;
|
|
24
|
+
/** Request headers, one value per name (last value wins in v1.0). */
|
|
20
25
|
headers?: Record<string, string | undefined>;
|
|
26
|
+
/** Request headers with every value per name; `cookie` values are re-joined with `; `. */
|
|
21
27
|
multiValueHeaders?: Record<string, string[] | undefined>;
|
|
28
|
+
/** Query parameters, one value per name. Used only when the multi-value map is empty. */
|
|
22
29
|
queryStringParameters?: Record<string, string | undefined> | null;
|
|
30
|
+
/** Query parameters with every value per name; preferred over the single-value map. */
|
|
23
31
|
multiValueQueryStringParameters?: Record<string, string[] | undefined> | null;
|
|
32
|
+
/** Request context; `domainName` is the host fallback and `path` the path fallback. */
|
|
24
33
|
requestContext?: {
|
|
25
34
|
domainName?: string;
|
|
26
35
|
path?: string;
|
|
27
36
|
};
|
|
37
|
+
/** Raw request body; base64-encoded when {@link LambdaEventV1.isBase64Encoded} is true. */
|
|
28
38
|
body?: string;
|
|
39
|
+
/** True when `body` is base64-encoded (binary payloads). */
|
|
29
40
|
isBase64Encoded?: boolean;
|
|
30
41
|
}
|
|
31
42
|
/** API Gateway HTTP API or Lambda Function URL event (payload format v2.0). */
|
|
32
43
|
export interface LambdaEventV2 {
|
|
44
|
+
/** Payload format version; `"2.0"` for HTTP API / Function URL events. */
|
|
33
45
|
version?: string;
|
|
46
|
+
/** URL path of the request, without the query string. */
|
|
34
47
|
rawPath?: string;
|
|
48
|
+
/** Raw query string without the leading `?` (empty string when none). */
|
|
35
49
|
rawQueryString?: string;
|
|
50
|
+
/** Request headers; multi-value headers arrive comma-joined in v2.0. */
|
|
36
51
|
headers?: Record<string, string | undefined>;
|
|
52
|
+
/** Request cookies as individual strings; re-joined with `; ` into a `cookie` header. */
|
|
37
53
|
cookies?: string[];
|
|
54
|
+
/** Request context; `http.method`/`http.path` carry the method and path, `domainName` the host fallback. */
|
|
38
55
|
requestContext?: {
|
|
39
56
|
http?: {
|
|
40
57
|
method?: string;
|
|
@@ -42,32 +59,51 @@ export interface LambdaEventV2 {
|
|
|
42
59
|
};
|
|
43
60
|
domainName?: string;
|
|
44
61
|
};
|
|
62
|
+
/** Raw request body; base64-encoded when {@link LambdaEventV2.isBase64Encoded} is true. */
|
|
45
63
|
body?: string;
|
|
64
|
+
/** True when `body` is base64-encoded (binary payloads). */
|
|
46
65
|
isBase64Encoded?: boolean;
|
|
47
66
|
}
|
|
48
67
|
/** Either payload format accepted by {@link toLambdaHandler}. */
|
|
49
68
|
export type LambdaEvent = LambdaEventV1 | LambdaEventV2;
|
|
50
69
|
/** Lambda response shape required by API Gateway REST API (payload format v1.0). */
|
|
51
70
|
export interface LambdaResponseV1 {
|
|
71
|
+
/** HTTP status code of the response. */
|
|
52
72
|
statusCode: number;
|
|
73
|
+
/** Response headers, one value per name (`set-cookie` excluded; see `multiValueHeaders`). */
|
|
53
74
|
headers: Record<string, string>;
|
|
75
|
+
/** Multi-value headers; used to carry each `set-cookie` value separately in v1.0. */
|
|
54
76
|
multiValueHeaders?: Record<string, string[]>;
|
|
77
|
+
/** Never present in v1.0 responses; cookies travel via `multiValueHeaders`. */
|
|
55
78
|
cookies?: never;
|
|
79
|
+
/** Response body; base64-encoded when {@link LambdaResponseV1.isBase64Encoded} is true. */
|
|
56
80
|
body: string;
|
|
81
|
+
/** True when `body` is base64-encoded (non-text content types). */
|
|
57
82
|
isBase64Encoded: boolean;
|
|
58
83
|
}
|
|
59
84
|
/** Lambda response shape required by API Gateway HTTP API and Function URLs (payload format v2.0). */
|
|
60
85
|
export interface LambdaResponseV2 {
|
|
86
|
+
/** HTTP status code of the response. */
|
|
61
87
|
statusCode: number;
|
|
88
|
+
/** Response headers, one value per name (`set-cookie` excluded; see `cookies`). */
|
|
62
89
|
headers: Record<string, string>;
|
|
90
|
+
/** Response cookies, one `set-cookie` value per entry (v2.0's cookie channel). */
|
|
63
91
|
cookies?: string[];
|
|
92
|
+
/** Never present in v2.0 responses; cookies travel via `cookies`. */
|
|
64
93
|
multiValueHeaders?: never;
|
|
94
|
+
/** Response body; base64-encoded when {@link LambdaResponseV2.isBase64Encoded} is true. */
|
|
65
95
|
body: string;
|
|
96
|
+
/** True when `body` is base64-encoded (non-text content types). */
|
|
66
97
|
isBase64Encoded: boolean;
|
|
67
98
|
}
|
|
68
99
|
/** Either response shape produced by {@link toLambdaHandler}, chosen automatically per event. */
|
|
69
100
|
export type LambdaResponse = LambdaResponseV1 | LambdaResponseV2;
|
|
70
101
|
/** Async handler shape consumed by AWS Lambda / Netlify Functions runtimes. */
|
|
71
102
|
export type LambdaHandler = (event: LambdaEvent) => Promise<LambdaResponse>;
|
|
72
|
-
/**
|
|
103
|
+
/**
|
|
104
|
+
* Wrap an {@link App} as a Lambda/Netlify handler accepting either v1.0 or v2.0 event payloads.
|
|
105
|
+
*
|
|
106
|
+
* @param app - The DaloyJS {@link App} that serves each translated request.
|
|
107
|
+
* @returns A {@link LambdaHandler} that converts the event to a `Request`, calls {@link App.fetch}, and emits the matching v1.0/v2.0 response shape.
|
|
108
|
+
*/
|
|
73
109
|
export declare function toLambdaHandler(app: App): LambdaHandler;
|
package/dist/adapters/lambda.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
const TEXT_TYPE_RE = /^(text\/|application\/(json|xml|javascript|x-www-form-urlencoded|.*\+json|.*\+xml))/i;
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Wrap an {@link App} as a Lambda/Netlify handler accepting either v1.0 or v2.0 event payloads.
|
|
4
|
+
*
|
|
5
|
+
* @param app - The DaloyJS {@link App} that serves each translated request.
|
|
6
|
+
* @returns A {@link LambdaHandler} that converts the event to a `Request`, calls {@link App.fetch}, and emits the matching v1.0/v2.0 response shape.
|
|
7
|
+
*/
|
|
3
8
|
export function toLambdaHandler(app) {
|
|
4
9
|
return async (event) => {
|
|
5
10
|
const request = eventToRequest(event);
|
package/dist/adapters/node.d.ts
CHANGED
|
@@ -6,7 +6,9 @@ import { type Server } from "node:http";
|
|
|
6
6
|
import type { App } from "../app.js";
|
|
7
7
|
/** Options for the Node.js {@link serve} entry point. */
|
|
8
8
|
export interface NodeServerOptions {
|
|
9
|
+
/** TCP port to listen on. Defaults to `3000`. */
|
|
9
10
|
port?: number;
|
|
11
|
+
/** Interface to bind. Defaults to `"0.0.0.0"`. */
|
|
10
12
|
hostname?: string;
|
|
11
13
|
/**
|
|
12
14
|
* Connection-level timeout in ms, applied to BOTH `headersTimeout` and
|
|
@@ -72,9 +74,18 @@ export interface NodeServerOptions {
|
|
|
72
74
|
}
|
|
73
75
|
/** Handle returned by {@link serve} exposing the underlying Node `Server` plus a `close()` for graceful shutdown. */
|
|
74
76
|
export interface NodeServerHandle {
|
|
77
|
+
/** The underlying `node:http` `Server` instance, for advanced wiring (extra listeners, address introspection). */
|
|
75
78
|
server: Server;
|
|
79
|
+
/** Port the server was asked to listen on ({@link NodeServerOptions.port}, default `3000`). */
|
|
76
80
|
port: number;
|
|
81
|
+
/** Graceful shutdown: drains {@link App.shutdown} hooks, destroys WebSocket sockets, then closes the server. Idempotent. */
|
|
77
82
|
close(): Promise<void>;
|
|
78
83
|
}
|
|
79
|
-
/**
|
|
84
|
+
/**
|
|
85
|
+
* Start a Node.js HTTP (and optional WebSocket) server bound to the given {@link App}.
|
|
86
|
+
*
|
|
87
|
+
* @param app - The DaloyJS {@link App} whose `fetch` (and WebSocket routes) serve requests.
|
|
88
|
+
* @param opts - Listener, timeout, proxy-trust, and hardening options; see {@link NodeServerOptions}.
|
|
89
|
+
* @returns A {@link NodeServerHandle} exposing the Node `Server`, the `port`, and a graceful `close()`.
|
|
90
|
+
*/
|
|
80
91
|
export declare function serve(app: App, opts?: NodeServerOptions): NodeServerHandle;
|
package/dist/adapters/node.js
CHANGED
|
@@ -7,7 +7,13 @@ import { Readable } from "node:stream";
|
|
|
7
7
|
import { DALOY_RAW_BODY, DALOY_RAW_STREAM, DALOY_REQUEST_RAW_BODY } from "../app.js";
|
|
8
8
|
import { setClientCertificate, normalizePeerCertificate, } from "../mtls.js";
|
|
9
9
|
import { FrameSink, encodeFrame, encodeClosePayload, encodeSendPayload, validateUpgrade, validateSelectedSubprotocol, checkWebSocketOrigin, WS_OPCODE, WS_CLOSE_CODE, WS_READY_STATE, WS_MAX_CONTROL_PAYLOAD, WebSocketProtocolError, WebSocketPayloadTooLargeError, } from "../websocket.js";
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Start a Node.js HTTP (and optional WebSocket) server bound to the given {@link App}.
|
|
12
|
+
*
|
|
13
|
+
* @param app - The DaloyJS {@link App} whose `fetch` (and WebSocket routes) serve requests.
|
|
14
|
+
* @param opts - Listener, timeout, proxy-trust, and hardening options; see {@link NodeServerOptions}.
|
|
15
|
+
* @returns A {@link NodeServerHandle} exposing the Node `Server`, the `port`, and a graceful `close()`.
|
|
16
|
+
*/
|
|
11
17
|
export function serve(app, opts = {}) {
|
|
12
18
|
const trustProxy = opts.trustProxy === true;
|
|
13
19
|
const bufferedBodyMaxBytes = typeof opts.bufferedBodyMaxBytes === "number" && opts.bufferedBodyMaxBytes >= 0
|
|
@@ -23,16 +23,25 @@ import type { App } from "../app.js";
|
|
|
23
23
|
export type WebHandler = (req: Request) => Promise<Response>;
|
|
24
24
|
/** Default export shape for Vercel's web-standard `{ fetch }` runtime. */
|
|
25
25
|
export interface FetchHandler {
|
|
26
|
+
/** Request entry point: forwards the request to {@link App.fetch}. */
|
|
26
27
|
fetch: WebHandler;
|
|
27
28
|
}
|
|
28
29
|
declare const NEXT_METHODS: readonly ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"];
|
|
29
30
|
/** Record of per-method handlers expected by a Next.js App Router `route.ts` file. */
|
|
30
31
|
export type RouteHandlers = Record<(typeof NEXT_METHODS)[number], WebHandler>;
|
|
31
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Wrap an {@link App} as a single web-standard fetch handler.
|
|
34
|
+
*
|
|
35
|
+
* @param app - The DaloyJS {@link App} that serves each incoming request.
|
|
36
|
+
* @returns A {@link WebHandler} delegating to {@link App.fetch}.
|
|
37
|
+
*/
|
|
32
38
|
export declare function toWebHandler(app: App): WebHandler;
|
|
33
39
|
/**
|
|
34
40
|
* Build the default `{ fetch }` export expected by Vercel Node.js Functions
|
|
35
41
|
* in the `/api` directory.
|
|
42
|
+
*
|
|
43
|
+
* @param app - The DaloyJS {@link App} that serves each incoming request.
|
|
44
|
+
* @returns A {@link FetchHandler} object suitable as the module's `export default`.
|
|
36
45
|
*/
|
|
37
46
|
export declare function toFetchHandler(app: App): FetchHandler;
|
|
38
47
|
/** Backward-compatible alias for {@link toWebHandler}. */
|
|
@@ -40,6 +49,9 @@ export declare const toEdgeHandler: typeof toWebHandler;
|
|
|
40
49
|
/**
|
|
41
50
|
* Build the `{ GET, POST, ... }` object expected by Next.js App Router
|
|
42
51
|
* `route.ts` files when a DaloyJS app is mounted inside an existing Next app.
|
|
52
|
+
*
|
|
53
|
+
* @param app - The DaloyJS {@link App} that serves each incoming request.
|
|
54
|
+
* @returns A {@link RouteHandlers} record mapping every supported HTTP method to the same {@link WebHandler}.
|
|
43
55
|
*/
|
|
44
56
|
export declare function toRouteHandlers(app: App): RouteHandlers;
|
|
45
57
|
export {};
|
package/dist/adapters/vercel.js
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
const NEXT_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"];
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Wrap an {@link App} as a single web-standard fetch handler.
|
|
4
|
+
*
|
|
5
|
+
* @param app - The DaloyJS {@link App} that serves each incoming request.
|
|
6
|
+
* @returns A {@link WebHandler} delegating to {@link App.fetch}.
|
|
7
|
+
*/
|
|
3
8
|
export function toWebHandler(app) {
|
|
4
9
|
return (req) => app.fetch(req);
|
|
5
10
|
}
|
|
6
11
|
/**
|
|
7
12
|
* Build the default `{ fetch }` export expected by Vercel Node.js Functions
|
|
8
13
|
* in the `/api` directory.
|
|
14
|
+
*
|
|
15
|
+
* @param app - The DaloyJS {@link App} that serves each incoming request.
|
|
16
|
+
* @returns A {@link FetchHandler} object suitable as the module's `export default`.
|
|
9
17
|
*/
|
|
10
18
|
export function toFetchHandler(app) {
|
|
11
19
|
return { fetch: toWebHandler(app) };
|
|
@@ -15,6 +23,9 @@ export const toEdgeHandler = toWebHandler;
|
|
|
15
23
|
/**
|
|
16
24
|
* Build the `{ GET, POST, ... }` object expected by Next.js App Router
|
|
17
25
|
* `route.ts` files when a DaloyJS app is mounted inside an existing Next app.
|
|
26
|
+
*
|
|
27
|
+
* @param app - The DaloyJS {@link App} that serves each incoming request.
|
|
28
|
+
* @returns A {@link RouteHandlers} record mapping every supported HTTP method to the same {@link WebHandler}.
|
|
18
29
|
*/
|
|
19
30
|
export function toRouteHandlers(app) {
|
|
20
31
|
const handler = toWebHandler(app);
|
package/dist/app.d.ts
CHANGED
|
@@ -51,7 +51,9 @@ export type SecurityPreset = "internal-service";
|
|
|
51
51
|
export interface AppOptions {
|
|
52
52
|
/** OpenAPI document metadata */
|
|
53
53
|
title?: string;
|
|
54
|
+
/** OpenAPI `info.version`. Falls back to the host package manifest version, then `"0.0.0"`. */
|
|
54
55
|
version?: string;
|
|
56
|
+
/** OpenAPI `info.description`. Falls back to the host package manifest description. */
|
|
55
57
|
description?: string;
|
|
56
58
|
/**
|
|
57
59
|
* Topology-aware security posture preset. See {@link SecurityPreset}.
|
|
@@ -350,9 +352,13 @@ export interface AppOptions {
|
|
|
350
352
|
* @since 0.3.0
|
|
351
353
|
*/
|
|
352
354
|
export interface AppOpenAPIOptions {
|
|
355
|
+
/** OpenAPI `info` object. `title`/`version` fall back to {@link AppOptions.title} / {@link AppOptions.version}, then the host package manifest. */
|
|
353
356
|
info?: Partial<OpenAPIInfo>;
|
|
357
|
+
/** `servers` array published in the generated document. */
|
|
354
358
|
servers?: OpenAPIOptions["servers"];
|
|
359
|
+
/** Security schemes stitched into `components.securitySchemes`. */
|
|
355
360
|
securitySchemes?: OpenAPIOptions["securitySchemes"];
|
|
361
|
+
/** OpenAPI 3.1 top-level `webhooks` operations, keyed by webhook name. */
|
|
356
362
|
webhooks?: OpenAPIOptions["webhooks"];
|
|
357
363
|
}
|
|
358
364
|
/**
|
|
@@ -684,18 +690,31 @@ export interface CspReportRouteOptions {
|
|
|
684
690
|
* @since 0.1.0
|
|
685
691
|
*/
|
|
686
692
|
export interface IntrospectedRoute {
|
|
693
|
+
/** HTTP method the route responds to (e.g. `"GET"`). */
|
|
687
694
|
method: HttpMethod;
|
|
695
|
+
/** Route path pattern as registered, including any group prefix (e.g. `/users/:id`). */
|
|
688
696
|
path: string;
|
|
697
|
+
/** OpenAPI operationId, when declared on the route. */
|
|
689
698
|
operationId?: string;
|
|
699
|
+
/** OpenAPI tags, when declared on the route or inherited from a group. */
|
|
690
700
|
tags?: string[];
|
|
701
|
+
/** One-line OpenAPI summary, when declared. */
|
|
691
702
|
summary?: string;
|
|
703
|
+
/** Longer OpenAPI description, when declared. */
|
|
692
704
|
description?: string;
|
|
705
|
+
/** `true` when the route is marked deprecated in OpenAPI. */
|
|
693
706
|
deprecated?: boolean;
|
|
707
|
+
/** Whether the route declares a request body schema. */
|
|
694
708
|
hasBody: boolean;
|
|
709
|
+
/** Whether the route declares a query-string schema. */
|
|
695
710
|
hasQuery: boolean;
|
|
711
|
+
/** Whether the route declares a path-params schema. */
|
|
696
712
|
hasParams: boolean;
|
|
713
|
+
/** Whether the route declares a request-headers schema. */
|
|
697
714
|
hasHeaders: boolean;
|
|
715
|
+
/** Declared response status codes (e.g. `[200, 404]`). */
|
|
698
716
|
responses: number[];
|
|
717
|
+
/** Security scheme name and required scopes, when the route declares `auth`. */
|
|
699
718
|
auth?: {
|
|
700
719
|
scheme: string;
|
|
701
720
|
scopes?: string[];
|
|
@@ -799,10 +818,28 @@ export declare const DALOY_RAW_STREAM: unique symbol;
|
|
|
799
818
|
*/
|
|
800
819
|
type AppendRoute<Routes extends readonly RouteDefinition<any, any, any, any>[], R extends RouteDefinition<any, any, any, any>> = readonly RouteDefinition<any, any, any, any>[] extends Routes ? readonly [R] : readonly [...Routes, R];
|
|
801
820
|
/**
|
|
821
|
+
* The DaloyJS application: a contract-first router plus a web-standard
|
|
822
|
+
* `fetch(Request): Promise<Response>` handler that runs unchanged on Node,
|
|
823
|
+
* Bun, Deno, Cloudflare Workers, and Vercel via the adapters.
|
|
824
|
+
*
|
|
825
|
+
* Routes registered with {@link App.route} are validated against their
|
|
826
|
+
* declared schemas on the way in and out, accumulate in the typed
|
|
827
|
+
* {@link App.routes} tuple (powering OpenAPI generation and the typed
|
|
828
|
+
* client), and are served with secure defaults: body limits, request
|
|
829
|
+
* timeouts, security headers, and prod-mode error redaction.
|
|
830
|
+
*
|
|
831
|
+
* @typeParam Routes - Compile-time tuple of registered route definitions,
|
|
832
|
+
* grown by each {@link App.route} call.
|
|
802
833
|
* @since 0.1.0
|
|
803
834
|
*/
|
|
804
835
|
export declare class App<Routes extends readonly RouteDefinition<any, any, any, any>[] = readonly RouteDefinition<any, any, any, any>[]> {
|
|
836
|
+
/**
|
|
837
|
+
* Resolved constructor options. The security-relevant trio is always
|
|
838
|
+
* populated: `validateResponses` (default `true`), `bodyLimitBytes`
|
|
839
|
+
* (default 1 MiB), and `requestTimeoutMs` (default 30_000 ms).
|
|
840
|
+
*/
|
|
805
841
|
readonly options: Required<Pick<AppOptions, "validateResponses" | "bodyLimitBytes" | "requestTimeoutMs">> & AppOptions;
|
|
842
|
+
/** Structured logger for the app. Defaults to a JSON-lines console logger; override via `options.logger`. */
|
|
806
843
|
readonly log: Logger;
|
|
807
844
|
/**
|
|
808
845
|
* Public registry: enables OpenAPI gen, typed-client gen, dead-route detection.
|
|
@@ -1312,6 +1349,14 @@ export declare class App<Routes extends readonly RouteDefinition<any, any, any,
|
|
|
1312
1349
|
* @returns This `App` instance for chaining.
|
|
1313
1350
|
*/
|
|
1314
1351
|
use(hooks: Hooks): this;
|
|
1352
|
+
/**
|
|
1353
|
+
* Apply an ordered list of plugin extensions to the
|
|
1354
|
+
* group-level hook chain. Each extension's `handler` is wrapped into a
|
|
1355
|
+
* single-event {@link Hooks} bundle so subsequent route registrations
|
|
1356
|
+
* pick it up via the normal hook composition path.
|
|
1357
|
+
* @internal
|
|
1358
|
+
*/
|
|
1359
|
+
private applyExtensions;
|
|
1315
1360
|
/**
|
|
1316
1361
|
* Decorate `ctx.state` with a value available inside every handler and hook.
|
|
1317
1362
|
*
|
|
@@ -1334,16 +1379,10 @@ export declare class App<Routes extends readonly RouteDefinition<any, any, any,
|
|
|
1334
1379
|
*
|
|
1335
1380
|
* @param key - Property name on `ctx.state`.
|
|
1336
1381
|
* @param value - Value bound to that property on every request.
|
|
1382
|
+
* @param opts - Pass `{ override: true }` to replace an existing decoration (logged as a warning).
|
|
1337
1383
|
* @returns This `App` instance for chaining.
|
|
1384
|
+
* @throws Error if `key` is already decorated and `opts.override` is not `true`.
|
|
1338
1385
|
*/
|
|
1339
|
-
/**
|
|
1340
|
-
* Apply an ordered list of plugin extensions to the
|
|
1341
|
-
* group-level hook chain. Each extension's `handler` is wrapped into a
|
|
1342
|
-
* single-event {@link Hooks} bundle so subsequent route registrations
|
|
1343
|
-
* pick it up via the normal hook composition path.
|
|
1344
|
-
* @internal
|
|
1345
|
-
*/
|
|
1346
|
-
private applyExtensions;
|
|
1347
1386
|
decorate<K extends string, V>(key: K, value: V, opts?: {
|
|
1348
1387
|
override?: boolean;
|
|
1349
1388
|
}): this;
|
|
@@ -1474,13 +1513,6 @@ export declare class App<Routes extends readonly RouteDefinition<any, any, any,
|
|
|
1474
1513
|
* @returns Fulfills with the `Response` produced by the matching handler.
|
|
1475
1514
|
*/
|
|
1476
1515
|
request(input: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
1477
|
-
/**
|
|
1478
|
-
* Return a JSON-serializable summary of every registered route. Useful for
|
|
1479
|
-
* dead-route detection, dashboards, and tests that want to assert against
|
|
1480
|
-
* the route table without parsing the OpenAPI document.
|
|
1481
|
-
*
|
|
1482
|
-
* @returns Array of one {@link IntrospectedRoute} per registered route.
|
|
1483
|
-
*/
|
|
1484
1516
|
/**
|
|
1485
1517
|
* Emit a one-time development warning when any route declares a `2xx`
|
|
1486
1518
|
* response without a body schema, because response-field stripping
|
|
@@ -1490,6 +1522,13 @@ export declare class App<Routes extends readonly RouteDefinition<any, any, any,
|
|
|
1490
1522
|
* `secureDefaults: false`. See {@link findRoutesMissingResponseBodySchema}.
|
|
1491
1523
|
*/
|
|
1492
1524
|
private warnMissingResponseBodySchemas;
|
|
1525
|
+
/**
|
|
1526
|
+
* Return a JSON-serializable summary of every registered route. Useful for
|
|
1527
|
+
* dead-route detection, dashboards, and tests that want to assert against
|
|
1528
|
+
* the route table without parsing the OpenAPI document.
|
|
1529
|
+
*
|
|
1530
|
+
* @returns Array of one {@link IntrospectedRoute} per registered route.
|
|
1531
|
+
*/
|
|
1493
1532
|
introspect(): IntrospectedRoute[];
|
|
1494
1533
|
/**
|
|
1495
1534
|
* Begin graceful shutdown.
|
|
@@ -1532,6 +1571,12 @@ export declare class App<Routes extends readonly RouteDefinition<any, any, any,
|
|
|
1532
1571
|
/**
|
|
1533
1572
|
* Topological sort of plugin extensions. Refuses-at-call
|
|
1534
1573
|
* on cyclic ordering with a structured error naming the cycle.
|
|
1574
|
+
*
|
|
1575
|
+
* @param exts - Extensions to order by their `before` / `after` constraints (Kahn's algorithm).
|
|
1576
|
+
* @returns The extensions in a valid execution order.
|
|
1577
|
+
* @throws Error on duplicate extension names, on a `before`/`after` cycle
|
|
1578
|
+
* (naming the members), or when two extensions mutate the same response
|
|
1579
|
+
* header without declaring an ordering between each other.
|
|
1535
1580
|
* @internal
|
|
1536
1581
|
*/
|
|
1537
1582
|
export declare function topoSortExtensions(exts: ReadonlyArray<PluginExtension>): PluginExtension[];
|
|
@@ -1550,13 +1595,16 @@ export declare function topoSortExtensions(exts: ReadonlyArray<PluginExtension>)
|
|
|
1550
1595
|
* It powers both the `daloy doctor` `audit.response.bodySchema` finding and
|
|
1551
1596
|
* the development-mode boot warning emitted on the first request. The result
|
|
1552
1597
|
* is advisory — a route may legitimately return no body — so callers treat
|
|
1553
|
-
* it as a `warn`, never a hard error.
|
|
1598
|
+
* it as a `warn`, never a hard error. Routes that set
|
|
1599
|
+
* `acknowledgeNoResponseBodySchema: true` (including the framework-mounted
|
|
1600
|
+
* docs, AsyncAPI, health, and metrics routes, whose bodies DaloyJS itself
|
|
1601
|
+
* serializes) are skipped: the missing schema is declared intentional.
|
|
1554
1602
|
*
|
|
1555
1603
|
* @param routes - Route definitions to inspect (typically `app.routes`).
|
|
1556
1604
|
* @returns One entry per offending route with the affected `2xx` status codes.
|
|
1557
1605
|
* @since 0.40.0
|
|
1558
1606
|
*/
|
|
1559
|
-
export declare function findRoutesMissingResponseBodySchema(routes: readonly Pick<RouteDefinition<any, any, any, any>, "method" | "path" | "responses">[]): Array<{
|
|
1607
|
+
export declare function findRoutesMissingResponseBodySchema(routes: readonly Pick<RouteDefinition<any, any, any, any>, "method" | "path" | "responses" | "acknowledgeNoResponseBodySchema">[]): Array<{
|
|
1560
1608
|
method: string;
|
|
1561
1609
|
path: string;
|
|
1562
1610
|
statuses: number[];
|
|
@@ -1575,6 +1623,8 @@ export declare function findRoutesMissingResponseBodySchema(routes: readonly Pic
|
|
|
1575
1623
|
* for ergonomics and matches the factory pattern used by Express, Fastify,
|
|
1576
1624
|
* and Hono adapters.
|
|
1577
1625
|
*
|
|
1626
|
+
* @param options - Same {@link AppOptions} accepted by the `App` constructor. Default: `{}`.
|
|
1627
|
+
* @returns A new {@link App} instance.
|
|
1578
1628
|
* @since 0.3.0
|
|
1579
1629
|
*/
|
|
1580
1630
|
export declare function createApp(options?: AppOptions): App;
|