azurajs 3.0.2 → 3.0.4

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.
Files changed (120) hide show
  1. package/README.md +32 -0
  2. package/dist/IpResolver-BVgnGnpf.d.mts +5 -0
  3. package/dist/IpResolver-BVgnGnpf.d.ts +5 -0
  4. package/dist/SwaggerPlugin-C0UZTjaZ.d.ts +6 -0
  5. package/dist/SwaggerPlugin-wr9S4SRG.d.mts +6 -0
  6. package/dist/cookies/index.d.mts +7 -0
  7. package/dist/cookies/index.d.ts +7 -0
  8. package/dist/cookies/index.js +38 -0
  9. package/dist/cookies/index.js.map +1 -0
  10. package/dist/cookies/index.mjs +35 -0
  11. package/dist/cookies/index.mjs.map +1 -0
  12. package/dist/core/index.d.mts +18 -27
  13. package/dist/core/index.d.ts +18 -27
  14. package/dist/core/index.js +214 -14
  15. package/dist/core/index.js.map +1 -1
  16. package/dist/core/index.mjs +214 -14
  17. package/dist/core/index.mjs.map +1 -1
  18. package/dist/cors/index.d.mts +7 -0
  19. package/dist/cors/index.d.ts +7 -0
  20. package/dist/cors/index.js +52 -0
  21. package/dist/cors/index.js.map +1 -0
  22. package/dist/cors/index.mjs +50 -0
  23. package/dist/cors/index.mjs.map +1 -0
  24. package/dist/decorators/index.d.mts +2 -0
  25. package/dist/decorators/index.d.ts +2 -0
  26. package/dist/decorators/index.js +25 -0
  27. package/dist/decorators/index.js.map +1 -1
  28. package/dist/decorators/index.mjs +24 -1
  29. package/dist/decorators/index.mjs.map +1 -1
  30. package/dist/decorators-B6l3CbxC.d.ts +13 -0
  31. package/dist/decorators-D5nY109r.d.mts +13 -0
  32. package/dist/http-error/index.d.mts +18 -0
  33. package/dist/http-error/index.d.ts +18 -0
  34. package/dist/http-error/index.js +81 -0
  35. package/dist/http-error/index.js.map +1 -0
  36. package/dist/http-error/index.mjs +79 -0
  37. package/dist/http-error/index.mjs.map +1 -0
  38. package/dist/index-j6QGMhZU.d.mts +30 -0
  39. package/dist/index-tpPZS_UK.d.ts +30 -0
  40. package/dist/index.d.mts +16 -5
  41. package/dist/index.d.ts +16 -5
  42. package/dist/index.js +1178 -14
  43. package/dist/index.js.map +1 -1
  44. package/dist/index.mjs +1176 -15
  45. package/dist/index.mjs.map +1 -1
  46. package/dist/infra/index.d.mts +6 -0
  47. package/dist/infra/index.d.ts +6 -0
  48. package/dist/infra/index.js +162 -0
  49. package/dist/infra/index.js.map +1 -0
  50. package/dist/infra/index.mjs +159 -0
  51. package/dist/infra/index.mjs.map +1 -0
  52. package/dist/{Logger-iEQNVVSc.d.mts → logger/index.d.mts} +2 -1
  53. package/dist/{Logger-iEQNVVSc.d.ts → logger/index.d.ts} +2 -1
  54. package/dist/logger/index.js +123 -0
  55. package/dist/logger/index.js.map +1 -0
  56. package/dist/logger/index.mjs +120 -0
  57. package/dist/logger/index.mjs.map +1 -0
  58. package/dist/plugins/index.d.mts +8 -6
  59. package/dist/plugins/index.d.ts +8 -6
  60. package/dist/plugins/index.js +1101 -0
  61. package/dist/plugins/index.js.map +1 -1
  62. package/dist/plugins/index.mjs +1101 -1
  63. package/dist/plugins/index.mjs.map +1 -1
  64. package/dist/rate-limit/index.d.mts +7 -0
  65. package/dist/rate-limit/index.d.ts +7 -0
  66. package/dist/rate-limit/index.js +81 -0
  67. package/dist/rate-limit/index.js.map +1 -0
  68. package/dist/rate-limit/index.mjs +79 -0
  69. package/dist/rate-limit/index.mjs.map +1 -0
  70. package/dist/router/index.d.mts +4 -0
  71. package/dist/router/index.d.ts +4 -0
  72. package/dist/router/index.js +218 -0
  73. package/dist/router/index.js.map +1 -0
  74. package/dist/router/index.mjs +216 -0
  75. package/dist/router/index.mjs.map +1 -0
  76. package/dist/routes.type-DZO5VBW2.d.mts +58 -0
  77. package/dist/routes.type-DzHNkCag.d.ts +58 -0
  78. package/dist/swagger/index.d.mts +30 -0
  79. package/dist/swagger/index.d.ts +30 -0
  80. package/dist/swagger/index.js +1136 -0
  81. package/dist/swagger/index.js.map +1 -0
  82. package/dist/swagger/index.mjs +1126 -0
  83. package/dist/swagger/index.mjs.map +1 -0
  84. package/dist/swagger/swagger-ui-modern.html +894 -0
  85. package/dist/swagger.type-Bfn5nGR8.d.mts +42 -0
  86. package/dist/swagger.type-CfDbFCZC.d.ts +42 -0
  87. package/dist/types/index.d.mts +5 -58
  88. package/dist/types/index.d.ts +5 -58
  89. package/dist/utils/index.d.mts +7 -72
  90. package/dist/utils/index.d.ts +7 -72
  91. package/dist/validators/index.d.mts +48 -0
  92. package/dist/validators/index.d.ts +48 -0
  93. package/dist/validators/index.js +144 -0
  94. package/dist/validators/index.js.map +1 -0
  95. package/dist/validators/index.mjs +141 -0
  96. package/dist/validators/index.mjs.map +1 -0
  97. package/package.json +86 -2
  98. package/src/cookies/index.ts +1 -0
  99. package/src/core/index.ts +1 -0
  100. package/src/core/router.ts +26 -15
  101. package/src/core/server.ts +64 -14
  102. package/src/cors/index.ts +2 -0
  103. package/src/decorators/index.ts +2 -0
  104. package/src/http-error/index.ts +1 -0
  105. package/src/infra/index.ts +3 -0
  106. package/src/logger/index.ts +1 -0
  107. package/src/plugins/SwaggerPlugin.ts +45 -0
  108. package/src/plugins/index.ts +1 -0
  109. package/src/rate-limit/index.ts +2 -0
  110. package/src/router/index.ts +1 -0
  111. package/src/swagger/constants.ts +8 -0
  112. package/src/swagger/decorators.ts +35 -0
  113. package/src/swagger/index.ts +10 -0
  114. package/src/swagger/openapi-builder.ts +199 -0
  115. package/src/swagger/swagger-ui-html.ts +24 -0
  116. package/src/swagger/swagger-ui-modern.html +894 -0
  117. package/src/swagger/swagger-ui-template.ts +5 -0
  118. package/src/types/index.ts +7 -0
  119. package/src/types/swagger.type.ts +36 -0
  120. package/src/validators/index.ts +4 -0
@@ -0,0 +1,81 @@
1
+ 'use strict';
2
+
3
+ // src/plugins/RateLimitPlugin.ts
4
+ var MemoryStore = class {
5
+ store = /* @__PURE__ */ new Map();
6
+ cleanupInterval;
7
+ constructor(windowMs) {
8
+ this.cleanupInterval = setInterval(() => {
9
+ const now = Date.now();
10
+ for (const [key, entry] of this.store) {
11
+ if (now >= entry.resetTime) this.store.delete(key);
12
+ }
13
+ }, windowMs);
14
+ if (this.cleanupInterval.unref) this.cleanupInterval.unref();
15
+ }
16
+ increment(key, windowMs) {
17
+ const now = Date.now();
18
+ const entry = this.store.get(key);
19
+ if (!entry || now >= entry.resetTime) {
20
+ const resetTime = now + windowMs;
21
+ this.store.set(key, { count: 1, resetTime });
22
+ return { totalHits: 1, resetTime: new Date(resetTime) };
23
+ }
24
+ entry.count++;
25
+ return { totalHits: entry.count, resetTime: new Date(entry.resetTime) };
26
+ }
27
+ decrement(key) {
28
+ const entry = this.store.get(key);
29
+ if (entry && entry.count > 0) entry.count--;
30
+ }
31
+ resetKey(key) {
32
+ this.store.delete(key);
33
+ }
34
+ destroy() {
35
+ clearInterval(this.cleanupInterval);
36
+ this.store.clear();
37
+ }
38
+ };
39
+ function RateLimitPlugin(options = {}) {
40
+ const {
41
+ windowMs = 6e4,
42
+ max = 100,
43
+ message = { error: { statusCode: 429, message: "Too many requests, please try again later" } },
44
+ statusCode = 429,
45
+ keyGenerator = (req) => req.ip,
46
+ skipSuccessfulRequests = false,
47
+ skipFailedRequests = false
48
+ } = options;
49
+ const memStore = new MemoryStore(windowMs);
50
+ return (ctx, next) => {
51
+ const { req, res } = ctx;
52
+ const key = keyGenerator(req);
53
+ const { totalHits, resetTime } = memStore.increment(key, windowMs);
54
+ res.setHeader("X-RateLimit-Limit", String(max));
55
+ res.setHeader("X-RateLimit-Remaining", String(Math.max(0, max - totalHits)));
56
+ res.setHeader("X-RateLimit-Reset", String(Math.ceil(resetTime.getTime() / 1e3)));
57
+ if (totalHits > max) {
58
+ res.setHeader("Retry-After", String(Math.ceil(windowMs / 1e3)));
59
+ res.statusCode = statusCode;
60
+ const body = typeof message === "string" ? message : JSON.stringify(message);
61
+ res.setHeader("Content-Type", typeof message === "string" ? "text/plain" : "application/json");
62
+ res.end(body);
63
+ return;
64
+ }
65
+ const origEnd = res.end;
66
+ res.end = function(...args) {
67
+ if (skipSuccessfulRequests && res.statusCode < 400) {
68
+ memStore.decrement(key);
69
+ }
70
+ if (skipFailedRequests && res.statusCode >= 400) {
71
+ memStore.decrement(key);
72
+ }
73
+ return origEnd.apply(this, args);
74
+ };
75
+ next();
76
+ };
77
+ }
78
+
79
+ exports.RateLimitPlugin = RateLimitPlugin;
80
+ //# sourceMappingURL=index.js.map
81
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plugins/RateLimitPlugin.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { RateLimitOptions, PluginHandler } from \"../types/plugins/plugin.type.js\";\r\nimport type { AzuraRequest } from \"../types/common.type.js\";\r\n\r\ninterface SlidingWindowEntry {\r\n count: number;\r\n resetTime: number;\r\n}\r\n\r\nclass MemoryStore {\r\n private store = new Map<string, SlidingWindowEntry>();\r\n private cleanupInterval: ReturnType<typeof setInterval>;\r\n\r\n constructor(windowMs: number) {\r\n this.cleanupInterval = setInterval(() => {\r\n const now = Date.now();\r\n for (const [key, entry] of this.store) {\r\n if (now >= entry.resetTime) this.store.delete(key);\r\n }\r\n }, windowMs);\r\n if (this.cleanupInterval.unref) this.cleanupInterval.unref();\r\n }\r\n\r\n increment(key: string, windowMs: number): { totalHits: number; resetTime: Date } {\r\n const now = Date.now();\r\n const entry = this.store.get(key);\r\n\r\n if (!entry || now >= entry.resetTime) {\r\n const resetTime = now + windowMs;\r\n this.store.set(key, { count: 1, resetTime });\r\n return { totalHits: 1, resetTime: new Date(resetTime) };\r\n }\r\n\r\n entry.count++;\r\n return { totalHits: entry.count, resetTime: new Date(entry.resetTime) };\r\n }\r\n\r\n decrement(key: string): void {\r\n const entry = this.store.get(key);\r\n if (entry && entry.count > 0) entry.count--;\r\n }\r\n\r\n resetKey(key: string): void {\r\n this.store.delete(key);\r\n }\r\n\r\n destroy(): void {\r\n clearInterval(this.cleanupInterval);\r\n this.store.clear();\r\n }\r\n}\r\n\r\nexport function RateLimitPlugin(options: RateLimitOptions = {}): PluginHandler {\r\n const {\r\n windowMs = 60_000,\r\n max = 100,\r\n message = { error: { statusCode: 429, message: \"Too many requests, please try again later\" } },\r\n statusCode = 429,\r\n keyGenerator = (req: AzuraRequest) => req.ip,\r\n skipSuccessfulRequests = false,\r\n skipFailedRequests = false,\r\n } = options;\r\n\r\n const memStore = new MemoryStore(windowMs);\r\n\r\n return (ctx, next) => {\r\n const { req, res } = ctx;\r\n const key = keyGenerator(req);\r\n const { totalHits, resetTime } = memStore.increment(key, windowMs);\r\n\r\n res.setHeader(\"X-RateLimit-Limit\", String(max));\r\n res.setHeader(\"X-RateLimit-Remaining\", String(Math.max(0, max - totalHits)));\r\n res.setHeader(\"X-RateLimit-Reset\", String(Math.ceil(resetTime.getTime() / 1000)));\r\n\r\n if (totalHits > max) {\r\n res.setHeader(\"Retry-After\", String(Math.ceil(windowMs / 1000)));\r\n res.statusCode = statusCode;\r\n const body = typeof message === \"string\" ? message : JSON.stringify(message);\r\n res.setHeader(\"Content-Type\", typeof message === \"string\" ? \"text/plain\" : \"application/json\");\r\n res.end(body);\r\n return;\r\n }\r\n\r\n const origEnd = res.end;\r\n res.end = function (...args: any[]) {\r\n if (skipSuccessfulRequests && res.statusCode < 400) {\r\n memStore.decrement(key);\r\n }\r\n if (skipFailedRequests && res.statusCode >= 400) {\r\n memStore.decrement(key);\r\n }\r\n return (origEnd as any).apply(this, args);\r\n };\r\n\r\n next();\r\n };\r\n}\r\n"]}
@@ -0,0 +1,79 @@
1
+ // src/plugins/RateLimitPlugin.ts
2
+ var MemoryStore = class {
3
+ store = /* @__PURE__ */ new Map();
4
+ cleanupInterval;
5
+ constructor(windowMs) {
6
+ this.cleanupInterval = setInterval(() => {
7
+ const now = Date.now();
8
+ for (const [key, entry] of this.store) {
9
+ if (now >= entry.resetTime) this.store.delete(key);
10
+ }
11
+ }, windowMs);
12
+ if (this.cleanupInterval.unref) this.cleanupInterval.unref();
13
+ }
14
+ increment(key, windowMs) {
15
+ const now = Date.now();
16
+ const entry = this.store.get(key);
17
+ if (!entry || now >= entry.resetTime) {
18
+ const resetTime = now + windowMs;
19
+ this.store.set(key, { count: 1, resetTime });
20
+ return { totalHits: 1, resetTime: new Date(resetTime) };
21
+ }
22
+ entry.count++;
23
+ return { totalHits: entry.count, resetTime: new Date(entry.resetTime) };
24
+ }
25
+ decrement(key) {
26
+ const entry = this.store.get(key);
27
+ if (entry && entry.count > 0) entry.count--;
28
+ }
29
+ resetKey(key) {
30
+ this.store.delete(key);
31
+ }
32
+ destroy() {
33
+ clearInterval(this.cleanupInterval);
34
+ this.store.clear();
35
+ }
36
+ };
37
+ function RateLimitPlugin(options = {}) {
38
+ const {
39
+ windowMs = 6e4,
40
+ max = 100,
41
+ message = { error: { statusCode: 429, message: "Too many requests, please try again later" } },
42
+ statusCode = 429,
43
+ keyGenerator = (req) => req.ip,
44
+ skipSuccessfulRequests = false,
45
+ skipFailedRequests = false
46
+ } = options;
47
+ const memStore = new MemoryStore(windowMs);
48
+ return (ctx, next) => {
49
+ const { req, res } = ctx;
50
+ const key = keyGenerator(req);
51
+ const { totalHits, resetTime } = memStore.increment(key, windowMs);
52
+ res.setHeader("X-RateLimit-Limit", String(max));
53
+ res.setHeader("X-RateLimit-Remaining", String(Math.max(0, max - totalHits)));
54
+ res.setHeader("X-RateLimit-Reset", String(Math.ceil(resetTime.getTime() / 1e3)));
55
+ if (totalHits > max) {
56
+ res.setHeader("Retry-After", String(Math.ceil(windowMs / 1e3)));
57
+ res.statusCode = statusCode;
58
+ const body = typeof message === "string" ? message : JSON.stringify(message);
59
+ res.setHeader("Content-Type", typeof message === "string" ? "text/plain" : "application/json");
60
+ res.end(body);
61
+ return;
62
+ }
63
+ const origEnd = res.end;
64
+ res.end = function(...args) {
65
+ if (skipSuccessfulRequests && res.statusCode < 400) {
66
+ memStore.decrement(key);
67
+ }
68
+ if (skipFailedRequests && res.statusCode >= 400) {
69
+ memStore.decrement(key);
70
+ }
71
+ return origEnd.apply(this, args);
72
+ };
73
+ next();
74
+ };
75
+ }
76
+
77
+ export { RateLimitPlugin };
78
+ //# sourceMappingURL=index.mjs.map
79
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plugins/RateLimitPlugin.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type { RateLimitOptions, PluginHandler } from \"../types/plugins/plugin.type.js\";\r\nimport type { AzuraRequest } from \"../types/common.type.js\";\r\n\r\ninterface SlidingWindowEntry {\r\n count: number;\r\n resetTime: number;\r\n}\r\n\r\nclass MemoryStore {\r\n private store = new Map<string, SlidingWindowEntry>();\r\n private cleanupInterval: ReturnType<typeof setInterval>;\r\n\r\n constructor(windowMs: number) {\r\n this.cleanupInterval = setInterval(() => {\r\n const now = Date.now();\r\n for (const [key, entry] of this.store) {\r\n if (now >= entry.resetTime) this.store.delete(key);\r\n }\r\n }, windowMs);\r\n if (this.cleanupInterval.unref) this.cleanupInterval.unref();\r\n }\r\n\r\n increment(key: string, windowMs: number): { totalHits: number; resetTime: Date } {\r\n const now = Date.now();\r\n const entry = this.store.get(key);\r\n\r\n if (!entry || now >= entry.resetTime) {\r\n const resetTime = now + windowMs;\r\n this.store.set(key, { count: 1, resetTime });\r\n return { totalHits: 1, resetTime: new Date(resetTime) };\r\n }\r\n\r\n entry.count++;\r\n return { totalHits: entry.count, resetTime: new Date(entry.resetTime) };\r\n }\r\n\r\n decrement(key: string): void {\r\n const entry = this.store.get(key);\r\n if (entry && entry.count > 0) entry.count--;\r\n }\r\n\r\n resetKey(key: string): void {\r\n this.store.delete(key);\r\n }\r\n\r\n destroy(): void {\r\n clearInterval(this.cleanupInterval);\r\n this.store.clear();\r\n }\r\n}\r\n\r\nexport function RateLimitPlugin(options: RateLimitOptions = {}): PluginHandler {\r\n const {\r\n windowMs = 60_000,\r\n max = 100,\r\n message = { error: { statusCode: 429, message: \"Too many requests, please try again later\" } },\r\n statusCode = 429,\r\n keyGenerator = (req: AzuraRequest) => req.ip,\r\n skipSuccessfulRequests = false,\r\n skipFailedRequests = false,\r\n } = options;\r\n\r\n const memStore = new MemoryStore(windowMs);\r\n\r\n return (ctx, next) => {\r\n const { req, res } = ctx;\r\n const key = keyGenerator(req);\r\n const { totalHits, resetTime } = memStore.increment(key, windowMs);\r\n\r\n res.setHeader(\"X-RateLimit-Limit\", String(max));\r\n res.setHeader(\"X-RateLimit-Remaining\", String(Math.max(0, max - totalHits)));\r\n res.setHeader(\"X-RateLimit-Reset\", String(Math.ceil(resetTime.getTime() / 1000)));\r\n\r\n if (totalHits > max) {\r\n res.setHeader(\"Retry-After\", String(Math.ceil(windowMs / 1000)));\r\n res.statusCode = statusCode;\r\n const body = typeof message === \"string\" ? message : JSON.stringify(message);\r\n res.setHeader(\"Content-Type\", typeof message === \"string\" ? \"text/plain\" : \"application/json\");\r\n res.end(body);\r\n return;\r\n }\r\n\r\n const origEnd = res.end;\r\n res.end = function (...args: any[]) {\r\n if (skipSuccessfulRequests && res.statusCode < 400) {\r\n memStore.decrement(key);\r\n }\r\n if (skipFailedRequests && res.statusCode >= 400) {\r\n memStore.decrement(key);\r\n }\r\n return (origEnd as any).apply(this, args);\r\n };\r\n\r\n next();\r\n };\r\n}\r\n"]}
@@ -0,0 +1,4 @@
1
+ export { R as Router } from '../index-j6QGMhZU.mjs';
2
+ import '../common.type-BhGCNyEm.mjs';
3
+ import 'node:http';
4
+ import '../routes.type-DZO5VBW2.mjs';
@@ -0,0 +1,4 @@
1
+ export { R as Router } from '../index-tpPZS_UK.js';
2
+ import '../common.type-BhGCNyEm.js';
3
+ import 'node:http';
4
+ import '../routes.type-DzHNkCag.js';
@@ -0,0 +1,218 @@
1
+ 'use strict';
2
+
3
+ // src/core/router.ts
4
+ var PARAM_PREFIX = 58;
5
+ function createNode(segment = "") {
6
+ return {
7
+ segment,
8
+ children: /* @__PURE__ */ new Map(),
9
+ paramChild: null,
10
+ paramName: "",
11
+ handlers: /* @__PURE__ */ new Map(),
12
+ wildcardHandler: null
13
+ };
14
+ }
15
+ var LRUCache = class {
16
+ capacity;
17
+ map;
18
+ head;
19
+ tail;
20
+ constructor(capacity) {
21
+ this.capacity = capacity;
22
+ this.map = /* @__PURE__ */ new Map();
23
+ this.head = { prev: null, next: null };
24
+ this.tail = { prev: null, next: null };
25
+ this.head.next = this.tail;
26
+ this.tail.prev = this.head;
27
+ }
28
+ get(key) {
29
+ const node = this.map.get(key);
30
+ if (!node) return void 0;
31
+ this.moveToHead(node);
32
+ return node.value;
33
+ }
34
+ set(key, value) {
35
+ const existing = this.map.get(key);
36
+ if (existing) {
37
+ existing.value = value;
38
+ this.moveToHead(existing);
39
+ return;
40
+ }
41
+ const node = { value, key, prev: null, next: null };
42
+ this.map.set(key, node);
43
+ this.addToHead(node);
44
+ if (this.map.size > this.capacity) {
45
+ const removed = this.removeTail();
46
+ if (removed) this.map.delete(removed.key);
47
+ }
48
+ }
49
+ addToHead(node) {
50
+ node.prev = this.head;
51
+ node.next = this.head.next;
52
+ this.head.next.prev = node;
53
+ this.head.next = node;
54
+ }
55
+ removeNode(node) {
56
+ node.prev.next = node.next;
57
+ node.next.prev = node.prev;
58
+ }
59
+ moveToHead(node) {
60
+ this.removeNode(node);
61
+ this.addToHead(node);
62
+ }
63
+ removeTail() {
64
+ const node = this.tail.prev;
65
+ if (node === this.head) return null;
66
+ this.removeNode(node);
67
+ return node;
68
+ }
69
+ clear() {
70
+ this.map.clear();
71
+ this.head.next = this.tail;
72
+ this.tail.prev = this.head;
73
+ }
74
+ };
75
+ var Router = class {
76
+ root = createNode();
77
+ cache;
78
+ staticRoutes = /* @__PURE__ */ new Map();
79
+ constructor(cacheSize = 1024) {
80
+ this.cache = new LRUCache(cacheSize);
81
+ }
82
+ add(method, path, handler, middlewares = [], meta) {
83
+ this.cache.clear();
84
+ const normalizedPath = this.normalizePath(path);
85
+ const stored = { handler, middlewares, meta };
86
+ if (!normalizedPath.includes(":") && !normalizedPath.includes("*")) {
87
+ const key = `${method}:${normalizedPath}`;
88
+ this.staticRoutes.set(key, stored);
89
+ return;
90
+ }
91
+ const segments = normalizedPath.split("/").filter(Boolean);
92
+ let node = this.root;
93
+ for (let i = 0; i < segments.length; i++) {
94
+ const seg = segments[i];
95
+ if (seg === "*") {
96
+ if (!node.wildcardHandler) {
97
+ node.wildcardHandler = /* @__PURE__ */ new Map();
98
+ }
99
+ node.wildcardHandler.set(method, stored);
100
+ return;
101
+ }
102
+ if (seg.charCodeAt(0) === PARAM_PREFIX) {
103
+ if (!node.paramChild) {
104
+ node.paramChild = createNode(seg);
105
+ node.paramChild.paramName = seg.slice(1);
106
+ }
107
+ node = node.paramChild;
108
+ continue;
109
+ }
110
+ let child = node.children.get(seg);
111
+ if (!child) {
112
+ child = createNode(seg);
113
+ node.children.set(seg, child);
114
+ }
115
+ node = child;
116
+ }
117
+ node.handlers.set(method, stored);
118
+ }
119
+ find(method, path) {
120
+ const normalizedPath = this.normalizePath(path);
121
+ const staticKey = `${method}:${normalizedPath}`;
122
+ const staticRoute = this.staticRoutes.get(staticKey);
123
+ if (staticRoute) {
124
+ return {
125
+ handler: staticRoute.handler,
126
+ params: {},
127
+ middlewares: staticRoute.middlewares,
128
+ meta: staticRoute.meta
129
+ };
130
+ }
131
+ const cacheKey = staticKey;
132
+ const cached = this.cache.get(cacheKey);
133
+ if (cached !== void 0) {
134
+ return cached ? { ...cached, params: { ...cached.params } } : null;
135
+ }
136
+ const segments = normalizedPath.split("/").filter(Boolean);
137
+ const params = {};
138
+ const result = this.matchNode(this.root, segments, 0, params, method);
139
+ if (result) {
140
+ const match = {
141
+ handler: result.handler,
142
+ params,
143
+ middlewares: result.middlewares,
144
+ meta: result.meta
145
+ };
146
+ this.cache.set(cacheKey, match);
147
+ return { ...match, params: { ...params } };
148
+ }
149
+ this.cache.set(cacheKey, null);
150
+ return null;
151
+ }
152
+ matchNode(node, segments, idx, params, method) {
153
+ if (idx === segments.length) {
154
+ return node.handlers.get(method) ?? null;
155
+ }
156
+ const seg = segments[idx];
157
+ const child = node.children.get(seg);
158
+ if (child) {
159
+ const result = this.matchNode(child, segments, idx + 1, params, method);
160
+ if (result) return result;
161
+ }
162
+ if (node.paramChild) {
163
+ params[node.paramChild.paramName] = seg;
164
+ const result = this.matchNode(node.paramChild, segments, idx + 1, params, method);
165
+ if (result) return result;
166
+ delete params[node.paramChild.paramName];
167
+ }
168
+ if (node.wildcardHandler) {
169
+ const route = node.wildcardHandler.get(method);
170
+ if (route) return route;
171
+ }
172
+ return null;
173
+ }
174
+ normalizePath(path) {
175
+ if (path === "/") return "/";
176
+ if (path.endsWith("/") && path.length > 1) return path.slice(0, -1);
177
+ return path;
178
+ }
179
+ getAllRoutes() {
180
+ return this.getRouteDocuments().map(({ method, path }) => ({ method, path }));
181
+ }
182
+ /**
183
+ * Todas as rotas com metadados (ex.: OpenAPI) associados ao handler.
184
+ */
185
+ getRouteDocuments() {
186
+ const routes = [];
187
+ for (const [key, stored] of this.staticRoutes) {
188
+ const [method, path] = key.split(":", 2);
189
+ routes.push({ method, path, meta: stored.meta });
190
+ }
191
+ this.collectRoutesWithMeta(this.root, "", routes);
192
+ return routes;
193
+ }
194
+ collectRoutesWithMeta(node, prefix, routes) {
195
+ for (const [method, stored] of node.handlers) {
196
+ routes.push({ method, path: prefix || "/", meta: stored.meta });
197
+ }
198
+ for (const [seg, child] of node.children) {
199
+ this.collectRoutesWithMeta(child, `${prefix}/${seg}`, routes);
200
+ }
201
+ if (node.paramChild) {
202
+ this.collectRoutesWithMeta(
203
+ node.paramChild,
204
+ `${prefix}/:${node.paramChild.paramName}`,
205
+ routes
206
+ );
207
+ }
208
+ if (node.wildcardHandler) {
209
+ for (const [method, stored] of node.wildcardHandler) {
210
+ routes.push({ method, path: `${prefix}/*`, meta: stored.meta });
211
+ }
212
+ }
213
+ }
214
+ };
215
+
216
+ exports.Router = Router;
217
+ //# sourceMappingURL=index.js.map
218
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/router.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { HttpMethod, RouteHandler, MiddlewareHandler, RouteMatch } from \"../types/common.type.js\";\r\nimport type { RouteMeta } from \"../types/routes.type.js\";\r\n\r\n/** Rota registada com metadados opcionais (OpenAPI / documentação). */\r\nexport interface RouteDocument {\r\n method: HttpMethod;\r\n path: string;\r\n meta?: RouteMeta;\r\n}\r\n\r\nconst PARAM_PREFIX = 58; // ':'\r\n\r\ninterface RadixNode {\r\n segment: string;\r\n children: Map<string, RadixNode>;\r\n paramChild: RadixNode | null;\r\n paramName: string;\r\n handlers: Map<HttpMethod, StoredRoute>;\r\n wildcardHandler: Map<HttpMethod, StoredRoute> | null;\r\n}\r\n\r\ninterface StoredRoute {\r\n handler: RouteHandler;\r\n middlewares: MiddlewareHandler[];\r\n meta?: Record<string, any>;\r\n}\r\n\r\nfunction createNode(segment: string = \"\"): RadixNode {\r\n return {\r\n segment,\r\n children: new Map(),\r\n paramChild: null,\r\n paramName: \"\",\r\n handlers: new Map(),\r\n wildcardHandler: null,\r\n };\r\n}\r\n\r\n/**\r\n * LRU Cache with O(1) get/set via doubly linked list + hash map.\r\n * Used for route lookup caching in hot paths.\r\n */\r\nclass LRUCache<K, V> {\r\n private capacity: number;\r\n private map: Map<K, { value: V; key: K; prev: any; next: any }>;\r\n private head: any;\r\n private tail: any;\r\n\r\n constructor(capacity: number) {\r\n this.capacity = capacity;\r\n this.map = new Map();\r\n this.head = { prev: null, next: null };\r\n this.tail = { prev: null, next: null };\r\n this.head.next = this.tail;\r\n this.tail.prev = this.head;\r\n }\r\n\r\n get(key: K): V | undefined {\r\n const node = this.map.get(key);\r\n if (!node) return undefined;\r\n this.moveToHead(node);\r\n return node.value;\r\n }\r\n\r\n set(key: K, value: V): void {\r\n const existing = this.map.get(key);\r\n if (existing) {\r\n existing.value = value;\r\n this.moveToHead(existing);\r\n return;\r\n }\r\n\r\n const node = { value, key, prev: null as any, next: null as any };\r\n this.map.set(key, node);\r\n this.addToHead(node);\r\n\r\n if (this.map.size > this.capacity) {\r\n const removed = this.removeTail();\r\n if (removed) this.map.delete(removed.key);\r\n }\r\n }\r\n\r\n private addToHead(node: any): void {\r\n node.prev = this.head;\r\n node.next = this.head.next;\r\n this.head.next.prev = node;\r\n this.head.next = node;\r\n }\r\n\r\n private removeNode(node: any): void {\r\n node.prev.next = node.next;\r\n node.next.prev = node.prev;\r\n }\r\n\r\n private moveToHead(node: any): void {\r\n this.removeNode(node);\r\n this.addToHead(node);\r\n }\r\n\r\n private removeTail(): any {\r\n const node = this.tail.prev;\r\n if (node === this.head) return null;\r\n this.removeNode(node);\r\n return node;\r\n }\r\n\r\n clear(): void {\r\n this.map.clear();\r\n this.head.next = this.tail;\r\n this.tail.prev = this.head;\r\n }\r\n}\r\n\r\nexport class Router {\r\n private root: RadixNode = createNode();\r\n private cache: LRUCache<string, RouteMatch | null>;\r\n private staticRoutes: Map<string, StoredRoute> = new Map();\r\n\r\n constructor(cacheSize: number = 1024) {\r\n this.cache = new LRUCache(cacheSize);\r\n }\r\n\r\n add(\r\n method: HttpMethod,\r\n path: string,\r\n handler: RouteHandler,\r\n middlewares: MiddlewareHandler[] = [],\r\n meta?: Record<string, any>,\r\n ): void {\r\n this.cache.clear();\r\n const normalizedPath = this.normalizePath(path);\r\n const stored: StoredRoute = { handler, middlewares, meta };\r\n\r\n if (!normalizedPath.includes(\":\") && !normalizedPath.includes(\"*\")) {\r\n const key = `${method}:${normalizedPath}`;\r\n this.staticRoutes.set(key, stored);\r\n return;\r\n }\r\n\r\n const segments = normalizedPath.split(\"/\").filter(Boolean);\r\n let node = this.root;\r\n\r\n for (let i = 0; i < segments.length; i++) {\r\n const seg = segments[i];\r\n\r\n if (seg === \"*\") {\r\n if (!node.wildcardHandler) {\r\n node.wildcardHandler = new Map();\r\n }\r\n node.wildcardHandler.set(method, stored);\r\n return;\r\n }\r\n\r\n if (seg.charCodeAt(0) === PARAM_PREFIX) {\r\n if (!node.paramChild) {\r\n node.paramChild = createNode(seg);\r\n node.paramChild.paramName = seg.slice(1);\r\n }\r\n node = node.paramChild;\r\n continue;\r\n }\r\n\r\n let child = node.children.get(seg);\r\n if (!child) {\r\n child = createNode(seg);\r\n node.children.set(seg, child);\r\n }\r\n node = child;\r\n }\r\n\r\n node.handlers.set(method, stored);\r\n }\r\n\r\n find(method: HttpMethod, path: string): RouteMatch | null {\r\n const normalizedPath = this.normalizePath(path);\r\n\r\n const staticKey = `${method}:${normalizedPath}`;\r\n const staticRoute = this.staticRoutes.get(staticKey);\r\n if (staticRoute) {\r\n return {\r\n handler: staticRoute.handler,\r\n params: {},\r\n middlewares: staticRoute.middlewares,\r\n meta: staticRoute.meta,\r\n };\r\n }\r\n\r\n const cacheKey = staticKey;\r\n const cached = this.cache.get(cacheKey);\r\n if (cached !== undefined) {\r\n return cached ? { ...cached, params: { ...cached.params } } : null;\r\n }\r\n\r\n const segments = normalizedPath.split(\"/\").filter(Boolean);\r\n const params: Record<string, string> = {};\r\n const result = this.matchNode(this.root, segments, 0, params, method);\r\n\r\n if (result) {\r\n const match: RouteMatch = {\r\n handler: result.handler,\r\n params,\r\n middlewares: result.middlewares,\r\n meta: result.meta,\r\n };\r\n this.cache.set(cacheKey, match);\r\n return { ...match, params: { ...params } };\r\n }\r\n\r\n this.cache.set(cacheKey, null);\r\n return null;\r\n }\r\n\r\n private matchNode(\r\n node: RadixNode,\r\n segments: string[],\r\n idx: number,\r\n params: Record<string, string>,\r\n method: HttpMethod,\r\n ): StoredRoute | null {\r\n if (idx === segments.length) {\r\n return node.handlers.get(method) ?? null;\r\n }\r\n\r\n const seg = segments[idx];\r\n\r\n const child = node.children.get(seg);\r\n if (child) {\r\n const result = this.matchNode(child, segments, idx + 1, params, method);\r\n if (result) return result;\r\n }\r\n\r\n if (node.paramChild) {\r\n params[node.paramChild.paramName] = seg;\r\n const result = this.matchNode(node.paramChild, segments, idx + 1, params, method);\r\n if (result) return result;\r\n delete params[node.paramChild.paramName];\r\n }\r\n\r\n if (node.wildcardHandler) {\r\n const route = node.wildcardHandler.get(method);\r\n if (route) return route;\r\n }\r\n\r\n return null;\r\n }\r\n\r\n private normalizePath(path: string): string {\r\n if (path === \"/\") return \"/\";\r\n if (path.endsWith(\"/\") && path.length > 1) return path.slice(0, -1);\r\n return path;\r\n }\r\n\r\n getAllRoutes(): Array<{ method: HttpMethod; path: string }> {\r\n return this.getRouteDocuments().map(({ method, path }) => ({ method, path }));\r\n }\r\n\r\n /**\r\n * Todas as rotas com metadados (ex.: OpenAPI) associados ao handler.\r\n */\r\n getRouteDocuments(): RouteDocument[] {\r\n const routes: RouteDocument[] = [];\r\n\r\n for (const [key, stored] of this.staticRoutes) {\r\n const [method, path] = key.split(\":\", 2) as [HttpMethod, string];\r\n routes.push({ method, path, meta: stored.meta });\r\n }\r\n\r\n this.collectRoutesWithMeta(this.root, \"\", routes);\r\n return routes;\r\n }\r\n\r\n private collectRoutesWithMeta(node: RadixNode, prefix: string, routes: RouteDocument[]): void {\r\n for (const [method, stored] of node.handlers) {\r\n routes.push({ method, path: prefix || \"/\", meta: stored.meta });\r\n }\r\n\r\n for (const [seg, child] of node.children) {\r\n this.collectRoutesWithMeta(child, `${prefix}/${seg}`, routes);\r\n }\r\n\r\n if (node.paramChild) {\r\n this.collectRoutesWithMeta(\r\n node.paramChild,\r\n `${prefix}/:${node.paramChild.paramName}`,\r\n routes,\r\n );\r\n }\r\n\r\n if (node.wildcardHandler) {\r\n for (const [method, stored] of node.wildcardHandler) {\r\n routes.push({ method, path: `${prefix}/*`, meta: stored.meta });\r\n }\r\n }\r\n }\r\n}\r\n"]}
@@ -0,0 +1,216 @@
1
+ // src/core/router.ts
2
+ var PARAM_PREFIX = 58;
3
+ function createNode(segment = "") {
4
+ return {
5
+ segment,
6
+ children: /* @__PURE__ */ new Map(),
7
+ paramChild: null,
8
+ paramName: "",
9
+ handlers: /* @__PURE__ */ new Map(),
10
+ wildcardHandler: null
11
+ };
12
+ }
13
+ var LRUCache = class {
14
+ capacity;
15
+ map;
16
+ head;
17
+ tail;
18
+ constructor(capacity) {
19
+ this.capacity = capacity;
20
+ this.map = /* @__PURE__ */ new Map();
21
+ this.head = { prev: null, next: null };
22
+ this.tail = { prev: null, next: null };
23
+ this.head.next = this.tail;
24
+ this.tail.prev = this.head;
25
+ }
26
+ get(key) {
27
+ const node = this.map.get(key);
28
+ if (!node) return void 0;
29
+ this.moveToHead(node);
30
+ return node.value;
31
+ }
32
+ set(key, value) {
33
+ const existing = this.map.get(key);
34
+ if (existing) {
35
+ existing.value = value;
36
+ this.moveToHead(existing);
37
+ return;
38
+ }
39
+ const node = { value, key, prev: null, next: null };
40
+ this.map.set(key, node);
41
+ this.addToHead(node);
42
+ if (this.map.size > this.capacity) {
43
+ const removed = this.removeTail();
44
+ if (removed) this.map.delete(removed.key);
45
+ }
46
+ }
47
+ addToHead(node) {
48
+ node.prev = this.head;
49
+ node.next = this.head.next;
50
+ this.head.next.prev = node;
51
+ this.head.next = node;
52
+ }
53
+ removeNode(node) {
54
+ node.prev.next = node.next;
55
+ node.next.prev = node.prev;
56
+ }
57
+ moveToHead(node) {
58
+ this.removeNode(node);
59
+ this.addToHead(node);
60
+ }
61
+ removeTail() {
62
+ const node = this.tail.prev;
63
+ if (node === this.head) return null;
64
+ this.removeNode(node);
65
+ return node;
66
+ }
67
+ clear() {
68
+ this.map.clear();
69
+ this.head.next = this.tail;
70
+ this.tail.prev = this.head;
71
+ }
72
+ };
73
+ var Router = class {
74
+ root = createNode();
75
+ cache;
76
+ staticRoutes = /* @__PURE__ */ new Map();
77
+ constructor(cacheSize = 1024) {
78
+ this.cache = new LRUCache(cacheSize);
79
+ }
80
+ add(method, path, handler, middlewares = [], meta) {
81
+ this.cache.clear();
82
+ const normalizedPath = this.normalizePath(path);
83
+ const stored = { handler, middlewares, meta };
84
+ if (!normalizedPath.includes(":") && !normalizedPath.includes("*")) {
85
+ const key = `${method}:${normalizedPath}`;
86
+ this.staticRoutes.set(key, stored);
87
+ return;
88
+ }
89
+ const segments = normalizedPath.split("/").filter(Boolean);
90
+ let node = this.root;
91
+ for (let i = 0; i < segments.length; i++) {
92
+ const seg = segments[i];
93
+ if (seg === "*") {
94
+ if (!node.wildcardHandler) {
95
+ node.wildcardHandler = /* @__PURE__ */ new Map();
96
+ }
97
+ node.wildcardHandler.set(method, stored);
98
+ return;
99
+ }
100
+ if (seg.charCodeAt(0) === PARAM_PREFIX) {
101
+ if (!node.paramChild) {
102
+ node.paramChild = createNode(seg);
103
+ node.paramChild.paramName = seg.slice(1);
104
+ }
105
+ node = node.paramChild;
106
+ continue;
107
+ }
108
+ let child = node.children.get(seg);
109
+ if (!child) {
110
+ child = createNode(seg);
111
+ node.children.set(seg, child);
112
+ }
113
+ node = child;
114
+ }
115
+ node.handlers.set(method, stored);
116
+ }
117
+ find(method, path) {
118
+ const normalizedPath = this.normalizePath(path);
119
+ const staticKey = `${method}:${normalizedPath}`;
120
+ const staticRoute = this.staticRoutes.get(staticKey);
121
+ if (staticRoute) {
122
+ return {
123
+ handler: staticRoute.handler,
124
+ params: {},
125
+ middlewares: staticRoute.middlewares,
126
+ meta: staticRoute.meta
127
+ };
128
+ }
129
+ const cacheKey = staticKey;
130
+ const cached = this.cache.get(cacheKey);
131
+ if (cached !== void 0) {
132
+ return cached ? { ...cached, params: { ...cached.params } } : null;
133
+ }
134
+ const segments = normalizedPath.split("/").filter(Boolean);
135
+ const params = {};
136
+ const result = this.matchNode(this.root, segments, 0, params, method);
137
+ if (result) {
138
+ const match = {
139
+ handler: result.handler,
140
+ params,
141
+ middlewares: result.middlewares,
142
+ meta: result.meta
143
+ };
144
+ this.cache.set(cacheKey, match);
145
+ return { ...match, params: { ...params } };
146
+ }
147
+ this.cache.set(cacheKey, null);
148
+ return null;
149
+ }
150
+ matchNode(node, segments, idx, params, method) {
151
+ if (idx === segments.length) {
152
+ return node.handlers.get(method) ?? null;
153
+ }
154
+ const seg = segments[idx];
155
+ const child = node.children.get(seg);
156
+ if (child) {
157
+ const result = this.matchNode(child, segments, idx + 1, params, method);
158
+ if (result) return result;
159
+ }
160
+ if (node.paramChild) {
161
+ params[node.paramChild.paramName] = seg;
162
+ const result = this.matchNode(node.paramChild, segments, idx + 1, params, method);
163
+ if (result) return result;
164
+ delete params[node.paramChild.paramName];
165
+ }
166
+ if (node.wildcardHandler) {
167
+ const route = node.wildcardHandler.get(method);
168
+ if (route) return route;
169
+ }
170
+ return null;
171
+ }
172
+ normalizePath(path) {
173
+ if (path === "/") return "/";
174
+ if (path.endsWith("/") && path.length > 1) return path.slice(0, -1);
175
+ return path;
176
+ }
177
+ getAllRoutes() {
178
+ return this.getRouteDocuments().map(({ method, path }) => ({ method, path }));
179
+ }
180
+ /**
181
+ * Todas as rotas com metadados (ex.: OpenAPI) associados ao handler.
182
+ */
183
+ getRouteDocuments() {
184
+ const routes = [];
185
+ for (const [key, stored] of this.staticRoutes) {
186
+ const [method, path] = key.split(":", 2);
187
+ routes.push({ method, path, meta: stored.meta });
188
+ }
189
+ this.collectRoutesWithMeta(this.root, "", routes);
190
+ return routes;
191
+ }
192
+ collectRoutesWithMeta(node, prefix, routes) {
193
+ for (const [method, stored] of node.handlers) {
194
+ routes.push({ method, path: prefix || "/", meta: stored.meta });
195
+ }
196
+ for (const [seg, child] of node.children) {
197
+ this.collectRoutesWithMeta(child, `${prefix}/${seg}`, routes);
198
+ }
199
+ if (node.paramChild) {
200
+ this.collectRoutesWithMeta(
201
+ node.paramChild,
202
+ `${prefix}/:${node.paramChild.paramName}`,
203
+ routes
204
+ );
205
+ }
206
+ if (node.wildcardHandler) {
207
+ for (const [method, stored] of node.wildcardHandler) {
208
+ routes.push({ method, path: `${prefix}/*`, meta: stored.meta });
209
+ }
210
+ }
211
+ }
212
+ };
213
+
214
+ export { Router };
215
+ //# sourceMappingURL=index.mjs.map
216
+ //# sourceMappingURL=index.mjs.map