tezx 2.0.11 → 3.0.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.
Files changed (234) hide show
  1. package/README.md +122 -89
  2. package/bun/getConnInfo.d.ts +21 -0
  3. package/bun/getConnInfo.js +9 -0
  4. package/bun/index.d.ts +10 -4
  5. package/bun/index.js +8 -4
  6. package/bun/ws.d.ts +48 -0
  7. package/bun/ws.js +58 -0
  8. package/cjs/bun/getConnInfo.js +12 -0
  9. package/cjs/bun/index.js +35 -7
  10. package/cjs/bun/ws.js +63 -0
  11. package/cjs/core/config.js +2 -12
  12. package/cjs/core/context.js +131 -379
  13. package/cjs/core/error.js +49 -0
  14. package/cjs/core/request.js +79 -131
  15. package/cjs/core/router.js +54 -387
  16. package/cjs/core/server.js +83 -202
  17. package/cjs/deno/env.js +4 -4
  18. package/cjs/deno/getConnInfo.js +18 -0
  19. package/cjs/deno/index.js +11 -18
  20. package/cjs/deno/serveStatic.js +53 -0
  21. package/cjs/deno/ws.js +39 -0
  22. package/cjs/helper/index.js +46 -10
  23. package/cjs/index.js +5 -7
  24. package/cjs/jwt/node.js +94 -0
  25. package/cjs/jwt/web.js +178 -0
  26. package/cjs/middleware/basic-auth.js +42 -0
  27. package/cjs/middleware/bearer-auth.js +34 -0
  28. package/cjs/middleware/cache-control.js +44 -0
  29. package/cjs/middleware/cors.js +11 -21
  30. package/cjs/middleware/detect-bot.js +57 -0
  31. package/cjs/middleware/i18n.js +73 -60
  32. package/cjs/middleware/index.js +8 -46
  33. package/cjs/middleware/logger.js +9 -4
  34. package/cjs/middleware/pagination.js +3 -2
  35. package/cjs/middleware/powered-by.js +3 -2
  36. package/cjs/middleware/rate-limiter.js +38 -0
  37. package/cjs/middleware/request-id.js +4 -5
  38. package/cjs/middleware/sanitize-headers.js +22 -0
  39. package/cjs/middleware/secure-headers copy.js +143 -0
  40. package/cjs/middleware/secure-headers.js +157 -0
  41. package/cjs/middleware/{xssProtection.js → xss-protection.js} +5 -8
  42. package/cjs/node/env.js +7 -7
  43. package/cjs/node/getConnInfo.js +16 -0
  44. package/cjs/node/index.js +17 -18
  45. package/cjs/node/mount-node.js +59 -0
  46. package/cjs/node/serveStatic.js +56 -0
  47. package/cjs/node/toWebRequest.js +25 -0
  48. package/cjs/node/ws.js +82 -0
  49. package/cjs/registry/RadixRouter.js +148 -0
  50. package/cjs/registry/index.js +17 -0
  51. package/cjs/types/headers.js +2 -0
  52. package/cjs/types/index.js +13 -0
  53. package/cjs/utils/buffer.js +17 -0
  54. package/cjs/utils/colors.js +2 -0
  55. package/cjs/utils/cookie.js +59 -0
  56. package/cjs/utils/file.js +136 -0
  57. package/cjs/utils/formData.js +60 -10
  58. package/cjs/utils/generateID.js +37 -0
  59. package/cjs/utils/low-level.js +115 -0
  60. package/cjs/utils/{staticFile.js → mimeTypes.js} +0 -87
  61. package/cjs/utils/rateLimit.js +41 -0
  62. package/cjs/utils/response.js +65 -0
  63. package/cjs/{core/environment.js → utils/runtime.js} +2 -1
  64. package/cjs/utils/url.js +65 -30
  65. package/core/config.d.ts +2 -7
  66. package/core/config.js +2 -12
  67. package/core/context.d.ts +209 -164
  68. package/core/context.js +131 -346
  69. package/core/error.d.ts +96 -0
  70. package/core/error.js +44 -0
  71. package/core/request.d.ts +67 -107
  72. package/core/request.js +78 -130
  73. package/core/router.d.ts +138 -133
  74. package/core/router.js +53 -352
  75. package/core/server.d.ts +99 -38
  76. package/core/server.js +83 -202
  77. package/deno/env.js +3 -3
  78. package/deno/getConnInfo.d.ts +21 -0
  79. package/deno/getConnInfo.js +15 -0
  80. package/deno/index.d.ts +9 -4
  81. package/deno/index.js +7 -4
  82. package/deno/serveStatic.d.ts +28 -0
  83. package/deno/serveStatic.js +49 -0
  84. package/deno/ws.d.ts +42 -0
  85. package/deno/ws.js +36 -0
  86. package/helper/index.d.ts +29 -15
  87. package/helper/index.js +27 -7
  88. package/index.d.ts +10 -8
  89. package/index.js +4 -5
  90. package/jwt/node.d.ts +39 -0
  91. package/jwt/node.js +87 -0
  92. package/jwt/web.d.ts +14 -0
  93. package/jwt/web.js +174 -0
  94. package/middleware/basic-auth.d.ts +56 -0
  95. package/middleware/basic-auth.js +38 -0
  96. package/middleware/bearer-auth.d.ts +53 -0
  97. package/middleware/bearer-auth.js +30 -0
  98. package/middleware/cache-control.d.ts +30 -0
  99. package/middleware/cache-control.js +40 -0
  100. package/middleware/cors.d.ts +30 -3
  101. package/middleware/cors.js +12 -22
  102. package/middleware/detect-bot.d.ts +113 -0
  103. package/middleware/detect-bot.js +53 -0
  104. package/middleware/i18n.d.ts +166 -73
  105. package/middleware/i18n.js +73 -60
  106. package/middleware/index.d.ts +8 -32
  107. package/middleware/index.js +8 -44
  108. package/middleware/logger.d.ts +5 -2
  109. package/middleware/logger.js +9 -4
  110. package/middleware/pagination.d.ts +9 -6
  111. package/middleware/pagination.js +3 -2
  112. package/middleware/powered-by.d.ts +2 -1
  113. package/middleware/powered-by.js +3 -2
  114. package/middleware/{rateLimiter.d.ts → rate-limiter.d.ts} +15 -9
  115. package/middleware/rate-limiter.js +34 -0
  116. package/middleware/request-id.d.ts +2 -1
  117. package/middleware/request-id.js +5 -6
  118. package/middleware/{sanitizeHeader.d.ts → sanitize-headers.d.ts} +5 -19
  119. package/middleware/sanitize-headers.js +18 -0
  120. package/middleware/secure-headers copy.d.ts +15 -0
  121. package/middleware/secure-headers copy.js +136 -0
  122. package/middleware/secure-headers.d.ts +132 -0
  123. package/middleware/secure-headers.js +153 -0
  124. package/middleware/{xssProtection.d.ts → xss-protection.d.ts} +2 -1
  125. package/middleware/xss-protection.js +19 -0
  126. package/node/env.js +4 -4
  127. package/node/getConnInfo.d.ts +21 -0
  128. package/node/getConnInfo.js +13 -0
  129. package/node/index.d.ts +13 -4
  130. package/node/index.js +11 -4
  131. package/node/mount-node.d.ts +11 -0
  132. package/node/mount-node.js +56 -0
  133. package/node/serveStatic.d.ts +36 -0
  134. package/node/serveStatic.js +52 -0
  135. package/node/toWebRequest.js +22 -0
  136. package/node/ws.d.ts +56 -0
  137. package/node/ws.js +46 -0
  138. package/package.json +39 -30
  139. package/registry/RadixRouter.d.ts +40 -0
  140. package/registry/RadixRouter.js +144 -0
  141. package/registry/index.d.ts +2 -0
  142. package/registry/index.js +1 -0
  143. package/types/headers.d.ts +2 -0
  144. package/types/headers.js +1 -0
  145. package/types/index.d.ts +318 -18
  146. package/types/index.js +12 -1
  147. package/utils/buffer.d.ts +1 -0
  148. package/utils/buffer.js +14 -0
  149. package/utils/colors.d.ts +24 -0
  150. package/utils/colors.js +2 -0
  151. package/utils/cookie.d.ts +55 -0
  152. package/utils/cookie.js +53 -0
  153. package/utils/file.d.ts +38 -0
  154. package/utils/file.js +96 -0
  155. package/utils/formData.d.ts +41 -1
  156. package/utils/formData.js +58 -9
  157. package/utils/generateID.d.ts +42 -0
  158. package/utils/generateID.js +32 -0
  159. package/utils/httpStatusMap.d.ts +14 -0
  160. package/utils/low-level.d.ts +58 -0
  161. package/utils/low-level.js +108 -0
  162. package/utils/mimeTypes.d.ts +4 -0
  163. package/utils/{staticFile.js → mimeTypes.js} +0 -53
  164. package/utils/rateLimit.d.ts +18 -0
  165. package/utils/rateLimit.js +37 -0
  166. package/utils/response.d.ts +18 -0
  167. package/utils/response.js +58 -0
  168. package/{core/environment.d.ts → utils/runtime.d.ts} +1 -0
  169. package/{core/environment.js → utils/runtime.js} +1 -0
  170. package/utils/url.d.ts +42 -14
  171. package/utils/url.js +61 -27
  172. package/bun/adapter.d.ts +0 -127
  173. package/bun/adapter.js +0 -97
  174. package/cjs/bun/adapter.js +0 -100
  175. package/cjs/core/MiddlewareConfigure.js +0 -68
  176. package/cjs/core/common.js +0 -15
  177. package/cjs/deno/adpater.js +0 -67
  178. package/cjs/helper/common.js +0 -17
  179. package/cjs/middleware/basicAuth.js +0 -71
  180. package/cjs/middleware/cacheControl.js +0 -90
  181. package/cjs/middleware/detectBot.js +0 -104
  182. package/cjs/middleware/detectLocale.js +0 -43
  183. package/cjs/middleware/lazyLoadModules.js +0 -73
  184. package/cjs/middleware/rateLimiter.js +0 -24
  185. package/cjs/middleware/requestTimeout.js +0 -42
  186. package/cjs/middleware/sanitizeHeader.js +0 -51
  187. package/cjs/middleware/secureHeaders.js +0 -42
  188. package/cjs/node/adapter.js +0 -138
  189. package/cjs/utils/regexRouter.js +0 -58
  190. package/cjs/utils/state.js +0 -34
  191. package/cjs/utils/toWebRequest.js +0 -35
  192. package/cjs/ws/deno.js +0 -20
  193. package/cjs/ws/index.js +0 -53
  194. package/cjs/ws/node.js +0 -65
  195. package/core/MiddlewareConfigure.d.ts +0 -15
  196. package/core/MiddlewareConfigure.js +0 -63
  197. package/core/common.d.ts +0 -21
  198. package/core/common.js +0 -11
  199. package/deno/adpater.d.ts +0 -38
  200. package/deno/adpater.js +0 -64
  201. package/helper/common.d.ts +0 -5
  202. package/helper/common.js +0 -14
  203. package/middleware/basicAuth.d.ts +0 -81
  204. package/middleware/basicAuth.js +0 -67
  205. package/middleware/cacheControl.d.ts +0 -48
  206. package/middleware/cacheControl.js +0 -53
  207. package/middleware/detectBot.d.ts +0 -121
  208. package/middleware/detectBot.js +0 -98
  209. package/middleware/detectLocale.d.ts +0 -55
  210. package/middleware/detectLocale.js +0 -39
  211. package/middleware/lazyLoadModules.d.ts +0 -72
  212. package/middleware/lazyLoadModules.js +0 -69
  213. package/middleware/rateLimiter.js +0 -20
  214. package/middleware/requestTimeout.d.ts +0 -25
  215. package/middleware/requestTimeout.js +0 -38
  216. package/middleware/sanitizeHeader.js +0 -47
  217. package/middleware/secureHeaders.d.ts +0 -78
  218. package/middleware/secureHeaders.js +0 -38
  219. package/middleware/xssProtection.js +0 -22
  220. package/node/adapter.d.ts +0 -46
  221. package/node/adapter.js +0 -102
  222. package/utils/regexRouter.d.ts +0 -66
  223. package/utils/regexRouter.js +0 -53
  224. package/utils/state.d.ts +0 -50
  225. package/utils/state.js +0 -30
  226. package/utils/staticFile.d.ts +0 -10
  227. package/utils/toWebRequest.js +0 -32
  228. package/ws/deno.d.ts +0 -6
  229. package/ws/deno.js +0 -16
  230. package/ws/index.d.ts +0 -180
  231. package/ws/index.js +0 -50
  232. package/ws/node.d.ts +0 -7
  233. package/ws/node.js +0 -28
  234. /package/{utils → node}/toWebRequest.d.ts +0 -0
package/core/router.js CHANGED
@@ -1,28 +1,14 @@
1
- import { addBaseToRegex, compileRegexRoute } from "../utils/regexRouter.js";
2
- import { getFiles } from "../utils/staticFile.js";
3
- import { sanitizePathSplit, wildcardOrOptionalParamRegex, } from "../utils/url.js";
4
- import { GlobalConfig } from "./config.js";
5
- import MiddlewareConfigure, { TriMiddleware, } from "./MiddlewareConfigure.js";
6
- export class TrieRouter {
7
- children = new Map();
8
- handlers = new Map();
9
- pathname;
10
- paramName;
11
- isParam = false;
12
- constructor(pathname = "/") {
13
- this.children = new Map();
14
- this.pathname = pathname;
15
- }
16
- }
17
- export class Router extends MiddlewareConfigure {
18
- routers = new Map();
1
+ import { sanitizePathSplitBasePath } from "../utils/low-level.js";
2
+ import { TezXError } from "./error.js";
3
+ export class Router {
19
4
  env = {};
20
- triRouter;
5
+ router;
6
+ route = [];
7
+ staticFile = Object.create(null);
8
+ basePath;
21
9
  constructor({ basePath = "/", env = {} } = {}) {
22
- super(basePath);
23
10
  this.basePath = basePath;
24
11
  this.env = { ...env };
25
- this.triRouter = new TrieRouter(basePath);
26
12
  this.get = this.get.bind(this);
27
13
  this.post = this.post.bind(this);
28
14
  this.put = this.put.bind(this);
@@ -31,57 +17,30 @@ export class Router extends MiddlewareConfigure {
31
17
  this.addRouter = this.addRouter.bind(this);
32
18
  this.group = this.group.bind(this);
33
19
  }
34
- static(...args) {
35
- let route = "";
36
- let dir;
37
- let options = {};
38
- switch (args.length) {
39
- case 3:
40
- [route, dir, options] = args;
41
- break;
42
- case 2:
43
- if (typeof args[1] === "object") {
44
- [dir, options] = args;
45
- }
46
- else {
47
- [route, dir] = args;
48
- }
49
- break;
50
- case 1:
51
- [dir] = args;
52
- break;
53
- default:
54
- throw new Error(`\x1b[1;31m404 Not Found\x1b[0m \x1b[1;32mInvalid arguments\x1b[0m`);
20
+ static(serveStatic) {
21
+ if (Array.isArray(serveStatic?.files)) {
22
+ serveStatic?.files.forEach((r) => {
23
+ this.staticFile[`GET ${r?.route}`] = (ctx) => {
24
+ if (serveStatic?.options?.cacheControl) {
25
+ ctx.setHeader("Cache-Control", serveStatic?.options.cacheControl);
26
+ }
27
+ let headers = serveStatic?.options?.headers;
28
+ if (headers) {
29
+ for (const key in headers) {
30
+ let value = headers?.[key];
31
+ ctx.headers.set(key, value);
32
+ }
33
+ }
34
+ return ctx.sendFile(r.fileSource);
35
+ };
36
+ });
55
37
  }
56
- getFiles(dir, route, this, options);
57
38
  return this;
58
39
  }
59
40
  get(path, ...args) {
60
41
  this.#registerRoute("GET", path, ...args);
61
42
  return this;
62
43
  }
63
- sse(path, handler) {
64
- this.get(path, async (ctx) => {
65
- let res = await handler(ctx);
66
- const headersMap = {};
67
- if (res instanceof Response) {
68
- for (const [key, value] of res.headers.entries()) {
69
- headersMap[key.toLowerCase()] = value;
70
- }
71
- res = res.body;
72
- }
73
- const headers = {
74
- ...headersMap,
75
- "content-type": "text/event-stream",
76
- "cache-control": "no-cache",
77
- connection: "keep-alive",
78
- };
79
- return new Response(res, {
80
- status: 200,
81
- headers,
82
- });
83
- });
84
- }
85
44
  post(path, ...args) {
86
45
  this.#registerRoute("POST", path, ...args);
87
46
  return this;
@@ -102,27 +61,26 @@ export class Router extends MiddlewareConfigure {
102
61
  this.#registerRoute("OPTIONS", path, ...args);
103
62
  return this;
104
63
  }
105
- head(path, ...args) {
106
- this.#registerRoute("HEAD", path, ...args);
107
- return this;
108
- }
109
64
  all(path, ...args) {
110
65
  this.#registerRoute("ALL", path, ...args);
111
66
  return this;
112
67
  }
113
- addRoute(method, path, ...args) {
114
- this.#registerRoute(method, path, ...args);
68
+ when(methods, path, ...args) {
69
+ const methodList = Array.isArray(methods) ? methods : [methods];
70
+ for (const method of methodList) {
71
+ this.#registerRoute(method.toUpperCase(), path, ...args);
72
+ }
115
73
  return this;
116
74
  }
117
75
  addRouter(path, router) {
118
- return this.#routeAddTriNode(path, router);
76
+ return this.#addRouterInstance(path, router);
119
77
  }
120
78
  group(prefix, callback) {
121
79
  const router = new Router({
122
80
  basePath: prefix,
123
81
  });
124
82
  callback(router);
125
- this.#routeAddTriNode("/", router);
83
+ this.#addRouterInstance("/", router);
126
84
  return this;
127
85
  }
128
86
  use(...args) {
@@ -159,15 +117,26 @@ export class Router extends MiddlewareConfigure {
159
117
  else if (args[0] instanceof Router) {
160
118
  router = args[0];
161
119
  }
162
- this.#addRouteMiddleware(path, middlewares);
120
+ if (middlewares?.length) {
121
+ this.#addRoute("ALL", path, middlewares);
122
+ }
163
123
  if (router && router instanceof Router) {
164
124
  this.addRouter(path, router);
165
125
  }
166
126
  return this;
167
127
  }
128
+ #addRoute(method, path, handlers) {
129
+ let pattern = `/${sanitizePathSplitBasePath(this.basePath, path).join("/")}`;
130
+ this.router?.addRoute(method, pattern, handlers);
131
+ this.route.push({
132
+ method: method,
133
+ pattern: pattern,
134
+ handlers: handlers,
135
+ });
136
+ }
168
137
  #registerRoute(method, path, ...args) {
169
138
  if (args.length === 0) {
170
- throw new Error("At least one handler is required.");
139
+ throw new TezXError("At least one handler is required.");
171
140
  }
172
141
  let middlewares = [];
173
142
  let callback;
@@ -184,289 +153,21 @@ export class Router extends MiddlewareConfigure {
184
153
  callback = args[0];
185
154
  }
186
155
  if (typeof callback !== "function") {
187
- throw new Error("Route callback function is missing or invalid.");
156
+ throw new TezXError("Route callback function is missing or invalid.");
188
157
  }
189
158
  if (!middlewares.every((middleware) => typeof middleware === "function")) {
190
- throw new Error("Middleware must be a function or an array of functions.");
191
- }
192
- this.#addRoute(method, path, callback, middlewares);
193
- }
194
- #addRoute(method, path, callback, middlewares) {
195
- let finalMiddleware = middlewares;
196
- if (!GlobalConfig.allowDuplicateMw) {
197
- finalMiddleware = new Set(middlewares);
198
- }
199
- if (path instanceof RegExp) {
200
- let regex = addBaseToRegex(this.basePath, path);
201
- let regexPath = `regex://${regex?.source}`;
202
- let handler = this.routers.get(regexPath);
203
- if (!handler) {
204
- handler = new Map();
205
- handler.set(method, {
206
- callback: callback,
207
- paramNames: [],
208
- regex: regex,
209
- middlewares: finalMiddleware,
210
- });
211
- return this.routers.set(regexPath, handler);
212
- }
213
- if (!GlobalConfig.overwriteMethod && handler.has(method))
214
- return;
215
- return handler.set(method, {
216
- callback: callback,
217
- paramNames: [],
218
- regex: regex,
219
- middlewares: finalMiddleware
220
- });
221
- }
222
- const parts = sanitizePathSplit(this.basePath, path);
223
- let p = parts.join("/");
224
- if (wildcardOrOptionalParamRegex.test(`/${p}`)) {
225
- let strPath = `string://${p}`;
226
- let { paramNames, regex } = compileRegexRoute(parts);
227
- let handler = this.routers.get(strPath);
228
- if (!handler) {
229
- handler = new Map();
230
- handler.set(method, {
231
- callback: callback,
232
- regex: regex,
233
- paramNames: paramNames,
234
- middlewares: finalMiddleware,
235
- });
236
- return this.routers.set(strPath, handler);
237
- }
238
- if (!GlobalConfig.overwriteMethod && handler.has(method))
239
- return;
240
- return handler.set(method, {
241
- callback: callback,
242
- regex: regex,
243
- paramNames: paramNames,
244
- middlewares: finalMiddleware
245
- });
246
- }
247
- let node = this.triRouter;
248
- for (const part of parts) {
249
- if (part.startsWith(":")) {
250
- if (!node.children.has(":")) {
251
- node.children.set(":", new TrieRouter());
252
- }
253
- node = node.children.get(":");
254
- node.isParam = true;
255
- if (!node.paramName) {
256
- node.paramName = part.slice(1);
257
- }
258
- }
259
- else {
260
- if (!node.children.has(part)) {
261
- node.children.set(part, new TrieRouter());
262
- }
263
- node = node.children.get(part);
264
- }
159
+ throw new TezXError("Middleware must be a function or an array of functions.");
265
160
  }
266
- if (!GlobalConfig.overwriteMethod && node.handlers.has(method))
267
- return;
268
- node.handlers.set(method, {
269
- callback: callback,
270
- middlewares: finalMiddleware,
271
- });
272
- node.pathname = `/${p}`;
273
- }
274
- #addRouteMiddleware(path, middlewareFunctions) {
275
- this.addMiddleware(path, middlewareFunctions);
161
+ this.#addRoute(method, path, [...middlewares, callback]);
276
162
  }
277
- #routeAddTriNode(path, router) {
163
+ #addRouterInstance(path, router) {
278
164
  this.env = { ...this.env, ...router.env };
279
165
  if (!(router instanceof Router)) {
280
- throw new Error("Router instance is required.");
281
- }
282
- const parts = sanitizePathSplit(this.basePath, path);
283
- if (router.routers.size) {
284
- for (const [segment, handlers] of router.routers) {
285
- if (segment.indexOf("string://") == 0) {
286
- let pattern = segment.replace(/^string:\/\//, "");
287
- let joined = [...parts, pattern].join("/");
288
- let strPath = `string://${joined}`;
289
- if (this.routers.has(strPath)) {
290
- const baseRouter = this.routers.get(strPath);
291
- for (const [method, handler] of handlers) {
292
- let { regex, paramNames } = baseRouter?.get(method);
293
- handler.regex = regex;
294
- handler.paramNames = paramNames;
295
- if (!GlobalConfig.overwriteMethod && baseRouter.has(method))
296
- continue;
297
- baseRouter.set(method, handler);
298
- }
299
- }
300
- else {
301
- let h = new Map();
302
- for (const [method, { callback, middlewares }] of handlers) {
303
- let { paramNames, regex } = compileRegexRoute(joined);
304
- h.set(method, {
305
- callback: callback,
306
- middlewares: middlewares,
307
- paramNames,
308
- regex
309
- });
310
- }
311
- this.routers.set(strPath, h);
312
- }
313
- }
314
- else {
315
- let pattern = segment.replace("regex://", "");
316
- let base = parts?.join("/");
317
- let regex = addBaseToRegex(base, new RegExp(pattern));
318
- let regexPath = `regex://${regex.source}`;
319
- if (this.routers.has(regexPath)) {
320
- const baseRouter = this.routers.get(regexPath);
321
- for (const [method, handler] of handlers) {
322
- handler.regex = regex;
323
- handler.paramNames = [];
324
- if (!GlobalConfig.overwriteMethod && baseRouter.has(method))
325
- continue;
326
- baseRouter.set(method, handler);
327
- }
328
- }
329
- else {
330
- let h = new Map();
331
- for (const [method, { callback, middlewares }] of handlers) {
332
- h.set(method, {
333
- callback: callback,
334
- middlewares: middlewares,
335
- paramNames: [],
336
- regex
337
- });
338
- }
339
- this.routers.set(regexPath, h);
340
- }
341
- }
342
- }
343
- }
344
- let rootNode = this.triRouter;
345
- let rootMiddlewares = this.triMiddlewares;
346
- if (parts.length == 0) {
347
- this.#addMiddlewareHandlerIDsTriNode(rootNode, rootMiddlewares, router);
348
- }
349
- else {
350
- for (const part of parts) {
351
- if (part.startsWith(":")) {
352
- if (!rootNode.children.has(":")) {
353
- rootNode.children.set(":", new TrieRouter());
354
- }
355
- rootNode = rootNode.children.get(":");
356
- rootNode.isParam = true;
357
- if (!rootNode.paramName) {
358
- rootNode.paramName = part.slice(1);
359
- }
360
- }
361
- else {
362
- if (!rootNode.children.has(part)) {
363
- rootNode.children.set(part, new TrieRouter());
364
- }
365
- rootNode = rootNode.children.get(part);
366
- }
367
- }
368
- for (const part of parts) {
369
- if (part.startsWith("*")) {
370
- if (!rootMiddlewares.children.has("*")) {
371
- rootMiddlewares.children.set("*", new TriMiddleware());
372
- }
373
- rootMiddlewares = rootMiddlewares.children.get("*");
374
- }
375
- else if (part.startsWith(":")) {
376
- const isOptional = part?.endsWith("?");
377
- if (isOptional) {
378
- rootMiddlewares.isOptional = isOptional;
379
- continue;
380
- }
381
- if (!rootMiddlewares.children.has(":")) {
382
- rootMiddlewares.children.set(":", new TriMiddleware());
383
- }
384
- rootMiddlewares = rootMiddlewares.children.get(":");
385
- }
386
- else {
387
- if (!rootMiddlewares.children.has(part)) {
388
- rootMiddlewares.children.set(part, new TriMiddleware());
389
- }
390
- rootMiddlewares = rootMiddlewares.children.get(part);
391
- }
392
- }
393
- this.#addMiddlewareHandlerIDsTriNode(rootNode, rootMiddlewares, router);
394
- }
395
- }
396
- #addMiddlewareHandlerIDsTriNode(rootNode, rootMiddlewares, router) {
397
- function addSubRouter(children, node) {
398
- let rtN = node;
399
- for (const element of children) {
400
- const pathSegment = element[0];
401
- const subRouter = element[1];
402
- if (rtN.children.has(pathSegment)) {
403
- let findNode = rtN.children.get(pathSegment);
404
- for (const [method, handlers] of subRouter.handlers) {
405
- if (!GlobalConfig.overwriteMethod && node.handlers.has(method))
406
- return;
407
- findNode.handlers.set(method, handlers);
408
- }
409
- if (subRouter.children.size) {
410
- addSubRouter(subRouter.children, findNode);
411
- }
412
- }
413
- else {
414
- rtN.children.set(pathSegment, subRouter);
415
- }
416
- }
417
- }
418
- let routerNode = router.triRouter;
419
- const routerMiddlewares = router.triMiddlewares;
420
- for (const [method, handlers] of routerNode.handlers) {
421
- if (!GlobalConfig.overwriteMethod) {
422
- rootNode.handlers.set(method, handlers);
423
- continue;
424
- }
425
- if (!rootNode.handlers.has(method)) {
426
- rootNode.handlers.set(method, handlers);
427
- }
428
- }
429
- if (routerNode.children.size > 0) {
430
- addSubRouter(routerNode.children, rootNode);
431
- }
432
- function addMiddleware(children, node) {
433
- let n = node;
434
- for (const [path, middlewareNode] of children) {
435
- if (n.children.has(path)) {
436
- let findNode = n.children.get(path);
437
- if (GlobalConfig.allowDuplicateMw) {
438
- findNode.middlewares.push(...middlewareNode.middlewares);
439
- }
440
- else {
441
- for (const mw of middlewareNode.middlewares) {
442
- if (findNode.middlewares.has(mw)) {
443
- middlewareNode.middlewares.delete(mw);
444
- }
445
- findNode.middlewares.add(mw);
446
- }
447
- }
448
- if (middlewareNode.children.size) {
449
- addMiddleware(middlewareNode.children, findNode);
450
- }
451
- }
452
- else {
453
- n.children.set(path, middlewareNode);
454
- }
455
- }
456
- }
457
- if (GlobalConfig.allowDuplicateMw) {
458
- rootMiddlewares.middlewares.push(...routerMiddlewares.middlewares);
459
- }
460
- else {
461
- for (const mw of routerMiddlewares.middlewares) {
462
- if (rootMiddlewares.middlewares.has(mw)) {
463
- routerMiddlewares.middlewares.delete(mw);
464
- }
465
- rootMiddlewares.middlewares.add(mw);
466
- }
467
- }
468
- if (routerMiddlewares.children.size > 0) {
469
- addMiddleware(routerMiddlewares.children, rootMiddlewares);
166
+ throw new TezXError("Router instance is required.");
470
167
  }
168
+ router.route.forEach((r) => {
169
+ this.#addRoute(r?.method, `/${sanitizePathSplitBasePath(path, r?.pattern).join("/")}`, r?.handlers);
170
+ });
171
+ Object.assign(this.staticFile, router.staticFile);
471
172
  }
472
173
  }
package/core/server.d.ts CHANGED
@@ -1,33 +1,6 @@
1
- import { ConnAddress, HTTPMethod, Middleware } from "../types/index.js";
2
- import { Context } from "./context.js";
1
+ import { Callback, ErrorHandler, RouteRegistry } from "../types/index.js";
3
2
  import { Router, RouterConfig } from "./router.js";
4
- export type TezXServeOptions = {
5
- connInfo: ConnAddress;
6
- };
7
3
  export type TezXConfig = {
8
- /**
9
- * `allowDuplicateMw` determines whether duplicate middleware functions
10
- * are allowed in the router.
11
- *
12
- * - When `true`: The same middleware can be added multiple times.
13
- * - When `false`: Ensures each middleware is registered only once
14
- * per route or application context.
15
- *
16
- * @default false
17
- */
18
- allowDuplicateMw?: boolean;
19
- /**
20
- * `overwriteMethod` controls whether existing route handlers
21
- * should be overwritten when a new handler for the same
22
- * HTTP method and path is added.
23
- *
24
- * - When `true`: The new handler replaces the existing one.
25
- * - When `false`: Prevents overwriting, ensuring that the
26
- * first registered handler remains active.
27
- *
28
- * @default true
29
- */
30
- overwriteMethod?: boolean;
31
4
  /**
32
5
  * 🔄 Hook to transform or normalize the incoming request pathname before routing.
33
6
  *
@@ -47,6 +20,11 @@ export type TezXConfig = {
47
20
  * @returns The transformed or resolved path used for routing (e.g., `/api/users`)
48
21
  */
49
22
  onPathResolve?: (pathname: string) => string;
23
+ /**
24
+ * Custom route registry instance used internally to store routes.
25
+ * If not provided, the router will use the default CombineRouteRegistry.
26
+ */
27
+ routeRegistry?: RouteRegistry;
50
28
  /**
51
29
  * Enables or disables debugging for the middleware.
52
30
  * When set to `true`, detailed debug logs will be output,
@@ -56,16 +34,99 @@ export type TezXConfig = {
56
34
  */
57
35
  debugMode?: boolean;
58
36
  } & RouterConfig;
37
+ /**
38
+ * TezX is an ultra-fast, flexible request router and server handler.
39
+ * It supports plug-and-play for Bun, and Node runtimes.
40
+ *
41
+ * @template T - The environment object shared across requests.
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * const app = new TezX();
46
+ *
47
+ * app.get("/hello", (ctx) => ctx.text("Hello TezX"));
48
+ * bunAdapter(app).listen();
49
+ * ```
50
+ */
59
51
  export declare class TezX<T extends Record<string, any> = {}> extends Router<T> {
60
52
  #private;
61
- constructor({ basePath, env, debugMode, onPathResolve, allowDuplicateMw, overwriteMethod, }?: TezXConfig);
62
- protected findRoute(method: HTTPMethod, pathname: string): {
63
- callback: any;
64
- middlewares: Middleware<T>[];
65
- params: Record<string, null | string>;
66
- } | null;
67
- serve(req: Request, options: TezXServeOptions): Promise<Response | {
68
- websocket: (props: any) => any;
69
- ctx: Context;
70
- }>;
53
+ /** Internal route registry to hold all routes */
54
+ protected router?: RouteRegistry;
55
+ constructor({ basePath, env, debugMode, onPathResolve, routeRegistry, }?: TezXConfig);
56
+ /**
57
+ * Register a custom 404 (not found) handler.
58
+ *
59
+ * @param callback - Function to handle unmatched routes.
60
+ * @returns The current TezX instance (for chaining).
61
+ *
62
+ * @example
63
+ * app.notFound((ctx) => ctx.status(404).text("Oops! Page not found."));
64
+ */
65
+ notFound(callback: Callback<T>): this;
66
+ /**
67
+ * Register a global error handler for uncaught route errors.
68
+ *
69
+ * @param callback - Function to handle thrown exceptions or failed routes.
70
+ * @returns The current TezX instance (for chaining).
71
+ *
72
+ * @example
73
+ * app.onError((err, ctx) => {
74
+ * return ctx.status(500).text("Server crashed!");
75
+ * });
76
+ */
77
+ onError(callback: ErrorHandler<T>): this;
78
+ /**
79
+ * Main request handler compatible with multiple runtimes (Node.js, Deno, Bun).
80
+ *
81
+ * This function can be passed directly to native HTTP servers to handle incoming requests.
82
+ *
83
+ * ### Usage examples:
84
+ *
85
+ * #### Bun
86
+ * ```ts
87
+ * // Simple usage with Bun's built-in HTTP server
88
+ * app.serve(request, server);
89
+ *
90
+ * // Or with WebSocket support (required for ws handling)
91
+ * Bun.serve({
92
+ * port: 3001,
93
+ * reusePort: true, // enables SO_REUSEPORT for clustering
94
+ * fetch: app.serve,
95
+ * websocket: wsHandlers()
96
+ * });
97
+ * ```
98
+ *
99
+ * #### Deno
100
+ * ```ts
101
+ * // Using Deno’s serve method with connection info
102
+ * serve((req, connInfo) => app.serve(req, connInfo));
103
+ *
104
+ * // Or using Deno’s built-in Deno.serve with options
105
+ * Deno.serve({ port: 8080 }, app.serve);
106
+ * ```
107
+ *
108
+ * #### Node.js
109
+ * ```ts
110
+ * import { createServer } from "http";
111
+ * import { mountTezXOnNode } from "tezx/node";
112
+ *
113
+ * // Option 1: Manually convert and forward request/response
114
+ * const response = await app.serve(toWebRequest(req, req.method), req, res, server);
115
+ *
116
+ * // Option 2: Use provided utility to mount TezX app onto native HTTP server
117
+ * const server = createServer();
118
+ * mountTezXOnNode(app, server);
119
+ * server.listen(3000);
120
+ * ```
121
+ *
122
+ * @param {Request} req - Native Fetch API Request object.
123
+ * @param {...any} args - Runtime-specific arguments such as connection info (Deno), server instances, or response objects.
124
+ * @returns {Promise<Response>} The final response to be sent back to the client or the result of WebSocket handlers.
125
+ *
126
+ * @example
127
+ * ```ts
128
+ * const response = await app.serve(new Request("http://localhost/hello"));
129
+ * ```
130
+ */
131
+ serve(req: Request, ...args: any[]): Promise<Response>;
71
132
  }