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,26 @@
|
|
|
1
|
+
import type { FastifyRequest } from "fastify";
|
|
2
|
+
import type { UploadedFileMeta } from "../../core/metadata";
|
|
3
|
+
import type { UploadedFileInfo } from "../../core/types";
|
|
4
|
+
import type { MultipartOptions } from "./types";
|
|
5
|
+
/**
|
|
6
|
+
* Normalized multipart options with defaults applied.
|
|
7
|
+
*/
|
|
8
|
+
export interface NormalizedMultipartOptions {
|
|
9
|
+
storage: "memory" | "disk";
|
|
10
|
+
dest: string;
|
|
11
|
+
maxFileSize: number;
|
|
12
|
+
maxFiles: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Normalizes multipart options with defaults.
|
|
16
|
+
*/
|
|
17
|
+
export declare function normalizeMultipartOptions(options: boolean | MultipartOptions | undefined): NormalizedMultipartOptions | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Extracts uploaded files from the Fastify request.
|
|
20
|
+
* For Fastify, files are expected to be attached to the request by @fastify/multipart
|
|
21
|
+
*/
|
|
22
|
+
export declare function extractFiles(req: FastifyRequest): Promise<Record<string, UploadedFileInfo | UploadedFileInfo[]> | undefined>;
|
|
23
|
+
/**
|
|
24
|
+
* Checks if a route has file uploads configured.
|
|
25
|
+
*/
|
|
26
|
+
export declare function hasFileUploads(files: UploadedFileMeta[] | undefined): boolean;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeMultipartOptions = normalizeMultipartOptions;
|
|
4
|
+
exports.extractFiles = extractFiles;
|
|
5
|
+
exports.hasFileUploads = hasFileUploads;
|
|
6
|
+
const DEFAULT_OPTIONS = {
|
|
7
|
+
storage: "memory",
|
|
8
|
+
dest: "",
|
|
9
|
+
maxFileSize: 10 * 1024 * 1024, // 10MB
|
|
10
|
+
maxFiles: 10
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Normalizes multipart options with defaults.
|
|
14
|
+
*/
|
|
15
|
+
function normalizeMultipartOptions(options) {
|
|
16
|
+
if (!options) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
if (options === true) {
|
|
20
|
+
return DEFAULT_OPTIONS;
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
storage: options.storage ?? DEFAULT_OPTIONS.storage,
|
|
24
|
+
dest: options.dest ?? DEFAULT_OPTIONS.dest,
|
|
25
|
+
maxFileSize: options.maxFileSize ?? DEFAULT_OPTIONS.maxFileSize,
|
|
26
|
+
maxFiles: options.maxFiles ?? DEFAULT_OPTIONS.maxFiles
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Extracts uploaded files from the Fastify request.
|
|
31
|
+
* For Fastify, files are expected to be attached to the request by @fastify/multipart
|
|
32
|
+
*/
|
|
33
|
+
async function extractFiles(req) {
|
|
34
|
+
const parts = req.parts();
|
|
35
|
+
const filesMap = {};
|
|
36
|
+
const fields = {};
|
|
37
|
+
for await (const part of parts) {
|
|
38
|
+
if (part.file) {
|
|
39
|
+
const buffer = await part.toBuffer();
|
|
40
|
+
const info = {
|
|
41
|
+
originalName: part.filename,
|
|
42
|
+
mimeType: part.mimetype,
|
|
43
|
+
size: buffer.length,
|
|
44
|
+
buffer: buffer,
|
|
45
|
+
fieldName: part.fieldname
|
|
46
|
+
};
|
|
47
|
+
if (filesMap[part.fieldname]) {
|
|
48
|
+
if (Array.isArray(filesMap[part.fieldname])) {
|
|
49
|
+
filesMap[part.fieldname].push(info);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
filesMap[part.fieldname] = [filesMap[part.fieldname], info];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
filesMap[part.fieldname] = info;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
// It's a field
|
|
61
|
+
fields[part.fieldname] = part.value;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Merge fields into body if it's a multipart request
|
|
65
|
+
if (Object.keys(fields).length > 0) {
|
|
66
|
+
Object.assign(req.body ?? (req.body = {}), fields);
|
|
67
|
+
}
|
|
68
|
+
return Object.keys(filesMap).length > 0 ? filesMap : undefined;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Checks if a route has file uploads configured.
|
|
72
|
+
*/
|
|
73
|
+
function hasFileUploads(files) {
|
|
74
|
+
return !!files && files.length > 0;
|
|
75
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FastifyInstance } from "fastify";
|
|
2
|
+
import type { Constructor } from "../../core/types";
|
|
3
|
+
import type { OpenApiFastifyOptions } from "./types";
|
|
4
|
+
/**
|
|
5
|
+
* Attaches OpenAPI endpoints to a Fastify application.
|
|
6
|
+
* @param app - Fastify application instance
|
|
7
|
+
* @param controllers - Array of controller classes
|
|
8
|
+
* @param options - OpenAPI options
|
|
9
|
+
*/
|
|
10
|
+
export declare function attachOpenApi(app: FastifyInstance, controllers: Constructor[], options: OpenApiFastifyOptions): void;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.attachOpenApi = attachOpenApi;
|
|
4
|
+
const openapi_1 = require("../../core/openapi");
|
|
5
|
+
/**
|
|
6
|
+
* Attaches OpenAPI endpoints to a Fastify application.
|
|
7
|
+
* @param app - Fastify application instance
|
|
8
|
+
* @param controllers - Array of controller classes
|
|
9
|
+
* @param options - OpenAPI options
|
|
10
|
+
*/
|
|
11
|
+
function attachOpenApi(app, controllers, options) {
|
|
12
|
+
const openApiPath = normalizePath(options.path, "/openapi.json");
|
|
13
|
+
const document = (0, openapi_1.buildOpenApi)({
|
|
14
|
+
info: options.info,
|
|
15
|
+
servers: options.servers,
|
|
16
|
+
controllers
|
|
17
|
+
});
|
|
18
|
+
app.get(openApiPath, (_req, reply) => {
|
|
19
|
+
if (options.prettyPrint) {
|
|
20
|
+
reply.header("Content-Type", "application/json");
|
|
21
|
+
reply.send(JSON.stringify(document, null, 2));
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
reply.send(document);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
if (!options.docs) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const docsOptions = typeof options.docs === "object" ? options.docs : {};
|
|
31
|
+
const docsPath = normalizePath(docsOptions.path, "/docs");
|
|
32
|
+
const title = docsOptions.title ?? `${options.info.title} Docs`;
|
|
33
|
+
const swaggerUiUrl = (docsOptions.swaggerUiUrl ?? "https://unpkg.com/swagger-ui-dist@5").replace(/\/+$/, "");
|
|
34
|
+
const html = buildSwaggerUiHtml({ title, swaggerUiUrl, openApiPath });
|
|
35
|
+
app.get(docsPath, (_req, reply) => {
|
|
36
|
+
reply.type("text/html").send(html);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function normalizePath(path, fallback) {
|
|
40
|
+
if (!path) {
|
|
41
|
+
return fallback;
|
|
42
|
+
}
|
|
43
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
44
|
+
}
|
|
45
|
+
function buildSwaggerUiHtml(options) {
|
|
46
|
+
return `<!doctype html>
|
|
47
|
+
<html lang="en">
|
|
48
|
+
<head>
|
|
49
|
+
<meta charset="utf-8" />
|
|
50
|
+
<title>${options.title}</title>
|
|
51
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
52
|
+
<link rel="stylesheet" href="${options.swaggerUiUrl}/swagger-ui.css" />
|
|
53
|
+
<style>
|
|
54
|
+
body {
|
|
55
|
+
margin: 0;
|
|
56
|
+
background: #f6f6f6;
|
|
57
|
+
}
|
|
58
|
+
</style>
|
|
59
|
+
</head>
|
|
60
|
+
<body>
|
|
61
|
+
<div id="swagger-ui"></div>
|
|
62
|
+
<script src="${options.swaggerUiUrl}/swagger-ui-bundle.js"></script>
|
|
63
|
+
<script>
|
|
64
|
+
window.onload = () => {
|
|
65
|
+
window.ui = SwaggerUIBundle({
|
|
66
|
+
url: "${options.openApiPath}",
|
|
67
|
+
dom_id: "#swagger-ui",
|
|
68
|
+
deepLinking: true,
|
|
69
|
+
presets: [SwaggerUIBundle.presets.apis],
|
|
70
|
+
layout: "BaseLayout"
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
</script>
|
|
74
|
+
</body>
|
|
75
|
+
</html>`;
|
|
76
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.serializeResponse = serializeResponse;
|
|
4
|
+
const metadata_1 = require("../../core/metadata");
|
|
5
|
+
function serializeResponse(value, schema) {
|
|
6
|
+
if (value === null || value === undefined) {
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
if (isSchemaNode(schema)) {
|
|
10
|
+
return serializeWithSchema(value, schema);
|
|
11
|
+
}
|
|
12
|
+
return serializeWithDto(value, schema);
|
|
13
|
+
}
|
|
14
|
+
function serializeWithDto(value, dto) {
|
|
15
|
+
if (value === null || value === undefined) {
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
if (Array.isArray(value)) {
|
|
19
|
+
return value.map((entry) => serializeWithDto(entry, dto));
|
|
20
|
+
}
|
|
21
|
+
const plainValue = toPlainObject(value);
|
|
22
|
+
if (!plainValue) {
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
const meta = (0, metadata_1.getDtoMeta)(dto);
|
|
26
|
+
if (!meta) {
|
|
27
|
+
return plainValue;
|
|
28
|
+
}
|
|
29
|
+
const output = { ...plainValue };
|
|
30
|
+
for (const [name, field] of Object.entries(meta.fields)) {
|
|
31
|
+
if (name in plainValue) {
|
|
32
|
+
output[name] = serializeWithSchema(plainValue[name], field.schema);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return output;
|
|
36
|
+
}
|
|
37
|
+
function serializeWithSchema(value, schema) {
|
|
38
|
+
if (value === null || value === undefined) {
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
switch (schema.kind) {
|
|
42
|
+
case "string":
|
|
43
|
+
return serializeString(value, schema.format);
|
|
44
|
+
case "array":
|
|
45
|
+
if (!Array.isArray(value)) {
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
return value.map((entry) => serializeWithSchema(entry, schema.items));
|
|
49
|
+
case "object":
|
|
50
|
+
return serializeObject(value, schema.properties);
|
|
51
|
+
case "record":
|
|
52
|
+
if (!isPlainObject(value)) {
|
|
53
|
+
return value;
|
|
54
|
+
}
|
|
55
|
+
return serializeRecord(value, schema.values);
|
|
56
|
+
case "ref":
|
|
57
|
+
return serializeWithDto(value, schema.dto);
|
|
58
|
+
case "union":
|
|
59
|
+
return serializeUnion(value, schema.anyOf);
|
|
60
|
+
default:
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function serializeString(value, format) {
|
|
65
|
+
if (format === "byte" && Buffer.isBuffer(value)) {
|
|
66
|
+
return value.toString("base64");
|
|
67
|
+
}
|
|
68
|
+
if (!(value instanceof Date)) {
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
71
|
+
if (Number.isNaN(value.getTime())) {
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
if (format === "date") {
|
|
75
|
+
return value.toISOString().slice(0, 10);
|
|
76
|
+
}
|
|
77
|
+
if (format === "date-time") {
|
|
78
|
+
return value.toISOString();
|
|
79
|
+
}
|
|
80
|
+
return value;
|
|
81
|
+
}
|
|
82
|
+
function serializeObject(value, properties) {
|
|
83
|
+
const plainValue = toPlainObject(value);
|
|
84
|
+
if (!plainValue) {
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
const output = { ...plainValue };
|
|
88
|
+
if (!properties) {
|
|
89
|
+
return output;
|
|
90
|
+
}
|
|
91
|
+
for (const [key, schema] of Object.entries(properties)) {
|
|
92
|
+
if (key in plainValue) {
|
|
93
|
+
output[key] = serializeWithSchema(plainValue[key], schema);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return output;
|
|
97
|
+
}
|
|
98
|
+
function serializeRecord(value, schema) {
|
|
99
|
+
const output = { ...value };
|
|
100
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
101
|
+
output[key] = serializeWithSchema(entry, schema);
|
|
102
|
+
}
|
|
103
|
+
return output;
|
|
104
|
+
}
|
|
105
|
+
function serializeUnion(value, options) {
|
|
106
|
+
for (const option of options) {
|
|
107
|
+
const serialized = serializeWithSchema(value, option);
|
|
108
|
+
if (serialized !== value) {
|
|
109
|
+
return serialized;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return value;
|
|
113
|
+
}
|
|
114
|
+
function isSchemaNode(value) {
|
|
115
|
+
return !!value && typeof value === "object" && "kind" in value;
|
|
116
|
+
}
|
|
117
|
+
function isPlainObject(value) {
|
|
118
|
+
return (value !== null &&
|
|
119
|
+
typeof value === "object" &&
|
|
120
|
+
!Array.isArray(value) &&
|
|
121
|
+
!(value instanceof Date));
|
|
122
|
+
}
|
|
123
|
+
function toPlainObject(value) {
|
|
124
|
+
// 1. Check if value has custom toJSON method (e.g., metal-orm entities)
|
|
125
|
+
if (value !== null &&
|
|
126
|
+
typeof value === "object" &&
|
|
127
|
+
typeof value.toJSON === "function") {
|
|
128
|
+
// Use the custom toJSON which handles circular refs and includes properly
|
|
129
|
+
const jsonResult = value.toJSON();
|
|
130
|
+
return jsonResult;
|
|
131
|
+
}
|
|
132
|
+
// 2. Handle lazy-load wrappers (BelongsToReference)
|
|
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
|
+
// 3. Handle plain objects
|
|
144
|
+
if (isPlainObject(value)) {
|
|
145
|
+
return value;
|
|
146
|
+
}
|
|
147
|
+
// 4. Convert class instances to plain objects
|
|
148
|
+
if (typeof value === "object") {
|
|
149
|
+
const result = {};
|
|
150
|
+
for (const key of Object.getOwnPropertyNames(value)) {
|
|
151
|
+
if (key.startsWith('_') || key === 'constructor' || key === 'prototype')
|
|
152
|
+
continue;
|
|
153
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
154
|
+
if (descriptor && descriptor.enumerable) {
|
|
155
|
+
const propertyValue = value[key];
|
|
156
|
+
result[key] = propertyValue;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { Constructor, RequestContext as CoreRequestContext, UploadedFileInfo } from "../../core/types";
|
|
2
|
+
import type { OpenApiInfo, OpenApiServer } from "../../core/openapi";
|
|
3
|
+
/**
|
|
4
|
+
* Request context provided to Fastify route handlers.
|
|
5
|
+
*/
|
|
6
|
+
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>;
|
|
7
|
+
/**
|
|
8
|
+
* Input coercion modes.
|
|
9
|
+
*/
|
|
10
|
+
export type InputCoercionMode = "safe" | "strict";
|
|
11
|
+
/**
|
|
12
|
+
* Input coercion setting - can be a mode or disabled.
|
|
13
|
+
*/
|
|
14
|
+
export type InputCoercionSetting = InputCoercionMode | false;
|
|
15
|
+
/**
|
|
16
|
+
* CORS configuration options.
|
|
17
|
+
*/
|
|
18
|
+
export interface CorsOptions {
|
|
19
|
+
/** Allowed origins. Use "*" for all, a string, array of strings, or a function for dynamic matching. */
|
|
20
|
+
origin?: string | string[] | ((origin: string | undefined) => boolean | string);
|
|
21
|
+
/** Allowed HTTP methods. Defaults to ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"]. */
|
|
22
|
+
methods?: string[];
|
|
23
|
+
/** Allowed headers. Defaults to ["Content-Type", "Authorization"]. */
|
|
24
|
+
allowedHeaders?: string[];
|
|
25
|
+
/** Headers exposed to the client. */
|
|
26
|
+
exposedHeaders?: string[];
|
|
27
|
+
/** Whether to include credentials (cookies, authorization headers). Defaults to false. */
|
|
28
|
+
credentials?: boolean;
|
|
29
|
+
/** Max age in seconds for preflight cache. Defaults to 86400 (24 hours). */
|
|
30
|
+
maxAge?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Options for OpenAPI documentation UI.
|
|
34
|
+
*/
|
|
35
|
+
export interface OpenApiDocsOptions {
|
|
36
|
+
/** Path for documentation UI */
|
|
37
|
+
path?: string;
|
|
38
|
+
/** Title for documentation page */
|
|
39
|
+
title?: string;
|
|
40
|
+
/** URL for Swagger UI assets */
|
|
41
|
+
swaggerUiUrl?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* OpenAPI configuration for Fastify adapter.
|
|
45
|
+
*/
|
|
46
|
+
export interface OpenApiFastifyOptions {
|
|
47
|
+
/** OpenAPI document info */
|
|
48
|
+
info: OpenApiInfo;
|
|
49
|
+
/** Array of servers */
|
|
50
|
+
servers?: OpenApiServer[];
|
|
51
|
+
/** Path for OpenAPI JSON endpoint */
|
|
52
|
+
path?: string;
|
|
53
|
+
/** Whether to pretty-print the JSON output (defaults to false for minified output) */
|
|
54
|
+
prettyPrint?: boolean;
|
|
55
|
+
/** Documentation UI configuration */
|
|
56
|
+
docs?: boolean | OpenApiDocsOptions;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Multipart file upload configuration.
|
|
60
|
+
*/
|
|
61
|
+
export interface MultipartOptions {
|
|
62
|
+
/** Storage type: 'memory' or 'disk' (Fastify adapter mainly supports memory via @fastify/multipart) */
|
|
63
|
+
storage?: "memory" | "disk";
|
|
64
|
+
/** Directory for disk storage (defaults to OS temp directory) */
|
|
65
|
+
dest?: string;
|
|
66
|
+
/** Maximum file size in bytes (defaults to 10MB) */
|
|
67
|
+
maxFileSize?: number;
|
|
68
|
+
/** Maximum number of files per field (defaults to 10) */
|
|
69
|
+
maxFiles?: number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Validation configuration options.
|
|
73
|
+
*/
|
|
74
|
+
export interface ValidationOptions {
|
|
75
|
+
/** Whether validation is enabled. Defaults to true. */
|
|
76
|
+
enabled?: boolean;
|
|
77
|
+
/** Validation mode. 'strict' mode fails on any validation error, 'lax' mode may allow some errors. Defaults to 'strict'. */
|
|
78
|
+
mode?: 'strict' | 'lax';
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Options for creating a Fastify application adapter.
|
|
82
|
+
*/
|
|
83
|
+
export interface FastifyAdapterOptions {
|
|
84
|
+
/** Array of controller classes */
|
|
85
|
+
controllers: Constructor[];
|
|
86
|
+
/** Whether to enable JSON body parsing */
|
|
87
|
+
jsonBody?: boolean;
|
|
88
|
+
/** Max JSON body size (e.g. 1048576 for 1MB). */
|
|
89
|
+
bodyLimit?: number;
|
|
90
|
+
/** OpenAPI configuration */
|
|
91
|
+
openApi?: OpenApiFastifyOptions;
|
|
92
|
+
/** Input coercion setting */
|
|
93
|
+
inputCoercion?: InputCoercionSetting;
|
|
94
|
+
/** CORS configuration. Set to true for permissive defaults, or provide options. */
|
|
95
|
+
cors?: boolean | CorsOptions;
|
|
96
|
+
/** Multipart file upload configuration. Set to true for defaults, or provide options. */
|
|
97
|
+
multipart?: boolean | MultipartOptions;
|
|
98
|
+
/** Validation configuration. Set to false to disable validation, or provide options. */
|
|
99
|
+
validation?: boolean | ValidationOptions;
|
|
100
|
+
}
|
|
@@ -11,4 +11,4 @@ export { createMetalDtoOverrides, type CreateMetalDtoOverridesOptions } from "./
|
|
|
11
11
|
export { createErrorDtoClass, StandardErrorDto, SimpleErrorDto, BasicErrorDto } from "./error-dtos";
|
|
12
12
|
export { withSession, parseIdOrThrow, compactUpdates, applyInput, getEntityOrThrow } from "./utils";
|
|
13
13
|
export { validateEntityMetadata, hasValidEntityMetadata } from "./field-builder";
|
|
14
|
-
export type { MetalDtoMode, MetalDtoOptions, MetalDtoTarget, PaginationConfig, PaginationOptions, ParsedPagination, Filter, FilterMapping, FilterFieldMapping, FilterFieldPath, FilterFieldPathArray, FilterFieldInput, RelationQuantifier, ParseFilterOptions, ParseSortOptions, ParsedSort, SortDirection, CrudListSortTerm, RunPagedListOptions, ExecuteCrudListOptions, CrudPagedResponse, ListConfig, PagedQueryDtoOptions, PagedResponseDtoOptions, PagedFilterQueryDtoOptions, FilterFieldDef, MetalCrudQueryFilterDef, MetalCrudSortableColumns, MetalCrudOptionsQueryOptions, MetalCrudQueryOptions, MetalCrudStandardErrorsOptions, MetalCrudDtoOptions, MetalCrudDtoClassOptions, MetalCrudDtoDecorators, MetalCrudDtoClasses, MetalCrudDtoClassNameKey, MetalCrudDtoClassNames, CrudControllerService, CrudControllerServiceInput, CreateCrudControllerOptions, RouteErrorsDecorator, NestedCreateDtoOptions, MetalTreeDtoClassOptions, MetalTreeDtoClasses, MetalTreeDtoClassNames, MetalTreeListEntryOptions, ErrorDtoOptions, CreateSessionFn } from "./types";
|
|
14
|
+
export type { MetalDtoMode, MetalDtoOptions, MetalDtoTarget, PaginationConfig, PaginationOptions, ParsedPagination, PaginationQueryParams, Filter, FilterMapping, FilterFieldMapping, FilterFieldPath, FilterFieldPathArray, FilterFieldInput, RelationQuantifier, ParseFilterOptions, ParseSortOptions, ParsedSort, SortDirection, SortingQueryParams, PagedQueryParams, CrudListSortTerm, RunPagedListOptions, ExecuteCrudListOptions, CrudPagedResponse, ListConfig, PagedQueryDtoOptions, PagedResponseDtoOptions, PagedFilterQueryDtoOptions, FilterFieldDef, MetalCrudQueryFilterDef, MetalCrudSortableColumns, MetalCrudOptionsQueryOptions, MetalCrudQueryOptions, MetalCrudStandardErrorsOptions, MetalCrudDtoOptions, MetalCrudDtoClassOptions, MetalCrudDtoDecorators, MetalCrudDtoClasses, MetalCrudDtoClassNameKey, MetalCrudDtoClassNames, CrudControllerService, CrudControllerServiceInput, CreateCrudControllerOptions, RouteErrorsDecorator, NestedCreateDtoOptions, MetalTreeDtoClassOptions, MetalTreeDtoClasses, MetalTreeDtoClassNames, MetalTreeListEntryOptions, ErrorDtoOptions, CreateSessionFn } from "./types";
|
|
@@ -56,6 +56,15 @@ export interface ParsedPagination {
|
|
|
56
56
|
/** Page size */
|
|
57
57
|
pageSize: number;
|
|
58
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Pagination query params for consumer-side TypeScript interfaces.
|
|
61
|
+
*/
|
|
62
|
+
export interface PaginationQueryParams {
|
|
63
|
+
/** Page number */
|
|
64
|
+
page?: number;
|
|
65
|
+
/** Page size */
|
|
66
|
+
pageSize?: number;
|
|
67
|
+
}
|
|
59
68
|
/**
|
|
60
69
|
* Filter field mapping.
|
|
61
70
|
*/
|
|
@@ -108,6 +117,20 @@ export interface ParseFilterOptions<T = Record<string, unknown>> {
|
|
|
108
117
|
* Sort direction.
|
|
109
118
|
*/
|
|
110
119
|
export type SortDirection = "asc" | "desc";
|
|
120
|
+
/**
|
|
121
|
+
* Sorting query params for consumer-side TypeScript interfaces.
|
|
122
|
+
*/
|
|
123
|
+
export interface SortingQueryParams {
|
|
124
|
+
/** Requested sort key */
|
|
125
|
+
sortBy?: string;
|
|
126
|
+
/** Sort direction */
|
|
127
|
+
sortDirection?: SortDirection;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Combined pagination + sorting query params.
|
|
131
|
+
*/
|
|
132
|
+
export interface PagedQueryParams extends PaginationQueryParams, SortingQueryParams {
|
|
133
|
+
}
|
|
111
134
|
/**
|
|
112
135
|
* Sort parsing options.
|
|
113
136
|
*/
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type InputMeta } from "../../core/metadata";
|
|
2
|
+
import type { InputCoercionMode } from "./types";
|
|
3
|
+
export type InputLocation = "params" | "query" | "body";
|
|
4
|
+
interface CoerceInputOptions {
|
|
5
|
+
mode: InputCoercionMode;
|
|
6
|
+
location: InputLocation;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Creates an input coercer function for the given input metadata.
|
|
10
|
+
*/
|
|
11
|
+
export declare function createInputCoercer<T extends Record<string, unknown> = Record<string, unknown>>(input: InputMeta | undefined, options: CoerceInputOptions): ((value: T) => T) | undefined;
|
|
12
|
+
export {};
|