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 +248 -4
- package/dist/adapter/metal-orm/crud-dtos.js +1 -1
- package/dist/adapter/metal-orm/error-dtos.js +1 -1
- package/dist/core/metadata.js +6 -0
- package/package.json +1 -1
- package/src/adapter/metal-orm/crud-dtos.ts +2 -2
- package/src/adapter/metal-orm/error-dtos.ts +1 -1
- package/src/adapter/metal-orm/filters.ts +1 -1
- package/src/adapter/metal-orm/paged-dtos.ts +1 -1
- package/src/adapter/metal-orm/pagination.ts +1 -1
- package/src/adapter/metal-orm/types.ts +1 -1
- package/src/core/metadata.ts +7 -0
- package/vitest.config.ts +14 -8
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
|
-
"
|
|
389
|
-
"
|
|
390
|
-
"
|
|
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)()];
|
package/dist/core/metadata.js
CHANGED
|
@@ -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,4 +1,4 @@
|
|
|
1
|
-
|
|
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,6 +1,6 @@
|
|
|
1
1
|
import { Dto, Field } from "../../core/decorators";
|
|
2
2
|
import type { DtoConstructor } from "../../core/types";
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import { t } from "../../core/schema";
|
|
5
5
|
import type { FieldMeta } from "../../core/metadata";
|
|
6
6
|
import { registerDto } from "../../core/metadata";
|
package/src/core/metadata.ts
CHANGED
|
@@ -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
|
+
});
|