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
package/dist/core/streaming.js
CHANGED
|
@@ -20,9 +20,11 @@ class SseEmitter {
|
|
|
20
20
|
if (keepAlive) {
|
|
21
21
|
this.startKeepAlive(keepAliveInterval);
|
|
22
22
|
}
|
|
23
|
-
res.on
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
if (res.on) {
|
|
24
|
+
res.on("close", () => {
|
|
25
|
+
this.close();
|
|
26
|
+
});
|
|
27
|
+
}
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
30
|
* Send an SSE event to the client.
|
|
@@ -73,11 +75,15 @@ class SseEmitter {
|
|
|
73
75
|
return this.closed;
|
|
74
76
|
}
|
|
75
77
|
setupSseHeaders() {
|
|
76
|
-
this.res.setHeader
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
if (this.res.setHeader) {
|
|
79
|
+
this.res.setHeader("Content-Type", "text/event-stream");
|
|
80
|
+
this.res.setHeader("Cache-Control", "no-cache, no-transform");
|
|
81
|
+
this.res.setHeader("Connection", "keep-alive");
|
|
82
|
+
this.res.setHeader("X-Accel-Buffering", "no");
|
|
83
|
+
}
|
|
84
|
+
if (this.res.flushHeaders) {
|
|
85
|
+
this.res.flushHeaders();
|
|
86
|
+
}
|
|
81
87
|
}
|
|
82
88
|
startKeepAlive(interval) {
|
|
83
89
|
this.keepAliveTimer = setInterval(() => {
|
|
@@ -135,9 +141,11 @@ class StreamWriter {
|
|
|
135
141
|
constructor(res, options = {}) {
|
|
136
142
|
this.res = res;
|
|
137
143
|
this.setupHeaders(options);
|
|
138
|
-
res.on
|
|
139
|
-
|
|
140
|
-
|
|
144
|
+
if (res.on) {
|
|
145
|
+
res.on("close", () => {
|
|
146
|
+
this.closed = true;
|
|
147
|
+
});
|
|
148
|
+
}
|
|
141
149
|
}
|
|
142
150
|
/**
|
|
143
151
|
* Write data to the stream.
|
|
@@ -186,16 +194,20 @@ class StreamWriter {
|
|
|
186
194
|
}
|
|
187
195
|
setupHeaders(options) {
|
|
188
196
|
const contentType = options.contentType ?? "application/octet-stream";
|
|
189
|
-
this.res.setHeader
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
197
|
+
if (this.res.setHeader) {
|
|
198
|
+
this.res.setHeader("Content-Type", contentType);
|
|
199
|
+
this.res.setHeader("Transfer-Encoding", "chunked");
|
|
200
|
+
this.res.setHeader("Cache-Control", "no-cache, no-transform");
|
|
201
|
+
this.res.setHeader("X-Accel-Buffering", "no");
|
|
202
|
+
if (options.headers) {
|
|
203
|
+
for (const [key, value] of Object.entries(options.headers)) {
|
|
204
|
+
this.res.setHeader(key, value);
|
|
205
|
+
}
|
|
196
206
|
}
|
|
197
207
|
}
|
|
198
|
-
this.res.flushHeaders
|
|
208
|
+
if (this.res.flushHeaders) {
|
|
209
|
+
this.res.flushHeaders();
|
|
210
|
+
}
|
|
199
211
|
}
|
|
200
212
|
}
|
|
201
213
|
exports.StreamWriter = StreamWriter;
|
package/dist/core/types.d.ts
CHANGED
|
@@ -10,3 +10,105 @@ export type DtoConstructor<T = any> = new (...args: any[]) => T;
|
|
|
10
10
|
* HTTP method types.
|
|
11
11
|
*/
|
|
12
12
|
export type HttpMethod = "get" | "post" | "put" | "patch" | "delete";
|
|
13
|
+
/**
|
|
14
|
+
* Uploaded file information from multipart form data.
|
|
15
|
+
*/
|
|
16
|
+
export interface UploadedFileInfo {
|
|
17
|
+
/** Original filename as provided by the client */
|
|
18
|
+
originalName: string;
|
|
19
|
+
/** MIME type of the file */
|
|
20
|
+
mimeType: string;
|
|
21
|
+
/** Size of the file in bytes */
|
|
22
|
+
size: number;
|
|
23
|
+
/** File buffer (when using memory storage) */
|
|
24
|
+
buffer?: Buffer;
|
|
25
|
+
/** Path to the file on disk (when using disk storage) */
|
|
26
|
+
path?: string;
|
|
27
|
+
/** Field name from the form */
|
|
28
|
+
fieldName: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Generic request interface.
|
|
32
|
+
*/
|
|
33
|
+
export interface HttpRequest {
|
|
34
|
+
method: string;
|
|
35
|
+
url: string;
|
|
36
|
+
originalUrl?: string;
|
|
37
|
+
path?: string;
|
|
38
|
+
params: Record<string, any>;
|
|
39
|
+
query: Record<string, any>;
|
|
40
|
+
body: any;
|
|
41
|
+
headers: Record<string, any>;
|
|
42
|
+
ip?: string;
|
|
43
|
+
protocol?: string;
|
|
44
|
+
secure?: boolean;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Generic response interface.
|
|
48
|
+
*/
|
|
49
|
+
export interface HttpResponseHeaders {
|
|
50
|
+
[key: string]: string | string[] | undefined;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Generic response interface.
|
|
54
|
+
*/
|
|
55
|
+
export interface HttpResponseWriter {
|
|
56
|
+
statusCode: number;
|
|
57
|
+
headersSent: boolean;
|
|
58
|
+
setHeader(name: string, value: string | string[]): void;
|
|
59
|
+
getHeader(name: string): string | string[] | undefined;
|
|
60
|
+
removeHeader(name: string): void;
|
|
61
|
+
status(code: number): this;
|
|
62
|
+
send(body?: any): this;
|
|
63
|
+
end(): void;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Server-Sent Event emitter interface.
|
|
67
|
+
*/
|
|
68
|
+
export interface SseEmitterInterface {
|
|
69
|
+
send(data: any): void;
|
|
70
|
+
emit(event: string, data: any): void;
|
|
71
|
+
comment(text: string): void;
|
|
72
|
+
close(): void;
|
|
73
|
+
isClosed(): boolean;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Stream writer interface.
|
|
77
|
+
*/
|
|
78
|
+
export interface StreamWriterInterface {
|
|
79
|
+
write(data: string | Buffer): boolean;
|
|
80
|
+
writeLine(data: string): boolean;
|
|
81
|
+
writeJson(data: any): boolean;
|
|
82
|
+
writeJsonLine(data: any): boolean;
|
|
83
|
+
close(): void;
|
|
84
|
+
isClosed(): boolean;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Request context provided to route handlers.
|
|
88
|
+
*/
|
|
89
|
+
export interface 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> {
|
|
90
|
+
/** Raw request object */
|
|
91
|
+
req: any;
|
|
92
|
+
/** Raw response object */
|
|
93
|
+
res: any;
|
|
94
|
+
/** Parsed request body */
|
|
95
|
+
body: TBody;
|
|
96
|
+
/** Parsed query parameters */
|
|
97
|
+
query: TQuery;
|
|
98
|
+
/** Parsed path parameters */
|
|
99
|
+
params: TParams;
|
|
100
|
+
/** Request headers */
|
|
101
|
+
headers: THeaders;
|
|
102
|
+
/** Uploaded files (when using multipart handling) */
|
|
103
|
+
files: TFiles;
|
|
104
|
+
/**
|
|
105
|
+
* Server-Sent Events emitter for streaming events to client.
|
|
106
|
+
* Only available on routes marked with @Sse decorator.
|
|
107
|
+
*/
|
|
108
|
+
sse?: SseEmitterInterface;
|
|
109
|
+
/**
|
|
110
|
+
* Stream writer for streaming responses.
|
|
111
|
+
* Available on routes marked with @Streaming or @Sse decorator.
|
|
112
|
+
*/
|
|
113
|
+
stream?: StreamWriterInterface;
|
|
114
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,11 @@ export * from "./core/serialization";
|
|
|
12
12
|
export * from "./core/auth";
|
|
13
13
|
export * from "./core/lifecycle";
|
|
14
14
|
export * from "./core/streaming";
|
|
15
|
-
export
|
|
15
|
+
export { createExpressApp, attachControllers as attachExpressControllers, attachOpenApi as attachExpressOpenApi, shutdownApp as shutdownExpressApp } from "./adapter/express/index";
|
|
16
|
+
export type { ExpressAdapterOptions, RequestContext as ExpressRequestContext } from "./adapter/express/index";
|
|
17
|
+
export { createFastifyApp, attachControllers as attachFastifyControllers, attachOpenApi as attachFastifyOpenApi, shutdownApp as shutdownFastifyApp } from "./adapter/fastify/index";
|
|
18
|
+
export type { FastifyAdapterOptions, RequestContext as FastifyRequestContext } from "./adapter/fastify/index";
|
|
19
|
+
export { createNativeApp, attachControllers as attachNativeControllers, attachOpenApi as attachNativeOpenApi, shutdownApp as shutdownNativeApp } from "./adapter/native/index";
|
|
20
|
+
export type { NativeAdapterOptions, RequestContext as NativeRequestContext, NativeApp } from "./adapter/native/index";
|
|
16
21
|
export * from "./adapter/metal-orm/index";
|
|
17
22
|
export * from "./core/types";
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.shutdownNativeApp = exports.attachNativeOpenApi = exports.attachNativeControllers = exports.createNativeApp = exports.shutdownFastifyApp = exports.attachFastifyOpenApi = exports.attachFastifyControllers = exports.createFastifyApp = exports.shutdownExpressApp = exports.attachExpressOpenApi = exports.attachExpressControllers = exports.createExpressApp = void 0;
|
|
17
18
|
__exportStar(require("./core/decorators"), exports);
|
|
18
19
|
__exportStar(require("./core/schema"), exports);
|
|
19
20
|
__exportStar(require("./core/openapi"), exports);
|
|
@@ -28,6 +29,20 @@ __exportStar(require("./core/serialization"), exports);
|
|
|
28
29
|
__exportStar(require("./core/auth"), exports);
|
|
29
30
|
__exportStar(require("./core/lifecycle"), exports);
|
|
30
31
|
__exportStar(require("./core/streaming"), exports);
|
|
31
|
-
|
|
32
|
+
var index_1 = require("./adapter/express/index");
|
|
33
|
+
Object.defineProperty(exports, "createExpressApp", { enumerable: true, get: function () { return index_1.createExpressApp; } });
|
|
34
|
+
Object.defineProperty(exports, "attachExpressControllers", { enumerable: true, get: function () { return index_1.attachControllers; } });
|
|
35
|
+
Object.defineProperty(exports, "attachExpressOpenApi", { enumerable: true, get: function () { return index_1.attachOpenApi; } });
|
|
36
|
+
Object.defineProperty(exports, "shutdownExpressApp", { enumerable: true, get: function () { return index_1.shutdownApp; } });
|
|
37
|
+
var index_2 = require("./adapter/fastify/index");
|
|
38
|
+
Object.defineProperty(exports, "createFastifyApp", { enumerable: true, get: function () { return index_2.createFastifyApp; } });
|
|
39
|
+
Object.defineProperty(exports, "attachFastifyControllers", { enumerable: true, get: function () { return index_2.attachControllers; } });
|
|
40
|
+
Object.defineProperty(exports, "attachFastifyOpenApi", { enumerable: true, get: function () { return index_2.attachOpenApi; } });
|
|
41
|
+
Object.defineProperty(exports, "shutdownFastifyApp", { enumerable: true, get: function () { return index_2.shutdownApp; } });
|
|
42
|
+
var index_3 = require("./adapter/native/index");
|
|
43
|
+
Object.defineProperty(exports, "createNativeApp", { enumerable: true, get: function () { return index_3.createNativeApp; } });
|
|
44
|
+
Object.defineProperty(exports, "attachNativeControllers", { enumerable: true, get: function () { return index_3.attachControllers; } });
|
|
45
|
+
Object.defineProperty(exports, "attachNativeOpenApi", { enumerable: true, get: function () { return index_3.attachOpenApi; } });
|
|
46
|
+
Object.defineProperty(exports, "shutdownNativeApp", { enumerable: true, get: function () { return index_3.shutdownApp; } });
|
|
32
47
|
__exportStar(require("./adapter/metal-orm/index"), exports);
|
|
33
48
|
__exportStar(require("./core/types"), exports);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createFastifyApp } from "../../src";
|
|
2
|
+
import { UserController } from "../basic/user.controller";
|
|
3
|
+
|
|
4
|
+
export async function createApp() {
|
|
5
|
+
const app = await createFastifyApp({
|
|
6
|
+
controllers: [UserController],
|
|
7
|
+
openApi: {
|
|
8
|
+
info: {
|
|
9
|
+
title: "Adorn API (Fastify)",
|
|
10
|
+
version: "1.0.0"
|
|
11
|
+
},
|
|
12
|
+
docs: true
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
return app;
|
|
16
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createApp } from "./app";
|
|
2
|
+
|
|
3
|
+
async function start() {
|
|
4
|
+
const app = await createApp();
|
|
5
|
+
const PORT = 3000;
|
|
6
|
+
|
|
7
|
+
app.listen({ port: PORT }, (err, address) => {
|
|
8
|
+
if (err) {
|
|
9
|
+
console.error(err);
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
console.log(`Server running at ${address}`);
|
|
13
|
+
console.log(`OpenAPI documentation: ${address}/openapi.json`);
|
|
14
|
+
console.log(`Swagger UI: ${address}/docs`);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
start().catch(error => {
|
|
19
|
+
console.error("Failed to start server:", error);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
});
|
package/package.json
CHANGED
|
@@ -1,37 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adorn-api",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.13",
|
|
4
4
|
"description": "Decorator-first web framework with OpenAPI 3.1 schema generation.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "tsc -p tsconfig.json",
|
|
9
|
+
"pretest": "npm run build",
|
|
9
10
|
"dev": "tsx examples/basic/index.ts",
|
|
10
11
|
"test": "vitest run",
|
|
11
12
|
"test:watch": "vitest",
|
|
13
|
+
"typecheck:tests": "tsc -p tsconfig.typecheck.json --noEmit",
|
|
12
14
|
"example": "node scripts/run-example.js",
|
|
13
15
|
"check": "tsc -p tsconfig.json --noEmit && npm test",
|
|
14
16
|
"lint": "eslint . --ext .ts,.tsx,.js"
|
|
15
17
|
},
|
|
16
18
|
"dependencies": {
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
+
"@fastify/cors": "^11.2.0",
|
|
20
|
+
"@fastify/multipart": "^9.4.0",
|
|
21
|
+
"express": "^5.2.1",
|
|
22
|
+
"fastify": "^5.8.4",
|
|
23
|
+
"metal-orm": "^1.1.10"
|
|
19
24
|
},
|
|
20
25
|
"devDependencies": {
|
|
21
|
-
"@electric-sql/pglite": "^0.
|
|
22
|
-
"@types/express": "^
|
|
23
|
-
"@types/
|
|
24
|
-
"@types/
|
|
25
|
-
"@
|
|
26
|
-
"@typescript-eslint/
|
|
27
|
-
"@
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
26
|
+
"@electric-sql/pglite": "^0.4.2",
|
|
27
|
+
"@types/express": "^5.0.6",
|
|
28
|
+
"@types/node": "^25.5.0",
|
|
29
|
+
"@types/sqlite3": "^5.1.0",
|
|
30
|
+
"@types/supertest": "^7.2.0",
|
|
31
|
+
"@typescript-eslint/eslint-plugin": "^8.58.0",
|
|
32
|
+
"@typescript-eslint/parser": "^8.58.0",
|
|
33
|
+
"@vitest/mocker": "^4.1.2",
|
|
34
|
+
"eslint": "^10.1.0",
|
|
35
|
+
"sqlite3": "^6.0.1",
|
|
36
|
+
"supertest": "^7.2.2",
|
|
37
|
+
"tedious": "^19.2.1",
|
|
38
|
+
"tsx": "^4.21.0",
|
|
39
|
+
"typescript": "^6.0.2",
|
|
40
|
+
"vite": "^8.0.3",
|
|
41
|
+
"vitest": "^4.1.2"
|
|
36
42
|
}
|
|
37
43
|
}
|