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.
Files changed (75) hide show
  1. package/README.md +18 -0
  2. package/dist/adapter/express/types.d.ts +3 -46
  3. package/dist/adapter/fastify/coercion.d.ts +12 -0
  4. package/dist/adapter/fastify/coercion.js +289 -0
  5. package/dist/adapter/fastify/controllers.d.ts +7 -0
  6. package/dist/adapter/fastify/controllers.js +201 -0
  7. package/dist/adapter/fastify/index.d.ts +14 -0
  8. package/dist/adapter/fastify/index.js +67 -0
  9. package/dist/adapter/fastify/multipart.d.ts +26 -0
  10. package/dist/adapter/fastify/multipart.js +75 -0
  11. package/dist/adapter/fastify/openapi.d.ts +10 -0
  12. package/dist/adapter/fastify/openapi.js +76 -0
  13. package/dist/adapter/fastify/response-serializer.d.ts +2 -0
  14. package/dist/adapter/fastify/response-serializer.js +162 -0
  15. package/dist/adapter/fastify/types.d.ts +100 -0
  16. package/dist/adapter/fastify/types.js +2 -0
  17. package/dist/adapter/metal-orm/index.d.ts +1 -1
  18. package/dist/adapter/metal-orm/types.d.ts +23 -0
  19. package/dist/adapter/native/coercion.d.ts +12 -0
  20. package/dist/adapter/native/coercion.js +289 -0
  21. package/dist/adapter/native/controllers.d.ts +17 -0
  22. package/dist/adapter/native/controllers.js +215 -0
  23. package/dist/adapter/native/index.d.ts +14 -0
  24. package/dist/adapter/native/index.js +127 -0
  25. package/dist/adapter/native/openapi.d.ts +7 -0
  26. package/dist/adapter/native/openapi.js +82 -0
  27. package/dist/adapter/native/response-serializer.d.ts +5 -0
  28. package/dist/adapter/native/response-serializer.js +160 -0
  29. package/dist/adapter/native/router.d.ts +25 -0
  30. package/dist/adapter/native/router.js +68 -0
  31. package/dist/adapter/native/types.d.ts +77 -0
  32. package/dist/adapter/native/types.js +2 -0
  33. package/dist/core/auth.d.ts +11 -12
  34. package/dist/core/auth.js +2 -2
  35. package/dist/core/logger.d.ts +3 -4
  36. package/dist/core/logger.js +2 -2
  37. package/dist/core/streaming.d.ts +10 -10
  38. package/dist/core/streaming.js +31 -19
  39. package/dist/core/types.d.ts +102 -0
  40. package/dist/index.d.ts +6 -1
  41. package/dist/index.js +16 -1
  42. package/examples/fastify/app.ts +16 -0
  43. package/examples/fastify/index.ts +21 -0
  44. package/package.json +24 -18
  45. package/src/adapter/express/controllers.ts +249 -249
  46. package/src/adapter/express/types.ts +121 -160
  47. package/src/adapter/fastify/coercion.ts +369 -0
  48. package/src/adapter/fastify/controllers.ts +255 -0
  49. package/src/adapter/fastify/index.ts +53 -0
  50. package/src/adapter/fastify/multipart.ts +94 -0
  51. package/src/adapter/fastify/openapi.ts +93 -0
  52. package/src/adapter/fastify/response-serializer.ts +179 -0
  53. package/src/adapter/fastify/types.ts +119 -0
  54. package/src/adapter/metal-orm/index.ts +3 -0
  55. package/src/adapter/metal-orm/types.ts +25 -0
  56. package/src/adapter/native/coercion.ts +369 -0
  57. package/src/adapter/native/controllers.ts +271 -0
  58. package/src/adapter/native/index.ts +116 -0
  59. package/src/adapter/native/openapi.ts +109 -0
  60. package/src/adapter/native/response-serializer.ts +177 -0
  61. package/src/adapter/native/router.ts +90 -0
  62. package/src/adapter/native/types.ts +96 -0
  63. package/src/core/auth.ts +314 -315
  64. package/src/core/health.ts +234 -235
  65. package/src/core/logger.ts +245 -247
  66. package/src/core/streaming.ts +342 -330
  67. package/src/core/types.ts +115 -0
  68. package/src/index.ts +46 -16
  69. package/tests/e2e/fastify.e2e.test.ts +174 -0
  70. package/tests/native.test.ts +191 -0
  71. package/tests/typecheck/query-params.typecheck.ts +42 -0
  72. package/tests/unit/openapi-parameters.test.ts +97 -97
  73. package/tsconfig.json +14 -13
  74. package/tsconfig.typecheck.json +8 -0
  75. package/vitest.config.ts +47 -7
@@ -20,9 +20,11 @@ class SseEmitter {
20
20
  if (keepAlive) {
21
21
  this.startKeepAlive(keepAliveInterval);
22
22
  }
23
- res.on("close", () => {
24
- this.close();
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("Content-Type", "text/event-stream");
77
- this.res.setHeader("Cache-Control", "no-cache, no-transform");
78
- this.res.setHeader("Connection", "keep-alive");
79
- this.res.setHeader("X-Accel-Buffering", "no");
80
- this.res.flushHeaders();
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("close", () => {
139
- this.closed = true;
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("Content-Type", contentType);
190
- this.res.setHeader("Transfer-Encoding", "chunked");
191
- this.res.setHeader("Cache-Control", "no-cache, no-transform");
192
- this.res.setHeader("X-Accel-Buffering", "no");
193
- if (options.headers) {
194
- for (const [key, value] of Object.entries(options.headers)) {
195
- this.res.setHeader(key, value);
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;
@@ -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 * from "./adapter/express/index";
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
- __exportStar(require("./adapter/express/index"), exports);
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.11",
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
- "express": "^4.19.2",
18
- "metal-orm": "^1.1.2"
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.3.15",
22
- "@types/express": "^4.17.21",
23
- "@types/sqlite3": "^3.1.11",
24
- "@types/supertest": "^2.0.16",
25
- "@typescript-eslint/eslint-plugin": "^8.53.0",
26
- "@typescript-eslint/parser": "^8.53.0",
27
- "@vitest/mocker": "^4.0.18",
28
- "eslint": "^8.57.1",
29
- "sqlite3": "^5.1.7",
30
- "supertest": "^6.3.4",
31
- "tedious": "^19.0.0",
32
- "tsx": "^4.7.0",
33
- "typescript": "^5.4.5",
34
- "vite": "^7.3.1",
35
- "vitest": "^4.0.18"
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
  }