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 +19 -7
- package/dist/adapter/express/bootstrap.d.ts +1 -0
- package/dist/adapter/express/bootstrap.d.ts.map +1 -1
- package/dist/adapter/express/index.d.ts +11 -0
- package/dist/adapter/express/index.d.ts.map +1 -1
- package/dist/cli.cjs +16 -0
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +16 -0
- package/dist/cli.js.map +1 -1
- package/dist/compiler/schema/typeToJsonSchema.d.ts.map +1 -1
- package/dist/express.cjs +231 -47
- package/dist/express.cjs.map +1 -1
- package/dist/express.js +231 -47
- package/dist/express.js.map +1 -1
- package/package.json +4 -4
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 {
|
|
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(
|
|
284
|
-
if (query?.authorId) qb = qb.where(eq(
|
|
285
|
-
if (query?.status) qb = qb.where(eq(
|
|
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<
|
|
293
|
+
async createPost(body: Pick<BlogPost, "title" | "content" | "authorId">) {
|
|
294
294
|
const session = getSession();
|
|
295
|
-
const post = new
|
|
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<
|
|
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:
|
|
@@ -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;
|
|
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;
|
|
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;
|