adorn-api 1.0.25 → 1.0.27

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
@@ -21,6 +21,138 @@ Decorator-first web framework for TypeScript with OpenAPI 3.1 schema generation.
21
21
  npm install adorn-api express metal-orm
22
22
  ```
23
23
 
24
+ ## Project Setup
25
+
26
+ Create a minimal `package.json` for your project:
27
+
28
+ ```json
29
+ {
30
+ "name": "my-api",
31
+ "version": "1.0.0",
32
+ "type": "module",
33
+ "scripts": {
34
+ "start": "node dist/index.js",
35
+ "dev": "tsx src/index.ts",
36
+ "build": "tsc"
37
+ },
38
+ "dependencies": {
39
+ "adorn-api": "^1.0.25",
40
+ "express": "^4.19.2"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^20.11.0",
44
+ "tsx": "^4.7.0",
45
+ "typescript": "^5.4.5"
46
+ }
47
+ }
48
+ ```
49
+
50
+ **Dependencies explained:**
51
+ - `adorn-api` - The main framework
52
+ - `express` - HTTP server (required)
53
+ - `tsx` - TypeScript execution for development
54
+ - `typescript` - TypeScript compiler
55
+
56
+ **Scripts explained:**
57
+ - `npm run dev` - Run in development mode with hot reload
58
+ - `npm run build` - Compile TypeScript to JavaScript
59
+ - `npm start` - Run the compiled application
60
+
61
+ ## Getting Started
62
+
63
+ Follow these steps to set up a new project from scratch:
64
+
65
+ ### 1. Create your project directory
66
+
67
+ ```bash
68
+ mkdir my-api
69
+ cd my-api
70
+ ```
71
+
72
+ ### 2. Initialize npm
73
+
74
+ ```bash
75
+ npm init -y
76
+ ```
77
+
78
+ ### 3. Install dependencies
79
+
80
+ ```bash
81
+ npm install adorn-api express
82
+ npm install -D tsx typescript @types/node
83
+ ```
84
+
85
+ ### 4. Create `tsconfig.json`
86
+
87
+ ```json
88
+ {
89
+ "compilerOptions": {
90
+ "target": "ES2022",
91
+ "module": "NodeNext",
92
+ "moduleResolution": "NodeNext",
93
+ "outDir": "./dist",
94
+ "rootDir": "./src",
95
+ "strict": true,
96
+ "esModuleInterop": true,
97
+ "skipLibCheck": true,
98
+ "forceConsistentCasingInFileNames": true,
99
+ "useDefineForClassFields": true,
100
+ "experimentalDecorators": false,
101
+ "emitDecoratorMetadata": false
102
+ },
103
+ "include": ["src"]
104
+ }
105
+ ```
106
+
107
+ ### 5. Create `src/index.ts`
108
+
109
+ ```typescript
110
+ import { Controller, Get, Dto, Field, t, createExpressApp } from "adorn-api";
111
+
112
+ @Dto({ description: "User record" })
113
+ class UserDto {
114
+ @Field(t.uuid({ description: "User ID" }))
115
+ id!: string;
116
+
117
+ @Field(t.string({ minLength: 1 }))
118
+ name!: string;
119
+ }
120
+
121
+ @Controller("/users")
122
+ class UserController {
123
+ @Get("/:id")
124
+ @Params(UserDto)
125
+ @Returns(UserDto)
126
+ async getOne(ctx: RequestContext<unknown, undefined, UserDto>) {
127
+ return {
128
+ id: ctx.params.id,
129
+ name: "Ada Lovelace"
130
+ };
131
+ }
132
+ }
133
+
134
+ const app = createExpressApp({
135
+ controllers: [UserController],
136
+ openApi: {
137
+ info: { title: "My API", version: "1.0.0" },
138
+ docs: true
139
+ }
140
+ });
141
+
142
+ app.listen(3000, () => {
143
+ console.log("Server running at http://localhost:3000");
144
+ console.log("API docs at http://localhost:3000/docs");
145
+ });
146
+ ```
147
+
148
+ ### 6. Run your application
149
+
150
+ ```bash
151
+ npm run dev
152
+ ```
153
+
154
+ Visit http://localhost:3000/docs to see your API documentation.
155
+
24
156
  ## Quick Start
25
157
 
26
158
  ```typescript
@@ -378,6 +510,55 @@ npm run lint
378
510
  npm run example basic
379
511
  ```
380
512
 
513
+ ## Common Pitfalls
514
+
515
+ ⚠️ **Important:** Adorn API uses standard ECMAScript decorators (Stage 3), NOT legacy TypeScript decorators.
516
+
517
+ ### ❌ DO NOT use these:
518
+
519
+ ```json
520
+ {
521
+ "compilerOptions": {
522
+ "experimentalDecorators": true, // ❌ WRONG - must be false
523
+ "emitDecoratorMetadata": true // ❌ WRONG - must be false
524
+ }
525
+ }
526
+ ```
527
+
528
+ ```bash
529
+ npm install reflect-metadata # ❌ WRONG - not needed
530
+ tsx -r reflect-metadata src/index.ts # ❌ WRONG - remove -r flag
531
+ ```
532
+
533
+ ### ✅ DO use these:
534
+
535
+ ```json
536
+ {
537
+ "compilerOptions": {
538
+ "experimentalDecorators": false, // ✅ CORRECT
539
+ "emitDecoratorMetadata": false // ✅ CORRECT
540
+ }
541
+ }
542
+ ```
543
+
544
+ ```bash
545
+ tsx src/index.ts # ✅ CORRECT - no reflect-metadata
546
+ ```
547
+
548
+ ### Why?
549
+
550
+ - **Standard ECMAScript decorators** (Stage 3) are the modern, standardized approach
551
+ - **Legacy TypeScript decorators** (`experimentalDecorators`) are deprecated
552
+ - `reflect-metadata` is only needed for legacy decorators
553
+ - TypeScript 5.0+ fully supports standard decorators
554
+
555
+ ### Troubleshooting
556
+
557
+ If you see errors like:
558
+ - `Decorators are not enabled` → Check `experimentalDecorators` is `false`
559
+ - `Cannot find module 'reflect-metadata'` → Remove `reflect-metadata` from dependencies
560
+ - `Decorator metadata not available` → This is expected with standard decorators
561
+
381
562
  ## TypeScript Configuration
382
563
 
383
564
  Ensure your `tsconfig.json` has:
@@ -385,15 +566,78 @@ Ensure your `tsconfig.json` has:
385
566
  ```json
386
567
  {
387
568
  "compilerOptions": {
388
- "experimentalDecorators": false,
389
- "emitDecoratorMetadata": false,
390
- "useDefineForClassFields": true
391
- }
569
+ "target": "ES2022",
570
+ "module": "NodeNext",
571
+ "moduleResolution": "NodeNext",
572
+ "outDir": "./dist",
573
+ "rootDir": "./src",
574
+ "strict": true,
575
+ "esModuleInterop": true,
576
+ "skipLibCheck": true,
577
+ "forceConsistentCasingInFileNames": true,
578
+ "useDefineForClassFields": true,
579
+ "experimentalDecorators": false, // ⚠️ MUST be false
580
+ "emitDecoratorMetadata": false // ⚠️ MUST be false
581
+ },
582
+ "include": ["src"]
392
583
  }
393
584
  ```
394
585
 
586
+ **Critical settings:**
587
+ - `experimentalDecorators: false` - Use standard ECMAScript decorators
588
+ - `emitDecoratorMetadata: false` - Not needed with standard decorators
589
+ - `useDefineForClassFields: true` - Required for standard decorators
590
+
395
591
  Adorn API uses standard ECMAScript decorators (Stage 3).
396
592
 
593
+ ## Quick Reference
594
+
595
+ ### Setup Checklist
596
+
597
+ - [ ] Initialize project: `npm init -y`
598
+ - [ ] Install dependencies: `npm install adorn-api express`
599
+ - [ ] Install dev dependencies: `npm install -D tsx typescript @types/node`
600
+ - [ ] Create `tsconfig.json` with correct decorator settings
601
+ - [ ] Create `src/index.ts` with your controllers
602
+ - [ ] Run: `npm run dev`
603
+
604
+ ### Common Commands
605
+
606
+ ```bash
607
+ # Development
608
+ npm run dev # Run with hot reload
609
+ npm run build # Compile TypeScript
610
+ npm start # Run compiled app
611
+
612
+ # Testing
613
+ npm test # Run tests
614
+ npm run test:watch # Run tests in watch mode
615
+
616
+ # Code Quality
617
+ npm run lint # Run ESLint
618
+ ```
619
+
620
+ ### Project Structure
621
+
622
+ ```
623
+ my-api/
624
+ ├── src/
625
+ │ └── index.ts # Main entry point
626
+ ├── dist/ # Compiled JavaScript (generated)
627
+ ├── node_modules/
628
+ ├── package.json
629
+ └── tsconfig.json
630
+ ```
631
+
632
+ ### Troubleshooting
633
+
634
+ | Issue | Solution |
635
+ |-------|----------|
636
+ | Decorators not working | Check `experimentalDecorators: false` in tsconfig.json |
637
+ | reflect-metadata errors | Remove `reflect-metadata` from package.json and scripts |
638
+ | Module not found | Ensure `moduleResolution: "NodeNext"` in tsconfig.json |
639
+ | Type errors | Run `npm run build` to see full TypeScript errors |
640
+
397
641
  ## License
398
642
 
399
643
  Check the package for license information.
@@ -83,7 +83,7 @@ function createMetalCrudDtoClasses(target, options = {}) {
83
83
  return classes;
84
84
  }
85
85
  function createNestedCreateDtoClass(target, overrides, options) {
86
- const { additionalExclude, name, parentEntity, ...metalDtoOptions } = options;
86
+ const { additionalExclude, name, parentEntity: _parentEntity, ...metalDtoOptions } = options;
87
87
  const allExcludes = mergeStringArrays(["id", "createdAt"], additionalExclude, metalDtoOptions.exclude);
88
88
  let NestedCreateDto = (() => {
89
89
  let _classDecorators = [(0, dto_1.MetalDto)(target, {
@@ -39,7 +39,7 @@ exports.createErrorDtoClass = createErrorDtoClass;
39
39
  const decorators_1 = require("../../core/decorators");
40
40
  const schema_1 = require("../../core/schema");
41
41
  function createErrorDtoClass(options = {}) {
42
- const { withDetails = true, includeTraceId = true } = options;
42
+ const { withDetails = true, includeTraceId: _includeTraceId = true } = options;
43
43
  if (withDetails) {
44
44
  let ErrorDetailDto = (() => {
45
45
  let _classDecorators = [(0, decorators_1.Dto)()];
@@ -12,6 +12,12 @@ const dtoStore = new Map();
12
12
  const controllerStore = new Map();
13
13
  exports.META_KEY = Symbol.for("adorn.metadata");
14
14
  function getAdornMetadata(metadata) {
15
+ // Handle case where metadata is undefined (when Symbol.metadata is not available)
16
+ if (!metadata) {
17
+ const temp = {};
18
+ temp[exports.META_KEY] = {};
19
+ return temp[exports.META_KEY];
20
+ }
15
21
  if (!metadata[exports.META_KEY]) {
16
22
  metadata[exports.META_KEY] = {};
17
23
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adorn-api",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
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",
@@ -1,4 +1,4 @@
1
- import { Dto } from "../../core/decorators";
1
+
2
2
  import type { DtoConstructor } from "../../core/types";
3
3
  import { MetalDto } from "./dto";
4
4
  import type {
@@ -70,7 +70,7 @@ export function createNestedCreateDtoClass(
70
70
  overrides: Record<string, any>,
71
71
  options: NestedCreateDtoOptions
72
72
  ): DtoConstructor {
73
- const { additionalExclude, name, parentEntity, ...metalDtoOptions } = options;
73
+ const { additionalExclude, name, parentEntity: _parentEntity, ...metalDtoOptions } = options;
74
74
 
75
75
  const allExcludes = mergeStringArrays(
76
76
  ["id", "createdAt"],
@@ -4,7 +4,7 @@ import type { ErrorDtoOptions } from "./types";
4
4
  import { t } from "../../core/schema";
5
5
 
6
6
  export function createErrorDtoClass(options: ErrorDtoOptions = {}): DtoConstructor {
7
- const { withDetails = true, includeTraceId = true } = options;
7
+ const { withDetails = true, includeTraceId: _includeTraceId = true } = options;
8
8
 
9
9
  if (withDetails) {
10
10
  @Dto()
@@ -1,4 +1,4 @@
1
- import type { Filter, FilterMapping, ParseFilterOptions } from "./types";
1
+ import type { Filter } from "./types";
2
2
 
3
3
  /**
4
4
  * Parses filter parameters from query parameters.
@@ -1,6 +1,6 @@
1
1
  import { Dto, Field } from "../../core/decorators";
2
2
  import type { DtoConstructor } from "../../core/types";
3
- import type { SchemaNode } from "../../core/schema";
3
+
4
4
  import { t } from "../../core/schema";
5
5
  import type { FieldMeta } from "../../core/metadata";
6
6
  import { registerDto } from "../../core/metadata";
@@ -1,4 +1,4 @@
1
- import type { PaginationConfig, PaginationOptions, ParsedPagination } from "./types";
1
+ import type { PaginationConfig, ParsedPagination } from "./types";
2
2
  import { coerce } from "../../core/coerce";
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import type { ColumnDef } from "metal-orm";
1
+
2
2
  import type { DtoOptions, FieldOverride } from "../../core/decorators";
3
3
  import type { SchemaNode } from "../../core/schema";
4
4
  import type { DtoConstructor } from "../../core/types";
@@ -79,6 +79,13 @@ export interface RouteMetaInput extends Partial<RouteMeta> {
79
79
  }
80
80
 
81
81
  export function getAdornMetadata(metadata: DecoratorMetadata): AdornMetadata {
82
+ // Handle case where metadata is undefined (when Symbol.metadata is not available)
83
+ if (!metadata) {
84
+ const temp: any = {};
85
+ temp[META_KEY] = {};
86
+ return temp[META_KEY];
87
+ }
88
+
82
89
  if (!metadata[META_KEY]) {
83
90
  metadata[META_KEY] = {};
84
91
  }
package/vitest.config.ts CHANGED
@@ -1,8 +1,14 @@
1
- import { defineConfig } from "vitest/config";
2
-
3
- export default defineConfig({
4
- test: {
5
- environment: "node",
6
- include: ["src/**/*.test.ts"]
7
- }
8
- });
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ environment: "node",
6
+ include: ["src/**/*.test.ts"],
7
+ pool: "forks",
8
+ poolOptions: {
9
+ forks: {
10
+ singleFork: true
11
+ }
12
+ }
13
+ }
14
+ });