azurajs 2.0.0 → 2.1.0
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 +12 -23
- package/package.json +86 -36
- package/src/infra/Router.ts +19 -11
- package/src/infra/Server.ts +7 -7
- package/src/infra/index.ts +3 -0
- package/src/shared/config/index.ts +2 -0
- package/src/shared/plugins/index.ts +2 -0
- package/src/types/index.ts +5 -0
- package/src/utils/Parser.ts +20 -8
- package/src/utils/cookies/index.ts +2 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/validators/index.ts +2 -0
package/README.md
CHANGED
|
@@ -67,7 +67,7 @@ import { Router } from "azurajs/router";
|
|
|
67
67
|
### 1. Create `azura.config.ts`
|
|
68
68
|
|
|
69
69
|
```typescript
|
|
70
|
-
import type { ConfigTypes } from "azurajs";
|
|
70
|
+
import type { ConfigTypes } from "azurajs/config";
|
|
71
71
|
|
|
72
72
|
const config: ConfigTypes = {
|
|
73
73
|
environment: "development",
|
|
@@ -100,19 +100,10 @@ export default config;
|
|
|
100
100
|
### 2. Create your server
|
|
101
101
|
|
|
102
102
|
```typescript
|
|
103
|
-
import {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
Post,
|
|
108
|
-
Body,
|
|
109
|
-
Param,
|
|
110
|
-
Query,
|
|
111
|
-
Res,
|
|
112
|
-
applyDecorators,
|
|
113
|
-
createLoggingMiddleware
|
|
114
|
-
} from "azurajs";
|
|
115
|
-
import type { ResponseServer } from "azurajs";
|
|
103
|
+
import { AzuraClient, applyDecorators } from "azurajs";
|
|
104
|
+
import { Controller, Get, Post, Body, Param, Query, Res } from "azurajs/decorators";
|
|
105
|
+
import { createLoggingMiddleware } from "azurajs/middleware";
|
|
106
|
+
import type { ResponseServer } from "azurajs/types";
|
|
116
107
|
|
|
117
108
|
@Controller("/api")
|
|
118
109
|
class UserController {
|
|
@@ -349,7 +340,7 @@ res.location(url: string)
|
|
|
349
340
|
### Middleware
|
|
350
341
|
|
|
351
342
|
```typescript
|
|
352
|
-
import { createLoggingMiddleware } from "azurajs";
|
|
343
|
+
import { createLoggingMiddleware } from "azurajs/middleware";
|
|
353
344
|
|
|
354
345
|
const app = new AzuraClient();
|
|
355
346
|
|
|
@@ -416,8 +407,9 @@ type ConfigTypes = {
|
|
|
416
407
|
### Complete CRUD API
|
|
417
408
|
|
|
418
409
|
```typescript
|
|
419
|
-
import { AzuraClient,
|
|
420
|
-
import
|
|
410
|
+
import { AzuraClient, applyDecorators } from "azurajs";
|
|
411
|
+
import { Controller, Get, Post, Put, Delete, Body, Param, Res } from "azurajs/decorators";
|
|
412
|
+
import type { ResponseServer } from "azurajs/types";
|
|
421
413
|
|
|
422
414
|
interface User {
|
|
423
415
|
id: number;
|
|
@@ -563,12 +555,9 @@ AzuraJS is designed for high performance:
|
|
|
563
555
|
Full TypeScript support with complete type definitions:
|
|
564
556
|
|
|
565
557
|
```typescript
|
|
566
|
-
import type {
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
ConfigTypes,
|
|
570
|
-
RequestHandler
|
|
571
|
-
} from "azurajs";
|
|
558
|
+
import type { RequestServer, ResponseServer } from "azurajs/types";
|
|
559
|
+
import type { ConfigTypes } from "azurajs/config";
|
|
560
|
+
import type { RequestHandler } from "azurajs/types";
|
|
572
561
|
```
|
|
573
562
|
|
|
574
563
|
> ⚠️ Azura is TypeScript-only.
|
package/package.json
CHANGED
|
@@ -1,86 +1,136 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "azurajs",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Modern TypeScript-first web framework with decorator-based routing, zero dependencies, and built for performance",
|
|
5
|
-
"main": "src/index.ts",
|
|
6
|
-
"module": "src/index.ts",
|
|
7
|
-
"types": "src/index.ts",
|
|
5
|
+
"main": "./src/index.ts",
|
|
6
|
+
"module": "./src/index.ts",
|
|
7
|
+
"types": "./src/index.ts",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
11
|
"types": "./src/index.ts",
|
|
12
12
|
"import": "./src/index.ts",
|
|
13
|
-
"
|
|
13
|
+
"default": "./src/index.ts"
|
|
14
14
|
},
|
|
15
15
|
"./decorators": {
|
|
16
16
|
"types": "./src/decorators/index.ts",
|
|
17
17
|
"import": "./src/decorators/index.ts",
|
|
18
|
-
"
|
|
18
|
+
"default": "./src/decorators/index.ts"
|
|
19
19
|
},
|
|
20
20
|
"./middleware": {
|
|
21
21
|
"types": "./src/middleware/index.ts",
|
|
22
22
|
"import": "./src/middleware/index.ts",
|
|
23
|
-
"
|
|
23
|
+
"default": "./src/middleware/index.ts"
|
|
24
24
|
},
|
|
25
25
|
"./types": {
|
|
26
|
-
"types": "./src/types/
|
|
27
|
-
"import": "./src/types/
|
|
28
|
-
"
|
|
26
|
+
"types": "./src/types/index.ts",
|
|
27
|
+
"import": "./src/types/index.ts",
|
|
28
|
+
"default": "./src/types/index.ts"
|
|
29
|
+
},
|
|
30
|
+
"./infra": {
|
|
31
|
+
"types": "./src/infra/index.ts",
|
|
32
|
+
"import": "./src/infra/index.ts",
|
|
33
|
+
"default": "./src/infra/index.ts"
|
|
29
34
|
},
|
|
30
35
|
"./router": {
|
|
31
36
|
"types": "./src/infra/Router.ts",
|
|
32
37
|
"import": "./src/infra/Router.ts",
|
|
33
|
-
"
|
|
38
|
+
"default": "./src/infra/Router.ts"
|
|
34
39
|
},
|
|
35
40
|
"./config": {
|
|
36
|
-
"types": "./src/shared/config/
|
|
37
|
-
"import": "./src/shared/config/
|
|
38
|
-
"
|
|
41
|
+
"types": "./src/shared/config/index.ts",
|
|
42
|
+
"import": "./src/shared/config/index.ts",
|
|
43
|
+
"default": "./src/shared/config/index.ts"
|
|
44
|
+
},
|
|
45
|
+
"./plugins": {
|
|
46
|
+
"types": "./src/shared/plugins/index.ts",
|
|
47
|
+
"import": "./src/shared/plugins/index.ts",
|
|
48
|
+
"default": "./src/shared/plugins/index.ts"
|
|
39
49
|
},
|
|
40
50
|
"./cors": {
|
|
41
51
|
"types": "./src/shared/plugins/CORSPlugin.ts",
|
|
42
52
|
"import": "./src/shared/plugins/CORSPlugin.ts",
|
|
43
|
-
"
|
|
53
|
+
"default": "./src/shared/plugins/CORSPlugin.ts"
|
|
44
54
|
},
|
|
45
55
|
"./rate-limit": {
|
|
46
56
|
"types": "./src/shared/plugins/RateLimitPlugin.ts",
|
|
47
57
|
"import": "./src/shared/plugins/RateLimitPlugin.ts",
|
|
48
|
-
"
|
|
58
|
+
"default": "./src/shared/plugins/RateLimitPlugin.ts"
|
|
59
|
+
},
|
|
60
|
+
"./utils": {
|
|
61
|
+
"types": "./src/utils/index.ts",
|
|
62
|
+
"import": "./src/utils/index.ts",
|
|
63
|
+
"default": "./src/utils/index.ts"
|
|
49
64
|
},
|
|
50
65
|
"./cookies": {
|
|
51
|
-
"types": "./src/utils/cookies/
|
|
52
|
-
"import": "./src/utils/cookies/
|
|
53
|
-
"
|
|
66
|
+
"types": "./src/utils/cookies/index.ts",
|
|
67
|
+
"import": "./src/utils/cookies/index.ts",
|
|
68
|
+
"default": "./src/utils/cookies/index.ts"
|
|
54
69
|
},
|
|
55
70
|
"./validators": {
|
|
56
|
-
"types": "./src/utils/validators/
|
|
57
|
-
"import": "./src/utils/validators/
|
|
58
|
-
"
|
|
71
|
+
"types": "./src/utils/validators/index.ts",
|
|
72
|
+
"import": "./src/utils/validators/index.ts",
|
|
73
|
+
"default": "./src/utils/validators/index.ts"
|
|
59
74
|
},
|
|
60
75
|
"./logger": {
|
|
61
76
|
"types": "./src/utils/Logger.ts",
|
|
62
77
|
"import": "./src/utils/Logger.ts",
|
|
63
|
-
"
|
|
78
|
+
"default": "./src/utils/Logger.ts"
|
|
64
79
|
},
|
|
65
80
|
"./http-error": {
|
|
66
81
|
"types": "./src/infra/utils/HttpError.ts",
|
|
67
82
|
"import": "./src/infra/utils/HttpError.ts",
|
|
68
|
-
"
|
|
69
|
-
}
|
|
83
|
+
"default": "./src/infra/utils/HttpError.ts"
|
|
84
|
+
},
|
|
85
|
+
"./package.json": "./package.json"
|
|
70
86
|
},
|
|
71
87
|
"typesVersions": {
|
|
72
88
|
"*": {
|
|
73
|
-
"
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
"
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
"
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
"
|
|
83
|
-
|
|
89
|
+
"*": [
|
|
90
|
+
"./src/*"
|
|
91
|
+
],
|
|
92
|
+
"decorators": [
|
|
93
|
+
"./src/decorators/index.ts"
|
|
94
|
+
],
|
|
95
|
+
"middleware": [
|
|
96
|
+
"./src/middleware/index.ts"
|
|
97
|
+
],
|
|
98
|
+
"types": [
|
|
99
|
+
"./src/types/index.ts"
|
|
100
|
+
],
|
|
101
|
+
"infra": [
|
|
102
|
+
"./src/infra/index.ts"
|
|
103
|
+
],
|
|
104
|
+
"router": [
|
|
105
|
+
"./src/infra/Router.ts"
|
|
106
|
+
],
|
|
107
|
+
"config": [
|
|
108
|
+
"./src/shared/config/index.ts"
|
|
109
|
+
],
|
|
110
|
+
"plugins": [
|
|
111
|
+
"./src/shared/plugins/index.ts"
|
|
112
|
+
],
|
|
113
|
+
"cors": [
|
|
114
|
+
"./src/shared/plugins/CORSPlugin.ts"
|
|
115
|
+
],
|
|
116
|
+
"rate-limit": [
|
|
117
|
+
"./src/shared/plugins/RateLimitPlugin.ts"
|
|
118
|
+
],
|
|
119
|
+
"utils": [
|
|
120
|
+
"./src/utils/index.ts"
|
|
121
|
+
],
|
|
122
|
+
"cookies": [
|
|
123
|
+
"./src/utils/cookies/index.ts"
|
|
124
|
+
],
|
|
125
|
+
"validators": [
|
|
126
|
+
"./src/utils/validators/index.ts"
|
|
127
|
+
],
|
|
128
|
+
"logger": [
|
|
129
|
+
"./src/utils/Logger.ts"
|
|
130
|
+
],
|
|
131
|
+
"http-error": [
|
|
132
|
+
"./src/infra/utils/HttpError.ts"
|
|
133
|
+
]
|
|
84
134
|
}
|
|
85
135
|
},
|
|
86
136
|
"files": [
|
package/src/infra/Router.ts
CHANGED
|
@@ -34,23 +34,31 @@ export class Router {
|
|
|
34
34
|
find(method: string, path: string): MatchResult {
|
|
35
35
|
const segments = path.split("/").filter(Boolean);
|
|
36
36
|
let node = this.root;
|
|
37
|
-
|
|
38
37
|
const params: Record<string, string> = {};
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
params[node.paramName] = seg;
|
|
47
|
-
}
|
|
38
|
+
|
|
39
|
+
for (let i = 0; i < segments.length; i++) {
|
|
40
|
+
const seg = segments[i];
|
|
41
|
+
let child = node.children.get(seg);
|
|
42
|
+
|
|
43
|
+
if (child) {
|
|
44
|
+
node = child;
|
|
48
45
|
} else {
|
|
49
|
-
|
|
46
|
+
child = node.children.get(":");
|
|
47
|
+
if (child) {
|
|
48
|
+
node = child;
|
|
49
|
+
if (node.paramName) {
|
|
50
|
+
params[node.paramName] = seg;
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
throw new HttpError(404, "Route not found");
|
|
54
|
+
}
|
|
50
55
|
}
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
const handlers = node.handlers.get(method.toUpperCase()) as Handler[];
|
|
59
|
+
if (!handlers) {
|
|
60
|
+
throw new HttpError(404, "Route not found");
|
|
61
|
+
}
|
|
54
62
|
return { handlers, params };
|
|
55
63
|
}
|
|
56
64
|
}
|
package/src/infra/Server.ts
CHANGED
|
@@ -139,14 +139,15 @@ export class AzuraClient {
|
|
|
139
139
|
await this.initPromise;
|
|
140
140
|
|
|
141
141
|
const url = new URL(request.url);
|
|
142
|
-
const
|
|
142
|
+
const urlPath = url.pathname;
|
|
143
143
|
|
|
144
|
-
// Parse query
|
|
145
|
-
const rawQuery = parseQS(url.search.slice(1) || "");
|
|
146
144
|
const safeQuery: Record<string, string> = {};
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
|
|
145
|
+
if (url.search) {
|
|
146
|
+
const rawQuery = parseQS(url.search.slice(1));
|
|
147
|
+
for (const k in rawQuery) {
|
|
148
|
+
const v = rawQuery[k];
|
|
149
|
+
safeQuery[k] = Array.isArray(v) ? v[0] || "" : v as string;
|
|
150
|
+
}
|
|
150
151
|
}
|
|
151
152
|
|
|
152
153
|
const cookieHeader = request.headers.get("cookie") || "";
|
|
@@ -202,7 +203,6 @@ export class AzuraClient {
|
|
|
202
203
|
ips: request.headers.get("x-forwarded-for")?.split(/\s*,\s*/) || [],
|
|
203
204
|
};
|
|
204
205
|
|
|
205
|
-
// Response builder
|
|
206
206
|
let statusCode = 200;
|
|
207
207
|
const responseHeaders = new Headers();
|
|
208
208
|
let responseBody: any = null;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { RequestServer } from "./http/request.type";
|
|
2
|
+
export type { ResponseServer } from "./http/response.type";
|
|
3
|
+
export type { RequestHandler, HttpContext } from "./common.type";
|
|
4
|
+
export type { RouteDefinition, ParamDefinition, ParamSource } from "./routes.type";
|
|
5
|
+
export type { Schema as ValidationSchema } from "./validations.type";
|
package/src/utils/Parser.ts
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
export function parseQS(qs: string): Record<string, string | string[]> {
|
|
2
2
|
const out: Record<string, string | string[]> = {};
|
|
3
3
|
if (!qs) return out;
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
|
|
5
|
+
const parts = qs.split("&");
|
|
6
|
+
for (let i = 0; i < parts.length; i++) {
|
|
7
|
+
const p = parts[i];
|
|
6
8
|
if (!p) continue;
|
|
9
|
+
|
|
7
10
|
const idx = p.indexOf("=");
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
if (idx === -1) {
|
|
12
|
+
out[decodeURIComponent(p)] = "";
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const k = decodeURIComponent(p.slice(0, idx));
|
|
17
|
+
const v = decodeURIComponent(p.slice(idx + 1));
|
|
18
|
+
|
|
19
|
+
const existing = out[k];
|
|
20
|
+
if (existing !== undefined) {
|
|
21
|
+
if (Array.isArray(existing)) {
|
|
22
|
+
existing.push(v);
|
|
23
|
+
} else {
|
|
24
|
+
out[k] = [existing as string, v];
|
|
25
|
+
}
|
|
14
26
|
} else {
|
|
15
27
|
out[k] = v;
|
|
16
28
|
}
|