adorn-api 1.1.11 → 1.1.13
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 +18 -0
- package/dist/adapter/express/types.d.ts +3 -46
- package/dist/adapter/fastify/coercion.d.ts +12 -0
- package/dist/adapter/fastify/coercion.js +289 -0
- package/dist/adapter/fastify/controllers.d.ts +7 -0
- package/dist/adapter/fastify/controllers.js +201 -0
- package/dist/adapter/fastify/index.d.ts +14 -0
- package/dist/adapter/fastify/index.js +67 -0
- package/dist/adapter/fastify/multipart.d.ts +26 -0
- package/dist/adapter/fastify/multipart.js +75 -0
- package/dist/adapter/fastify/openapi.d.ts +10 -0
- package/dist/adapter/fastify/openapi.js +76 -0
- package/dist/adapter/fastify/response-serializer.d.ts +2 -0
- package/dist/adapter/fastify/response-serializer.js +162 -0
- package/dist/adapter/fastify/types.d.ts +100 -0
- package/dist/adapter/fastify/types.js +2 -0
- package/dist/adapter/metal-orm/index.d.ts +1 -1
- package/dist/adapter/metal-orm/types.d.ts +23 -0
- package/dist/adapter/native/coercion.d.ts +12 -0
- package/dist/adapter/native/coercion.js +289 -0
- package/dist/adapter/native/controllers.d.ts +17 -0
- package/dist/adapter/native/controllers.js +215 -0
- package/dist/adapter/native/index.d.ts +14 -0
- package/dist/adapter/native/index.js +127 -0
- package/dist/adapter/native/openapi.d.ts +7 -0
- package/dist/adapter/native/openapi.js +82 -0
- package/dist/adapter/native/response-serializer.d.ts +5 -0
- package/dist/adapter/native/response-serializer.js +160 -0
- package/dist/adapter/native/router.d.ts +25 -0
- package/dist/adapter/native/router.js +68 -0
- package/dist/adapter/native/types.d.ts +77 -0
- package/dist/adapter/native/types.js +2 -0
- package/dist/core/auth.d.ts +11 -12
- package/dist/core/auth.js +2 -2
- package/dist/core/logger.d.ts +3 -4
- package/dist/core/logger.js +2 -2
- package/dist/core/streaming.d.ts +10 -10
- package/dist/core/streaming.js +31 -19
- package/dist/core/types.d.ts +102 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +16 -1
- package/examples/fastify/app.ts +16 -0
- package/examples/fastify/index.ts +21 -0
- package/package.json +24 -18
- package/src/adapter/express/controllers.ts +249 -249
- package/src/adapter/express/types.ts +121 -160
- package/src/adapter/fastify/coercion.ts +369 -0
- package/src/adapter/fastify/controllers.ts +255 -0
- package/src/adapter/fastify/index.ts +53 -0
- package/src/adapter/fastify/multipart.ts +94 -0
- package/src/adapter/fastify/openapi.ts +93 -0
- package/src/adapter/fastify/response-serializer.ts +179 -0
- package/src/adapter/fastify/types.ts +119 -0
- package/src/adapter/metal-orm/index.ts +3 -0
- package/src/adapter/metal-orm/types.ts +25 -0
- package/src/adapter/native/coercion.ts +369 -0
- package/src/adapter/native/controllers.ts +271 -0
- package/src/adapter/native/index.ts +116 -0
- package/src/adapter/native/openapi.ts +109 -0
- package/src/adapter/native/response-serializer.ts +177 -0
- package/src/adapter/native/router.ts +90 -0
- package/src/adapter/native/types.ts +96 -0
- package/src/core/auth.ts +314 -315
- package/src/core/health.ts +234 -235
- package/src/core/logger.ts +245 -247
- package/src/core/streaming.ts +342 -330
- package/src/core/types.ts +115 -0
- package/src/index.ts +46 -16
- package/tests/e2e/fastify.e2e.test.ts +174 -0
- package/tests/native.test.ts +191 -0
- package/tests/typecheck/query-params.typecheck.ts +42 -0
- package/tests/unit/openapi-parameters.test.ts +97 -97
- package/tsconfig.json +14 -13
- package/tsconfig.typecheck.json +8 -0
- package/vitest.config.ts +47 -7
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerOpenApi = registerOpenApi;
|
|
4
|
+
const openapi_1 = require("../../core/openapi");
|
|
5
|
+
/**
|
|
6
|
+
* Registers OpenAPI endpoints with a native application router.
|
|
7
|
+
*/
|
|
8
|
+
function registerOpenApi(router, controllers, options) {
|
|
9
|
+
const openApiPath = normalizePath(options.path, "/openapi.json");
|
|
10
|
+
const document = (0, openapi_1.buildOpenApi)({
|
|
11
|
+
info: options.info,
|
|
12
|
+
servers: options.servers,
|
|
13
|
+
controllers
|
|
14
|
+
});
|
|
15
|
+
router.add({
|
|
16
|
+
getOpenApi: async () => {
|
|
17
|
+
return document;
|
|
18
|
+
}
|
|
19
|
+
}, {
|
|
20
|
+
handlerName: "getOpenApi",
|
|
21
|
+
httpMethod: "get",
|
|
22
|
+
path: openApiPath,
|
|
23
|
+
responses: [{ status: 200, description: "OpenAPI JSON" }]
|
|
24
|
+
}, "");
|
|
25
|
+
if (!options.docs) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const docsOptions = typeof options.docs === "object" ? options.docs : {};
|
|
29
|
+
const docsPath = normalizePath(docsOptions.path, "/docs");
|
|
30
|
+
const title = docsOptions.title ?? `${options.info.title} Docs`;
|
|
31
|
+
const swaggerUiUrl = (docsOptions.swaggerUiUrl ?? "https://unpkg.com/swagger-ui-dist@5").replace(/\/+$/, "");
|
|
32
|
+
const html = buildSwaggerUiHtml({ title, swaggerUiUrl, openApiPath });
|
|
33
|
+
router.add({
|
|
34
|
+
getDocs: async () => {
|
|
35
|
+
return html;
|
|
36
|
+
}
|
|
37
|
+
}, {
|
|
38
|
+
handlerName: "getDocs",
|
|
39
|
+
httpMethod: "get",
|
|
40
|
+
path: docsPath,
|
|
41
|
+
raw: true,
|
|
42
|
+
responses: [{ status: 200, contentType: "text/html", description: "Swagger UI" }]
|
|
43
|
+
}, "");
|
|
44
|
+
}
|
|
45
|
+
function normalizePath(path, fallback) {
|
|
46
|
+
if (!path) {
|
|
47
|
+
return fallback;
|
|
48
|
+
}
|
|
49
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
50
|
+
}
|
|
51
|
+
function buildSwaggerUiHtml(options) {
|
|
52
|
+
return `<!doctype html>
|
|
53
|
+
<html lang="en">
|
|
54
|
+
<head>
|
|
55
|
+
<meta charset="utf-8" />
|
|
56
|
+
<title>${options.title}</title>
|
|
57
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
58
|
+
<link rel="stylesheet" href="${options.swaggerUiUrl}/swagger-ui.css" />
|
|
59
|
+
<style>
|
|
60
|
+
body {
|
|
61
|
+
margin: 0;
|
|
62
|
+
background: #f6f6f6;
|
|
63
|
+
}
|
|
64
|
+
</style>
|
|
65
|
+
</head>
|
|
66
|
+
<body>
|
|
67
|
+
<div id="swagger-ui"></div>
|
|
68
|
+
<script src="${options.swaggerUiUrl}/swagger-ui-bundle.js"></script>
|
|
69
|
+
<script>
|
|
70
|
+
window.onload = () => {
|
|
71
|
+
window.ui = SwaggerUIBundle({
|
|
72
|
+
url: "${options.openApiPath}",
|
|
73
|
+
dom_id: "#swagger-ui",
|
|
74
|
+
deepLinking: true,
|
|
75
|
+
presets: [SwaggerUIBundle.presets.apis],
|
|
76
|
+
layout: "BaseLayout"
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
</script>
|
|
80
|
+
</body>
|
|
81
|
+
</html>`;
|
|
82
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.serializeResponse = serializeResponse;
|
|
4
|
+
const metadata_1 = require("../../core/metadata");
|
|
5
|
+
/**
|
|
6
|
+
* Serializes a response body based on the provided schema.
|
|
7
|
+
*/
|
|
8
|
+
function serializeResponse(value, schema) {
|
|
9
|
+
if (value === null || value === undefined) {
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
if (isSchemaNode(schema)) {
|
|
13
|
+
return serializeWithSchema(value, schema);
|
|
14
|
+
}
|
|
15
|
+
return serializeWithDto(value, schema);
|
|
16
|
+
}
|
|
17
|
+
function serializeWithDto(value, dto) {
|
|
18
|
+
if (value === null || value === undefined) {
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
if (Array.isArray(value)) {
|
|
22
|
+
return value.map((entry) => serializeWithDto(entry, dto));
|
|
23
|
+
}
|
|
24
|
+
const plainValue = toPlainObject(value);
|
|
25
|
+
if (!plainValue) {
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
const meta = (0, metadata_1.getDtoMeta)(dto);
|
|
29
|
+
if (!meta) {
|
|
30
|
+
return plainValue;
|
|
31
|
+
}
|
|
32
|
+
const output = { ...plainValue };
|
|
33
|
+
for (const [name, field] of Object.entries(meta.fields)) {
|
|
34
|
+
if (name in plainValue) {
|
|
35
|
+
output[name] = serializeWithSchema(plainValue[name], field.schema);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return output;
|
|
39
|
+
}
|
|
40
|
+
function serializeWithSchema(value, schema) {
|
|
41
|
+
if (value === null || value === undefined) {
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
switch (schema.kind) {
|
|
45
|
+
case "string":
|
|
46
|
+
return serializeString(value, schema.format);
|
|
47
|
+
case "array":
|
|
48
|
+
if (!Array.isArray(value)) {
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
return value.map((entry) => serializeWithSchema(entry, schema.items));
|
|
52
|
+
case "object":
|
|
53
|
+
return serializeObject(value, schema.properties);
|
|
54
|
+
case "record":
|
|
55
|
+
if (!isPlainObject(value)) {
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
return serializeRecord(value, schema.values);
|
|
59
|
+
case "ref":
|
|
60
|
+
return serializeWithDto(value, schema.dto);
|
|
61
|
+
case "union":
|
|
62
|
+
return serializeUnion(value, schema.anyOf);
|
|
63
|
+
default:
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function serializeString(value, format) {
|
|
68
|
+
if (format === "byte" && Buffer.isBuffer(value)) {
|
|
69
|
+
return value.toString("base64");
|
|
70
|
+
}
|
|
71
|
+
if (!(value instanceof Date)) {
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
if (Number.isNaN(value.getTime())) {
|
|
75
|
+
return value;
|
|
76
|
+
}
|
|
77
|
+
if (format === "date") {
|
|
78
|
+
return value.toISOString().slice(0, 10);
|
|
79
|
+
}
|
|
80
|
+
if (format === "date-time") {
|
|
81
|
+
return value.toISOString();
|
|
82
|
+
}
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
function serializeObject(value, properties) {
|
|
86
|
+
const plainValue = toPlainObject(value);
|
|
87
|
+
if (!plainValue) {
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
const output = { ...plainValue };
|
|
91
|
+
if (!properties) {
|
|
92
|
+
return output;
|
|
93
|
+
}
|
|
94
|
+
for (const [key, schema] of Object.entries(properties)) {
|
|
95
|
+
if (key in plainValue) {
|
|
96
|
+
output[key] = serializeWithSchema(plainValue[key], schema);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return output;
|
|
100
|
+
}
|
|
101
|
+
function serializeRecord(value, schema) {
|
|
102
|
+
const output = { ...value };
|
|
103
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
104
|
+
output[key] = serializeWithSchema(entry, schema);
|
|
105
|
+
}
|
|
106
|
+
return output;
|
|
107
|
+
}
|
|
108
|
+
function serializeUnion(value, options) {
|
|
109
|
+
for (const option of options) {
|
|
110
|
+
const serialized = serializeWithSchema(value, option);
|
|
111
|
+
if (serialized !== value) {
|
|
112
|
+
return serialized;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return value;
|
|
116
|
+
}
|
|
117
|
+
function isSchemaNode(value) {
|
|
118
|
+
return !!value && typeof value === "object" && "kind" in value;
|
|
119
|
+
}
|
|
120
|
+
function isPlainObject(value) {
|
|
121
|
+
return (value !== null &&
|
|
122
|
+
typeof value === "object" &&
|
|
123
|
+
!Array.isArray(value) &&
|
|
124
|
+
!(value instanceof Date));
|
|
125
|
+
}
|
|
126
|
+
function toPlainObject(value) {
|
|
127
|
+
if (value !== null &&
|
|
128
|
+
typeof value === "object" &&
|
|
129
|
+
typeof value.toJSON === "function") {
|
|
130
|
+
const jsonResult = value.toJSON();
|
|
131
|
+
return jsonResult;
|
|
132
|
+
}
|
|
133
|
+
if (typeof value === "object" && typeof value.load === "function") {
|
|
134
|
+
const wrapper = value;
|
|
135
|
+
if (wrapper.current !== undefined && wrapper.current !== null) {
|
|
136
|
+
return toPlainObject(wrapper.current);
|
|
137
|
+
}
|
|
138
|
+
if (wrapper.loaded) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
if (isPlainObject(value)) {
|
|
144
|
+
return value;
|
|
145
|
+
}
|
|
146
|
+
if (typeof value === "object") {
|
|
147
|
+
const result = {};
|
|
148
|
+
for (const key of Object.getOwnPropertyNames(value)) {
|
|
149
|
+
if (key.startsWith('_') || key === 'constructor' || key === 'prototype')
|
|
150
|
+
continue;
|
|
151
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
152
|
+
if (descriptor && descriptor.enumerable) {
|
|
153
|
+
const propertyValue = value[key];
|
|
154
|
+
result[key] = propertyValue;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { RouteMeta } from "../../core/metadata";
|
|
2
|
+
/**
|
|
3
|
+
* Result of a route match.
|
|
4
|
+
*/
|
|
5
|
+
export interface RouteMatch {
|
|
6
|
+
controller: any;
|
|
7
|
+
route: RouteMeta;
|
|
8
|
+
params: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A simple router for matching URL paths to routes.
|
|
12
|
+
*/
|
|
13
|
+
export declare class Router {
|
|
14
|
+
private routes;
|
|
15
|
+
/**
|
|
16
|
+
* Registers a route in the router.
|
|
17
|
+
*/
|
|
18
|
+
add(controller: any, route: RouteMeta, basePath: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* Matches an incoming request to a registered route.
|
|
21
|
+
*/
|
|
22
|
+
match(method: string, path: string): RouteMatch | undefined;
|
|
23
|
+
private joinPaths;
|
|
24
|
+
private compilePath;
|
|
25
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Router = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* A simple router for matching URL paths to routes.
|
|
6
|
+
*/
|
|
7
|
+
class Router {
|
|
8
|
+
routes = [];
|
|
9
|
+
/**
|
|
10
|
+
* Registers a route in the router.
|
|
11
|
+
*/
|
|
12
|
+
add(controller, route, basePath) {
|
|
13
|
+
const fullPath = this.joinPaths(basePath, route.path);
|
|
14
|
+
const { pattern, paramNames } = this.compilePath(fullPath);
|
|
15
|
+
this.routes.push({
|
|
16
|
+
method: route.httpMethod,
|
|
17
|
+
pattern,
|
|
18
|
+
paramNames,
|
|
19
|
+
controller,
|
|
20
|
+
route
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Matches an incoming request to a registered route.
|
|
25
|
+
*/
|
|
26
|
+
match(method, path) {
|
|
27
|
+
const normalizedMethod = method.toLowerCase();
|
|
28
|
+
const url = new URL(path, "http://localhost");
|
|
29
|
+
const pathname = url.pathname;
|
|
30
|
+
for (const entry of this.routes) {
|
|
31
|
+
if (entry.method !== normalizedMethod) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const match = entry.pattern.exec(pathname);
|
|
35
|
+
if (match) {
|
|
36
|
+
const params = {};
|
|
37
|
+
for (let i = 0; i < entry.paramNames.length; i++) {
|
|
38
|
+
params[entry.paramNames[i]] = decodeURIComponent(match[i + 1]);
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
controller: entry.controller,
|
|
42
|
+
route: entry.route,
|
|
43
|
+
params
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
joinPaths(base, path) {
|
|
50
|
+
const normalizedBase = base.replace(/\/+$/, "");
|
|
51
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
52
|
+
return `${normalizedBase}${normalizedPath}` || "/";
|
|
53
|
+
}
|
|
54
|
+
compilePath(path) {
|
|
55
|
+
const paramNames = [];
|
|
56
|
+
const patternStr = path
|
|
57
|
+
.replace(/:([a-zA-Z0-9_]+)/g, (_, name) => {
|
|
58
|
+
paramNames.push(name);
|
|
59
|
+
return "([^/]+)";
|
|
60
|
+
})
|
|
61
|
+
.replace(/\//g, "\\/");
|
|
62
|
+
return {
|
|
63
|
+
pattern: new RegExp(`^${patternStr}$`),
|
|
64
|
+
paramNames
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.Router = Router;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import type { Constructor, RequestContext as CoreRequestContext, UploadedFileInfo } from "../../core/types";
|
|
3
|
+
import type { OpenApiInfo, OpenApiServer } from "../../core/openapi";
|
|
4
|
+
export { UploadedFileInfo };
|
|
5
|
+
/**
|
|
6
|
+
* Request context provided to native route handlers.
|
|
7
|
+
*/
|
|
8
|
+
export type RequestContext<TBody = any, TQuery extends object | undefined = Record<string, any>, TParams extends object | undefined = Record<string, any>, THeaders extends object | undefined = Record<string, any>, TFiles extends Record<string, UploadedFileInfo | UploadedFileInfo[]> | undefined = any> = CoreRequestContext<TBody, TQuery, TParams, THeaders, TFiles>;
|
|
9
|
+
/**
|
|
10
|
+
* Input coercion modes.
|
|
11
|
+
*/
|
|
12
|
+
export type InputCoercionMode = "safe" | "strict";
|
|
13
|
+
/**
|
|
14
|
+
* Input coercion setting - can be a mode or disabled.
|
|
15
|
+
*/
|
|
16
|
+
export type InputCoercionSetting = InputCoercionMode | false;
|
|
17
|
+
/**
|
|
18
|
+
* Options for OpenAPI documentation UI.
|
|
19
|
+
*/
|
|
20
|
+
export interface OpenApiDocsOptions {
|
|
21
|
+
/** Path for documentation UI */
|
|
22
|
+
path?: string;
|
|
23
|
+
/** Title for documentation page */
|
|
24
|
+
title?: string;
|
|
25
|
+
/** URL for Swagger UI assets */
|
|
26
|
+
swaggerUiUrl?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* OpenAPI configuration for native adapter.
|
|
30
|
+
*/
|
|
31
|
+
export interface OpenApiNativeOptions {
|
|
32
|
+
/** OpenAPI document info */
|
|
33
|
+
info: OpenApiInfo;
|
|
34
|
+
/** Array of servers */
|
|
35
|
+
servers?: OpenApiServer[];
|
|
36
|
+
/** Path for OpenAPI JSON endpoint */
|
|
37
|
+
path?: string;
|
|
38
|
+
/** Whether to pretty-print the JSON output (defaults to false for minified output) */
|
|
39
|
+
prettyPrint?: boolean;
|
|
40
|
+
/** Documentation UI configuration */
|
|
41
|
+
docs?: boolean | OpenApiDocsOptions;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Validation configuration options.
|
|
45
|
+
*/
|
|
46
|
+
export interface ValidationOptions {
|
|
47
|
+
/** Whether validation is enabled. Defaults to true. */
|
|
48
|
+
enabled?: boolean;
|
|
49
|
+
/** Validation mode. 'strict' mode fails on any validation error, 'lax' mode may allow some errors. Defaults to 'strict'. */
|
|
50
|
+
mode?: "strict" | "lax";
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Options for creating a native Node.js application adapter.
|
|
54
|
+
*/
|
|
55
|
+
export interface NativeAdapterOptions {
|
|
56
|
+
/** Array of controller classes */
|
|
57
|
+
controllers: Constructor[];
|
|
58
|
+
/** Whether to enable JSON body parsing */
|
|
59
|
+
jsonBody?: boolean;
|
|
60
|
+
/** Max JSON body size in bytes. */
|
|
61
|
+
bodyLimit?: number;
|
|
62
|
+
/** OpenAPI configuration */
|
|
63
|
+
openApi?: OpenApiNativeOptions;
|
|
64
|
+
/** Input coercion setting */
|
|
65
|
+
inputCoercion?: InputCoercionSetting;
|
|
66
|
+
/** Validation configuration. Set to false to disable validation, or provide options. */
|
|
67
|
+
validation?: boolean | ValidationOptions;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Interface for the native application.
|
|
71
|
+
*/
|
|
72
|
+
export interface NativeApp {
|
|
73
|
+
/** The native Node.js request handler */
|
|
74
|
+
handle(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
75
|
+
/** Start the server on the specified port */
|
|
76
|
+
listen(port: number, callback?: () => void): any;
|
|
77
|
+
}
|
package/dist/core/auth.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Request, Response, NextFunction } from "express";
|
|
2
1
|
import type { Constructor } from "./types";
|
|
3
2
|
/**
|
|
4
3
|
* User context interface - extend this in your application.
|
|
@@ -17,12 +16,12 @@ export interface AuthOptions {
|
|
|
17
16
|
/** All roles required (all must match) */
|
|
18
17
|
allRoles?: string[];
|
|
19
18
|
/** Custom guard function */
|
|
20
|
-
guard?: (user: AuthUser, req:
|
|
19
|
+
guard?: (user: AuthUser, req: any) => boolean | Promise<boolean>;
|
|
21
20
|
}
|
|
22
21
|
/**
|
|
23
22
|
* Function to extract user from request.
|
|
24
23
|
*/
|
|
25
|
-
export type AuthExtractor = (req:
|
|
24
|
+
export type AuthExtractor = (req: any) => AuthUser | null | Promise<AuthUser | null>;
|
|
26
25
|
/**
|
|
27
26
|
* Options for creating auth middleware.
|
|
28
27
|
*/
|
|
@@ -32,9 +31,9 @@ export interface AuthMiddlewareOptions {
|
|
|
32
31
|
/** Property name to attach user to request (default: "user") */
|
|
33
32
|
userProperty?: string;
|
|
34
33
|
/** Custom unauthorized response */
|
|
35
|
-
onUnauthorized?: (req:
|
|
34
|
+
onUnauthorized?: (req: any, res: any) => void;
|
|
36
35
|
/** Custom forbidden response */
|
|
37
|
-
onForbidden?: (req:
|
|
36
|
+
onForbidden?: (req: any, res: any, reason?: string) => void;
|
|
38
37
|
}
|
|
39
38
|
/**
|
|
40
39
|
* Metadata for authentication on routes/controllers.
|
|
@@ -49,7 +48,7 @@ interface AuthMeta {
|
|
|
49
48
|
/** Required roles (all must match) */
|
|
50
49
|
allRoles?: string[];
|
|
51
50
|
/** Custom guard function */
|
|
52
|
-
guard?: (user: AuthUser, req:
|
|
51
|
+
guard?: (user: AuthUser, req: any) => boolean | Promise<boolean>;
|
|
53
52
|
}
|
|
54
53
|
/**
|
|
55
54
|
* Decorator to require authentication on a controller or route.
|
|
@@ -92,7 +91,7 @@ export declare function getControllerAuthMeta(controller: Constructor): AuthMeta
|
|
|
92
91
|
* @param options - Auth middleware options
|
|
93
92
|
* @returns Express middleware function
|
|
94
93
|
*/
|
|
95
|
-
export declare function createAuthMiddleware(options: AuthMiddlewareOptions): (req:
|
|
94
|
+
export declare function createAuthMiddleware(options: AuthMiddlewareOptions): (req: any, res: any, next: (err?: any) => void) => Promise<void>;
|
|
96
95
|
/**
|
|
97
96
|
* Creates a route guard middleware that checks auth metadata.
|
|
98
97
|
* @param controller - Controller class
|
|
@@ -102,20 +101,20 @@ export declare function createAuthMiddleware(options: AuthMiddlewareOptions): (r
|
|
|
102
101
|
*/
|
|
103
102
|
export declare function createRouteGuard(controller: Constructor, handlerName: string | symbol, options?: {
|
|
104
103
|
userProperty?: string;
|
|
105
|
-
}): (req:
|
|
104
|
+
}): (req: any, res: any, next: (err?: any) => void) => Promise<void>;
|
|
106
105
|
/**
|
|
107
106
|
* Helper to get user from request in controllers.
|
|
108
|
-
* @param req -
|
|
107
|
+
* @param req - Raw request
|
|
109
108
|
* @param userProperty - Property name (default: "user")
|
|
110
109
|
* @returns User or undefined
|
|
111
110
|
*/
|
|
112
|
-
export declare function getUser<T extends AuthUser = AuthUser>(req:
|
|
111
|
+
export declare function getUser<T extends AuthUser = AuthUser>(req: any, userProperty?: string): T | undefined;
|
|
113
112
|
/**
|
|
114
113
|
* Helper to require user from request (throws if not present).
|
|
115
|
-
* @param req -
|
|
114
|
+
* @param req - Raw request
|
|
116
115
|
* @param userProperty - Property name (default: "user")
|
|
117
116
|
* @returns User
|
|
118
117
|
* @throws HttpError if user not found
|
|
119
118
|
*/
|
|
120
|
-
export declare function requireUser<T extends AuthUser = AuthUser>(req:
|
|
119
|
+
export declare function requireUser<T extends AuthUser = AuthUser>(req: any, userProperty?: string): T;
|
|
121
120
|
export {};
|
package/dist/core/auth.js
CHANGED
|
@@ -210,7 +210,7 @@ function createRouteGuard(controller, handlerName, options = {}) {
|
|
|
210
210
|
}
|
|
211
211
|
/**
|
|
212
212
|
* Helper to get user from request in controllers.
|
|
213
|
-
* @param req -
|
|
213
|
+
* @param req - Raw request
|
|
214
214
|
* @param userProperty - Property name (default: "user")
|
|
215
215
|
* @returns User or undefined
|
|
216
216
|
*/
|
|
@@ -219,7 +219,7 @@ function getUser(req, userProperty = "user") {
|
|
|
219
219
|
}
|
|
220
220
|
/**
|
|
221
221
|
* Helper to require user from request (throws if not present).
|
|
222
|
-
* @param req -
|
|
222
|
+
* @param req - Raw request
|
|
223
223
|
* @param userProperty - Property name (default: "user")
|
|
224
224
|
* @returns User
|
|
225
225
|
* @throws HttpError if user not found
|
package/dist/core/logger.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Request, Response, NextFunction } from "express";
|
|
2
1
|
/**
|
|
3
2
|
* Log levels in order of severity.
|
|
4
3
|
*/
|
|
@@ -45,13 +44,13 @@ export interface RequestLoggerOptions {
|
|
|
45
44
|
/** Custom transport function (default: JSON to console) */
|
|
46
45
|
transport?: LogTransport;
|
|
47
46
|
/** Paths to skip logging (e.g., ["/health", "/health/live"]) */
|
|
48
|
-
skip?: string[] | ((req:
|
|
47
|
+
skip?: string[] | ((req: any) => boolean);
|
|
49
48
|
/** Header name for request ID (default: "x-request-id") */
|
|
50
49
|
requestIdHeader?: string;
|
|
51
50
|
/** Whether to generate request ID if not present (default: true) */
|
|
52
51
|
generateRequestId?: boolean;
|
|
53
52
|
/** Custom context extractor */
|
|
54
|
-
context?: (req:
|
|
53
|
+
context?: (req: any, res: any) => Record<string, unknown>;
|
|
55
54
|
}
|
|
56
55
|
/**
|
|
57
56
|
* Logger interface for application-level logging.
|
|
@@ -99,7 +98,7 @@ export declare function prettyTransport(entry: RequestLogEntry | LogEntry): void
|
|
|
99
98
|
* @param options - Logger configuration options
|
|
100
99
|
* @returns Express middleware function
|
|
101
100
|
*/
|
|
102
|
-
export declare function requestLogger(options?: RequestLoggerOptions): (req:
|
|
101
|
+
export declare function requestLogger(options?: RequestLoggerOptions): (req: any, res: any, next: (err?: any) => void) => void;
|
|
103
102
|
/**
|
|
104
103
|
* Creates a structured logger for application-level logging.
|
|
105
104
|
* @param options - Logger configuration options
|
package/dist/core/logger.js
CHANGED
|
@@ -85,7 +85,7 @@ function requestLogger(options = {}) {
|
|
|
85
85
|
if (!requestId && generateRequestId) {
|
|
86
86
|
requestId = generateId();
|
|
87
87
|
}
|
|
88
|
-
if (requestId) {
|
|
88
|
+
if (requestId && res.setHeader) {
|
|
89
89
|
res.setHeader(requestIdHeader, requestId);
|
|
90
90
|
}
|
|
91
91
|
const originalEnd = res.end;
|
|
@@ -102,7 +102,7 @@ function requestLogger(options = {}) {
|
|
|
102
102
|
url: req.originalUrl || req.url,
|
|
103
103
|
status: res.statusCode,
|
|
104
104
|
responseTime: Math.round(responseTime * 100) / 100,
|
|
105
|
-
contentLength: res.get
|
|
105
|
+
contentLength: res.get ? parseInt(res.get("content-length"), 10) : undefined,
|
|
106
106
|
ip: req.ip || req.headers["x-forwarded-for"]?.split(",")[0]?.trim(),
|
|
107
107
|
userAgent: req.headers["user-agent"],
|
|
108
108
|
requestId,
|
package/dist/core/streaming.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SseEmitterInterface, StreamWriterInterface } from "./types";
|
|
2
2
|
/**
|
|
3
3
|
* Server-Sent Event data structure.
|
|
4
4
|
*/
|
|
@@ -24,11 +24,11 @@ export interface SseEmitterOptions {
|
|
|
24
24
|
/**
|
|
25
25
|
* SSE Emitter for sending Server-Sent Events to clients.
|
|
26
26
|
*/
|
|
27
|
-
export declare class SseEmitter {
|
|
27
|
+
export declare class SseEmitter implements SseEmitterInterface {
|
|
28
28
|
private readonly res;
|
|
29
29
|
private closed;
|
|
30
30
|
private keepAliveTimer?;
|
|
31
|
-
constructor(res:
|
|
31
|
+
constructor(res: any, options?: SseEmitterOptions);
|
|
32
32
|
/**
|
|
33
33
|
* Send an SSE event to the client.
|
|
34
34
|
*/
|
|
@@ -58,7 +58,7 @@ export declare class SseEmitter {
|
|
|
58
58
|
/**
|
|
59
59
|
* Create an SSE emitter from an Express response.
|
|
60
60
|
*/
|
|
61
|
-
export declare function createSseEmitter(res:
|
|
61
|
+
export declare function createSseEmitter(res: any, options?: SseEmitterOptions): SseEmitter;
|
|
62
62
|
/**
|
|
63
63
|
* Options for streaming response configuration.
|
|
64
64
|
*/
|
|
@@ -71,10 +71,10 @@ export interface StreamOptions {
|
|
|
71
71
|
/**
|
|
72
72
|
* Stream writer for sending chunked data to clients.
|
|
73
73
|
*/
|
|
74
|
-
export declare class StreamWriter {
|
|
74
|
+
export declare class StreamWriter implements StreamWriterInterface {
|
|
75
75
|
private readonly res;
|
|
76
76
|
private closed;
|
|
77
|
-
constructor(res:
|
|
77
|
+
constructor(res: any, options?: StreamOptions);
|
|
78
78
|
/**
|
|
79
79
|
* Write data to the stream.
|
|
80
80
|
*/
|
|
@@ -104,20 +104,20 @@ export declare class StreamWriter {
|
|
|
104
104
|
/**
|
|
105
105
|
* Create a stream writer from an Express response.
|
|
106
106
|
*/
|
|
107
|
-
export declare function createStreamWriter(res:
|
|
107
|
+
export declare function createStreamWriter(res: any, options?: StreamOptions): StreamWriter;
|
|
108
108
|
/**
|
|
109
109
|
* Create an NDJSON stream writer (newline-delimited JSON).
|
|
110
110
|
*/
|
|
111
|
-
export declare function createNdjsonStream(res:
|
|
111
|
+
export declare function createNdjsonStream(res: any): StreamWriter;
|
|
112
112
|
/**
|
|
113
113
|
* Stream an async iterable to the response.
|
|
114
114
|
*/
|
|
115
|
-
export declare function streamIterable<T>(res:
|
|
115
|
+
export declare function streamIterable<T>(res: any, iterable: AsyncIterable<T>, options?: StreamOptions & {
|
|
116
116
|
transform?: (item: T) => string | Buffer;
|
|
117
117
|
}): Promise<void>;
|
|
118
118
|
/**
|
|
119
119
|
* Stream an async iterable as SSE events.
|
|
120
120
|
*/
|
|
121
|
-
export declare function streamSseIterable<T>(res:
|
|
121
|
+
export declare function streamSseIterable<T>(res: any, iterable: AsyncIterable<T>, options?: SseEmitterOptions & {
|
|
122
122
|
eventType?: string;
|
|
123
123
|
}): Promise<void>;
|