adorn-api 1.0.5 → 1.0.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 CHANGED
@@ -272,7 +272,7 @@ Database-driven API using Metal ORM entities. See: `examples/blog-platform-metal
272
272
 
273
273
  ```typescript
274
274
  import { Controller, Get, Post, Put, Delete } from "adorn-api";
275
- import { Post as PostEntity } from "../entities/index.js";
275
+ import { BlogPost } from "../entities/index.js";
276
276
  import { getSession, selectFromEntity, eq } from "metal-orm";
277
277
 
278
278
  @Controller("/posts")
@@ -280,9 +280,9 @@ export class PostsController {
280
280
  @Get("/")
281
281
  async getPosts(query?: { authorId?: number; status?: string }) {
282
282
  const session = getSession();
283
- let qb = selectFromEntity(PostEntity);
284
- if (query?.authorId) qb = qb.where(eq(PostEntity.authorId, query.authorId));
285
- if (query?.status) qb = qb.where(eq(PostEntity.status, query.status));
283
+ let qb = selectFromEntity(BlogPost);
284
+ if (query?.authorId) qb = qb.where(eq(BlogPost.authorId, query.authorId));
285
+ if (query?.status) qb = qb.where(eq(BlogPost.status, query.status));
286
286
  return qb.execute(session);
287
287
  }
288
288
 
@@ -290,9 +290,9 @@ export class PostsController {
290
290
  async getPost(id: number) { /* ... */ }
291
291
 
292
292
  @Post("/")
293
- async createPost(body: Pick<PostEntity, "title" | "content" | "authorId">) {
293
+ async createPost(body: Pick<BlogPost, "title" | "content" | "authorId">) {
294
294
  const session = getSession();
295
- const post = new PostEntity();
295
+ const post = new BlogPost();
296
296
  Object.assign(post, body);
297
297
  await session.persist(post);
298
298
  await session.flush();
@@ -300,7 +300,7 @@ export class PostsController {
300
300
  }
301
301
 
302
302
  @Put("/:id")
303
- async updatePost(id: number, body: Partial<PostEntity>) { /* ... */ }
303
+ async updatePost(id: number, body: Partial<BlogPost>) { /* ... */ }
304
304
 
305
305
  @Delete("/:id")
306
306
  async deletePost(id: number) { return { success: true }; }
@@ -652,6 +652,7 @@ await bootstrap({
652
652
  swaggerJsonPath?: string, // Default: "/docs/openapi.json"
653
653
  middleware?: CreateRouterOptions["middleware"],
654
654
  auth?: CreateRouterOptions["auth"],
655
+ coerce?: CreateRouterOptions["coerce"],
655
656
  });
656
657
  ```
657
658
 
@@ -672,6 +673,15 @@ const router = await createExpressRouter({
672
673
  auth?: {
673
674
  schemes: Record<string, AuthSchemeRuntime>,
674
675
  },
676
+ coerce?: {
677
+ body?: boolean,
678
+ query?: boolean,
679
+ path?: boolean,
680
+ header?: boolean,
681
+ cookie?: boolean,
682
+ dateTime?: boolean,
683
+ date?: boolean,
684
+ },
675
685
  middleware?: {
676
686
  global?: Middleware[],
677
687
  named?: Record<string, Middleware>,
@@ -679,6 +689,8 @@ const router = await createExpressRouter({
679
689
  });
680
690
  ```
681
691
 
692
+ Date properties in TypeScript map to OpenAPI `type: "string"` with `format: "date-time"`. Enable `coerce` to convert ISO 8601 date-time strings into `Date` instances before your handler runs. For date-only strings, use `@Format("date")` and keep `date` coercion off to avoid timezone shifts. You can disable per-field coercion with `@Schema({ "x-adorn-coerce": false })`.
693
+
682
694
  ### setupSwagger()
683
695
 
684
696
  Add Swagger UI to any Express app:
@@ -11,6 +11,7 @@ export interface BootstrapOptions {
11
11
  swaggerJsonPath?: string;
12
12
  middleware?: CreateRouterOptions["middleware"];
13
13
  auth?: CreateRouterOptions["auth"];
14
+ coerce?: CreateRouterOptions["coerce"];
14
15
  }
15
16
  export interface BootstrapResult {
16
17
  server: Server;
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../src/adapter/express/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,EAAuB,KAAK,mBAAmB,EAA0C,MAAM,YAAY,CAAC;AAGnH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,KAAK,CAAC,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,mBAAmB,CAAC,YAAY,CAAC,CAAC;IAC/C,IAAI,CAAC,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAqG7E"}
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../src/adapter/express/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,EAAuB,KAAK,mBAAmB,EAA0C,MAAM,YAAY,CAAC;AAGnH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,KAAK,CAAC,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,mBAAmB,CAAC,YAAY,CAAC,CAAC;IAC/C,IAAI,CAAC,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACnC,MAAM,CAAC,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAuG7E"}
@@ -7,8 +7,18 @@ interface OpenAPI31 {
7
7
  schemas: Record<string, Record<string, unknown>>;
8
8
  securitySchemes?: Record<string, Record<string, unknown>>;
9
9
  };
10
+ paths?: Record<string, Record<string, any>>;
10
11
  security?: Array<Record<string, string[]>>;
11
12
  }
13
+ export interface CoerceOptions {
14
+ body?: boolean;
15
+ query?: boolean;
16
+ path?: boolean;
17
+ header?: boolean;
18
+ cookie?: boolean;
19
+ dateTime?: boolean;
20
+ date?: boolean;
21
+ }
12
22
  export interface CreateRouterOptions {
13
23
  controllers: Array<new (...args: any[]) => any>;
14
24
  artifactsDir?: string;
@@ -17,6 +27,7 @@ export interface CreateRouterOptions {
17
27
  auth?: {
18
28
  schemes: Record<string, AuthSchemeRuntime>;
19
29
  };
30
+ coerce?: CoerceOptions;
20
31
  middleware?: {
21
32
  global?: Array<string | ((req: any, res: any, next: (err?: any) => void) => any)>;
22
33
  named?: Record<string, (req: any, res: any, next: (err?: any) => void) => any>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapter/express/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAIjC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAGpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAIvE,UAAU,SAAS;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE;QACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;QACjD,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;KAC3D,CAAC;IACF,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;CAC5C;AAMD,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,KAAK,CAAC,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,CAAC;IAChD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE;QACL,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;KAC5C,CAAC;IACF,UAAU,CAAC,EAAE;QACX,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;QAClF,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,IAAI,KAAK,GAAG,CAAC,CAAC;KAChF,CAAC;CACH;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE;QACf,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,KAAK,CAAC;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACvD,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;CACH;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CA8OvF;AA8PD,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElE,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,MAAM,CA4BtE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapter/express/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAIjC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAGpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAIvE,UAAU,SAAS;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE;QACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;QACjD,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;KAC3D,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAC5C,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;CAC5C;AAMD,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,KAAK,CAAC,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,CAAC;IAChD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE;QACL,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;KAC5C,CAAC;IACF,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,UAAU,CAAC,EAAE;QACX,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;QAClF,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,IAAI,KAAK,GAAG,CAAC,CAAC;KAChF,CAAC;CACH;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE;QACf,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,KAAK,CAAC;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACvD,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;CACH;AAcD,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmRvF;AAwdD,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElE,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,MAAM,CA4BtE"}
package/dist/cli.cjs CHANGED
@@ -315,6 +315,9 @@ function typeToJsonSchema(type, ctx, typeNode) {
315
315
  if (type.flags & import_typescript3.default.TypeFlags.Null) {
316
316
  return { type: "null" };
317
317
  }
318
+ if (isDateType(type, checker)) {
319
+ return { type: "string", format: "date-time" };
320
+ }
318
321
  if (type.flags & import_typescript3.default.TypeFlags.String) {
319
322
  return { type: "string" };
320
323
  }
@@ -364,6 +367,19 @@ function typeToJsonSchema(type, ctx, typeNode) {
364
367
  }
365
368
  return {};
366
369
  }
370
+ function isDateType(type, checker) {
371
+ const symbol = type.getSymbol();
372
+ const aliasSymbol = type.aliasSymbol;
373
+ if (aliasSymbol && aliasSymbol.flags & import_typescript3.default.SymbolFlags.Alias) {
374
+ const aliased = checker.getAliasedSymbol(aliasSymbol);
375
+ return aliased?.getName() === "Date";
376
+ }
377
+ if (symbol && symbol.flags & import_typescript3.default.SymbolFlags.Alias) {
378
+ const aliased = checker.getAliasedSymbol(symbol);
379
+ return aliased?.getName() === "Date";
380
+ }
381
+ return symbol?.getName() === "Date";
382
+ }
367
383
  function isSetType(type, checker) {
368
384
  const symbol = type.getSymbol();
369
385
  if (!symbol) return false;