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
@@ -0,0 +1,52 @@
1
+ import { readdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { extensionExtract, sanitizePathSplitBasePath, } from "../utils/low-level.js";
4
+ import { TezXError } from "../core/error.js";
5
+ export function serveStatic(...args) {
6
+ let route = "";
7
+ let dir;
8
+ let options = {};
9
+ switch (args.length) {
10
+ case 3:
11
+ [route, dir, options] = args;
12
+ break;
13
+ case 2:
14
+ if (typeof args[1] === "object") {
15
+ [dir, options] = args;
16
+ }
17
+ else {
18
+ [route, dir] = args;
19
+ }
20
+ break;
21
+ case 1:
22
+ [dir] = args;
23
+ break;
24
+ default:
25
+ throw new TezXError(`\x1b[1;31m404 Not Found\x1b[0m \x1b[1;32mInvalid arguments\x1b[0m`);
26
+ }
27
+ return {
28
+ files: getFiles(dir, route, options),
29
+ options,
30
+ };
31
+ }
32
+ export function getFiles(dir, basePath = "/", option = {}) {
33
+ const files = [];
34
+ const entries = readdirSync(dir, { withFileTypes: true });
35
+ for (const entry of entries) {
36
+ const fullPath = join(dir, entry.name);
37
+ if (entry.isDirectory()) {
38
+ files.push(...getFiles(fullPath, `${basePath}/${entry.name}`, option));
39
+ }
40
+ else {
41
+ const ext = extensionExtract(entry.name);
42
+ if (option?.extensions?.length && !option.extensions.includes(ext)) {
43
+ continue;
44
+ }
45
+ files.push({
46
+ fileSource: fullPath,
47
+ route: `/${sanitizePathSplitBasePath(basePath, entry.name).join("/")}`,
48
+ });
49
+ }
50
+ }
51
+ return files;
52
+ }
@@ -0,0 +1,22 @@
1
+ import { Readable } from "node:stream";
2
+ export function toWebRequest(req, method = "GET") {
3
+ const protocol = req.socket && req.socket.encrypted ? "https:" : "http:";
4
+ const upperMethod = method.length === 3
5
+ ? method === "get"
6
+ ? "GET"
7
+ : method === "put"
8
+ ? "PUT"
9
+ : method.toUpperCase()
10
+ : method.toUpperCase();
11
+ let host = req.headers.host || "localhost";
12
+ const hasBody = upperMethod !== "GET" && upperMethod !== "HEAD";
13
+ const abortController = new AbortController();
14
+ req?.once("close", () => abortController.abort());
15
+ return new Request(protocol + "//" + host + (req.url ?? "/"), {
16
+ method,
17
+ headers: req?.headers,
18
+ body: hasBody ? Readable.toWeb(req) : undefined,
19
+ signal: abortController.signal,
20
+ duplex: hasBody ? "half" : undefined,
21
+ });
22
+ }
package/node/ws.d.ts ADDED
@@ -0,0 +1,56 @@
1
+ import type { PerMessageDeflateOptions } from "ws";
2
+ import { Middleware, WebSocketCallback, WebSocketOptions } from "../types/index.js";
3
+ export type nodeWebSocketOptions = {
4
+ /**
5
+ * Enables per-message deflate compression. Can be a boolean or a detailed config. (Node.js only)
6
+ */
7
+ perMessageDeflate?: boolean | PerMessageDeflateOptions;
8
+ /**
9
+ * Maximum allowed message size in bytes. Default is 1MB if not provided. (Node.js only)
10
+ */
11
+ maxPayload?: number;
12
+ };
13
+ /**
14
+ * Creates a Node.js-specific WebSocket upgrade middleware.
15
+ *
16
+ * This middleware validates WebSocket upgrade headers and upgrades the HTTP connection
17
+ * to a WebSocket connection using the `ws` library. It binds event handlers
18
+ * (`open`, `message`, `close`, `error`, `ping`, `pong`) based on the provided callback.
19
+ *
20
+ * @template T - Context type extending object with `wsProtocol` property ("ws" or "wss").
21
+ * @template Path - Route path type (string).
22
+ *
23
+ * @param {WebSocketCallback} callback - Function that returns WebSocket event handlers.
24
+ * @param {WebSocketOptions} [options={}] - Options for WebSocket upgrade behavior.
25
+ * @param {(error: TezXError, ctx: T) => any} [options.onUpgradeError] - Custom error handler for upgrade failures.
26
+ * @param {number} [options.maxPayload=1048576] - Maximum allowed payload size (in bytes).
27
+ * @param {boolean} [options.perMessageDeflate=false] - Whether to enable per-message deflate.
28
+ *
29
+ * @returns {Middleware<T, Path>} Middleware function for handling WebSocket upgrade requests.
30
+ *
31
+ * @throws Will return a 401 response if WebSocket upgrade headers are invalid.
32
+ * @throws Will return a 500 response if Node.js HTTP server instance is missing in context arguments.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * import { upgradeWebSocket } from "./nodeWebSocket.js";
37
+ *
38
+ * const wsMiddleware = upgradeWebSocket(ctx => ({
39
+ * open(ws) {
40
+ * console.log("WebSocket connection opened");
41
+ * },
42
+ * message(ws, data) {
43
+ * console.log("Received message:", data);
44
+ * },
45
+ * close(ws, event) {
46
+ * console.log("Connection closed:", event.code, event.reason);
47
+ * },
48
+ * error(ws, err) {
49
+ * console.error("WebSocket error:", err);
50
+ * },
51
+ * }));
52
+ * ```
53
+ */
54
+ export declare function upgradeWebSocket<T extends Record<string, any> & {
55
+ wsProtocol: "wss" | "ws";
56
+ }, Path extends string = any>(callback: WebSocketCallback, options?: WebSocketOptions & nodeWebSocketOptions): Middleware<T, Path>;
package/node/ws.js ADDED
@@ -0,0 +1,46 @@
1
+ import { TezXError } from "../core/error.js";
2
+ export function upgradeWebSocket(callback, options = {}) {
3
+ const { onUpgradeError = (error, ctx) => {
4
+ ctx.setStatus = 401;
5
+ return ctx.text(error.message);
6
+ }, } = options;
7
+ return async (ctx, next) => {
8
+ const upgrade = ctx.req.header("upgrade")?.toLowerCase();
9
+ const connection = ctx.req.header("connection")?.toLowerCase();
10
+ const key = ctx.req.header("sec-websocket-key");
11
+ if (upgrade !== "websocket" || !connection?.includes("upgrade") || !key) {
12
+ if (next) {
13
+ ctx.body = { error: "401 Bad Request: Invalid WebSocket headers" };
14
+ return next();
15
+ }
16
+ ctx.setStatus = 401;
17
+ return onUpgradeError(new TezXError("401 Bad Request: Invalid WebSocket headers", 401), ctx);
18
+ }
19
+ ctx.wsProtocol = ctx.url?.startsWith("https") ? "wss" : "ws";
20
+ const server = ctx.args?.[2];
21
+ if (!server?.on) {
22
+ ctx.setStatus = 500;
23
+ return onUpgradeError(new TezXError("Node server instance missing for WebSocket", 426), ctx);
24
+ }
25
+ const { WebSocketServer } = await import("ws");
26
+ const wss = new WebSocketServer({
27
+ noServer: true,
28
+ maxPayload: options.maxPayload ?? 1048576,
29
+ perMessageDeflate: options.perMessageDeflate ?? false,
30
+ });
31
+ server.on("upgrade", (request, socket, head) => {
32
+ wss?.handleUpgrade(request, socket, head, (ws) => {
33
+ wss?.emit("connection", ws, request);
34
+ let event = callback(ctx);
35
+ event.open?.(ws);
36
+ ws.on("open", () => event.open?.(ws));
37
+ ws.on("message", (data) => event.message?.(ws, data));
38
+ ws.on("close", (code, reason) => event.close?.(ws, { code, reason }));
39
+ ws.on("error", (err) => event.error?.(ws, err));
40
+ ws.on("ping", (data) => event.ping?.(ws, data));
41
+ ws.on("pong", (data) => event.pong?.(ws, data));
42
+ });
43
+ });
44
+ return next();
45
+ };
46
+ }
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "tezx",
3
- "version": "2.0.11",
3
+ "version": "3.0.0",
4
4
  "description": "TezX is a high-performance, lightweight JavaScript framework designed for speed, scalability, and flexibility. It enables efficient routing, middleware management, and static file serving with minimal configuration. Fully compatible with Node.js, Deno, and Bun.",
5
+ "type": "module",
5
6
  "main": "cjs/index.js",
6
7
  "module": "index.js",
7
8
  "types": "index.d.ts",
@@ -19,60 +20,68 @@
19
20
  ".": {
20
21
  "import": "./index.js",
21
22
  "require": "./cjs/index.js",
22
- "types": "./index.d.ts",
23
- "default": "./index.js"
23
+ "types": "./index.d.ts"
24
24
  },
25
- "./middleware": {
26
- "import": "./middleware/index.js",
27
- "require": "./cjs/middleware/index.js",
28
- "types": "./middleware/index.d.ts",
29
- "default": "./middleware/index.js"
25
+ "./bun": {
26
+ "import": "./bun/index.js",
27
+ "require": "./cjs/bun/index.js",
28
+ "types": "./bun/index.d.ts"
30
29
  },
31
30
  "./node": {
32
31
  "import": "./node/index.js",
33
32
  "require": "./cjs/node/index.js",
34
- "types": "./node/index.d.ts",
35
- "default": "./node/index.js"
36
- },
37
- "./bun": {
38
- "import": "./bun/index.js",
39
- "require": "./cjs/bun/index.js",
40
- "types": "./bun/index.d.ts",
41
- "default": "./bun/index.js"
33
+ "types": "./node/index.d.ts"
42
34
  },
43
35
  "./deno": {
44
36
  "import": "./deno/index.js",
45
37
  "require": "./cjs/deno/index.js",
46
- "types": "./deno/index.d.ts",
47
- "default": "./deno/index.js"
38
+ "types": "./deno/index.d.ts"
48
39
  },
49
40
  "./helper": {
50
41
  "import": "./helper/index.js",
51
42
  "require": "./cjs/helper/index.js",
52
- "types": "./helper/index.d.ts",
53
- "default": "./helper/index.js"
43
+ "types": "./helper/index.d.ts"
54
44
  },
55
- "./ws": {
56
- "import": "./ws/index.js",
57
- "require": "./cjs/ws/index.js",
58
- "types": "./ws/index.d.ts",
59
- "default": "./ws/index.js"
45
+ "./jwt/node": {
46
+ "import": "./jwt/node.js",
47
+ "require": "./cjs/jwt/node.js",
48
+ "types": "./jwt/node.d.ts"
49
+ },
50
+ "./jwt/web": {
51
+ "import": "./jwt/web.js",
52
+ "require": "./cjs/jwt/web.js",
53
+ "types": "./jwt/web.d.ts"
54
+ },
55
+ "./registry": {
56
+ "import": "./registry/index.js",
57
+ "require": "./cjs/registry/index.js",
58
+ "types": "./registry/index.d.ts"
59
+ },
60
+ "./middleware": {
61
+ "import": "./middleware/index.js",
62
+ "require": "./cjs/middleware/index.js",
63
+ "types": "./middleware/index.d.ts"
64
+ },
65
+ "./middleware/*": {
66
+ "import": "./middleware/*.js",
67
+ "require": "./cjs/middleware/*.js",
68
+ "types": "./middleware/*.d.ts"
60
69
  }
61
70
  },
62
71
  "files": [
63
- "adapter/",
64
72
  "bun/",
65
73
  "cjs/",
66
74
  "core/",
67
75
  "deno/",
68
76
  "helper/",
69
- "node/",
77
+ "jwt/",
70
78
  "middleware/",
79
+ "node/",
80
+ "registry/",
71
81
  "types/",
72
82
  "utils/",
73
- "ws/",
74
- "index.js",
75
- "index.d.ts"
83
+ "index.d.ts",
84
+ "index.js"
76
85
  ],
77
86
  "keywords": [
78
87
  "server",
@@ -0,0 +1,40 @@
1
+ import type { Callback, HTTPMethod, Middleware, RouteMatchResult, RouteRegistry } from "../types/index.js";
2
+ /**
3
+ * Radix-based router implementation for efficient route matching.
4
+ * Supports static, dynamic, optional, and wildcard parameters.
5
+ */
6
+ export declare class RadixRouter implements RouteRegistry {
7
+ private root;
8
+ name: string;
9
+ constructor();
10
+ /**
11
+ * Adds a new route to the radix tree.
12
+ *
13
+ * @param method - HTTP method (GET, POST, etc.)
14
+ * @param path - Route path, e.g., "/users/:id?"
15
+ * @param handlers - Array of handler functions or middleware
16
+ * @throws Error if conflicting parameter definitions are detected
17
+ */
18
+ addRoute(method: HTTPMethod, path: string, handlers: (Callback | Middleware)[]): void;
19
+ /**
20
+ * Searches for a route match based on HTTP method and URL path.
21
+ *
22
+ * @param method - HTTP method to match
23
+ * @param path - Request path
24
+ * @returns RouteMatchResult containing handlers, middlewares, and parameters
25
+ */
26
+ search(method: HTTPMethod, path: string): RouteMatchResult;
27
+ /**
28
+ * Recursively matches the route path segments.
29
+ *
30
+ * @private
31
+ */
32
+ private _match;
33
+ /**
34
+ * Parses a route pattern into structured segments.
35
+ *
36
+ * @param pattern - The route string (e.g., "/users/:id?")
37
+ * @returns Parsed segments containing type, value, paramName, and optionality
38
+ */
39
+ private parsePattern;
40
+ }
@@ -0,0 +1,144 @@
1
+ import { TezXError } from "../core/error.js";
2
+ import { sanitizePathSplit } from "../helper/index.js";
3
+ export class RadixRouter {
4
+ root = { children: {} };
5
+ name;
6
+ constructor() {
7
+ this.name = "RadixRouter";
8
+ }
9
+ addRoute(method, path, handlers) {
10
+ const segments = this.parsePattern(path);
11
+ let node = this.root;
12
+ for (let i = 0; i < segments.length; i++) {
13
+ const { type, value, paramName, isOptional } = segments[i];
14
+ if (type === "static") {
15
+ node = node.children[value] ??= { children: {} };
16
+ }
17
+ else if (type === "dynamic") {
18
+ if (!node.children[":"]) {
19
+ node.children[":"] = { children: {}, paramName, isOptional };
20
+ }
21
+ else if (node.children[":"]?.paramName !== paramName ||
22
+ node.children[":"]?.isOptional !== isOptional) {
23
+ throw new TezXError(`Conflicting param definition for ${paramName}`);
24
+ }
25
+ node = node.children[":"];
26
+ }
27
+ else if (type === "wildcard") {
28
+ node = node.children["*"] ??= { children: {}, paramName };
29
+ break;
30
+ }
31
+ }
32
+ node.isEndpoint = true;
33
+ node.handlers ??= {};
34
+ node.handlers[method] ??= [];
35
+ node.handlers[method].push(...(handlers || []));
36
+ }
37
+ search(method, path) {
38
+ let params = {};
39
+ let middlewares = [];
40
+ const { success, node } = this._match(method, this.root, path?.split("/")?.filter(Boolean), 0, params, middlewares);
41
+ if (success && node) {
42
+ const handlers = node.handlers?.[method] ?? [];
43
+ return { method, params, handlers, middlewares };
44
+ }
45
+ return { method, params: {}, handlers: [], middlewares };
46
+ }
47
+ _match(method, node, segments, index, params, middlewares) {
48
+ if (node?.handlers?.ALL) {
49
+ const mw = node.handlers?.ALL;
50
+ for (let i = 0; i < mw.length; i++) {
51
+ middlewares.push(mw[i]);
52
+ }
53
+ }
54
+ if (index === segments.length) {
55
+ if (node.isEndpoint && node.handlers?.[method])
56
+ return { success: true, node };
57
+ const opt = node.children[":"];
58
+ if (opt?.isOptional) {
59
+ params[opt.paramName] = null;
60
+ return this._match(method, opt, segments, index, params, middlewares);
61
+ }
62
+ return { success: false, node: node };
63
+ }
64
+ const wc = node.children["*"];
65
+ const seg = segments[index];
66
+ if (node.children[seg]) {
67
+ const res = this._match(method, node.children[seg], segments, index + 1, params, middlewares);
68
+ if (res.success) {
69
+ if (wc?.handlers?.ALL) {
70
+ const mw = wc.handlers?.ALL;
71
+ for (let i = 0; i < mw.length; i++) {
72
+ middlewares.push(mw[i]);
73
+ }
74
+ }
75
+ return res;
76
+ }
77
+ }
78
+ const dyn = node.children[":"];
79
+ if (dyn) {
80
+ params[dyn.paramName] = seg;
81
+ const res = this._match(method, dyn, segments, index + 1, params, middlewares);
82
+ if (res.success) {
83
+ if (wc?.handlers?.ALL) {
84
+ const mw = wc.handlers?.ALL;
85
+ for (let i = 0; i < mw.length; i++) {
86
+ middlewares.push(mw[i]);
87
+ }
88
+ }
89
+ return res;
90
+ }
91
+ if (dyn.isOptional) {
92
+ params[dyn.paramName] = null;
93
+ const skip = this._match(method, dyn, segments, index, params, middlewares);
94
+ if (skip.success) {
95
+ if (wc?.handlers?.ALL) {
96
+ const mw = wc.handlers?.ALL;
97
+ for (let i = 0; i < mw.length; i++) {
98
+ middlewares.push(mw[i]);
99
+ }
100
+ }
101
+ return skip;
102
+ }
103
+ }
104
+ }
105
+ if (wc) {
106
+ let wildcard = segments.slice(index).join("/");
107
+ if (wc?.handlers?.ALL) {
108
+ const mw = wc.handlers?.ALL;
109
+ for (let i = 0; i < mw.length; i++) {
110
+ middlewares.push(mw[i]);
111
+ }
112
+ }
113
+ if (wildcard) {
114
+ params[wc.paramName] = wildcard;
115
+ return { node: wc, success: true };
116
+ }
117
+ }
118
+ return { success: false, node };
119
+ }
120
+ parsePattern(pattern) {
121
+ const segments = sanitizePathSplit(pattern);
122
+ const result = [];
123
+ for (const segment of segments) {
124
+ if (segment === "*") {
125
+ result.push({ type: "wildcard", paramName: "*" });
126
+ break;
127
+ }
128
+ else if (segment.startsWith("*")) {
129
+ const paramName = segment.slice(1) || "*";
130
+ result.push({ type: "wildcard", paramName });
131
+ break;
132
+ }
133
+ else if (segment.startsWith(":")) {
134
+ const isOptional = segment.endsWith("?");
135
+ const paramName = isOptional ? segment.slice(1, -1) : segment.slice(1);
136
+ result.push({ type: "dynamic", paramName, isOptional });
137
+ }
138
+ else {
139
+ result.push({ type: "static", value: segment });
140
+ }
141
+ }
142
+ return result;
143
+ }
144
+ }
@@ -0,0 +1,2 @@
1
+ export { HandlerType, RouteMatchResult, RouteRegistry, } from "../types/index.js";
2
+ export * from "./RadixRouter.js";
@@ -0,0 +1 @@
1
+ export * from "./RadixRouter.js";
@@ -0,0 +1,2 @@
1
+ export type RequestHeader = "A-IM" | "Accept" | "Accept-Additions" | "Accept-CH" | "Accept-Charset" | "Accept-Datetime" | "Accept-Encoding" | "Accept-Features" | "Accept-Language" | "Accept-Patch" | "Accept-Post" | "Accept-Ranges" | "Accept-Signature" | "Access-Control" | "Access-Control-Allow-Credentials" | "Access-Control-Allow-Headers" | "Access-Control-Allow-Methods" | "Access-Control-Allow-Origin" | "Access-Control-Expose-Headers" | "Access-Control-Max-Age" | "Access-Control-Request-Headers" | "Access-Control-Request-Method" | "Age" | "Allow" | "ALPN" | "Alt-Svc" | "Alt-Used" | "Alternates" | "AMP-Cache-Transform" | "Apply-To-Redirect-Ref" | "Authentication-Control" | "Authentication-Info" | "Authorization" | "Available-Dictionary" | "C-Ext" | "C-Man" | "C-Opt" | "C-PEP" | "C-PEP-Info" | "Cache-Control" | "Cache-Status" | "Cal-Managed-ID" | "CalDAV-Timezones" | "Capsule-Protocol" | "CDN-Cache-Control" | "CDN-Loop" | "Cert-Not-After" | "Cert-Not-Before" | "Clear-Site-Data" | "Client-Cert" | "Client-Cert-Chain" | "Close" | "CMCD-Object" | "CMCD-Request" | "CMCD-Session" | "CMCD-Status" | "CMSD-Dynamic" | "CMSD-Static" | "Concealed-Auth-Export" | "Configuration-Context" | "Connection" | "Content-Base" | "Content-Digest" | "Content-Disposition" | "Content-Encoding" | "Content-ID" | "Content-Language" | "Content-Length" | "Content-Location" | "Content-MD5" | "Content-Range" | "Content-Script-Type" | "Content-Security-Policy" | "Content-Security-Policy-Report-Only" | "Content-Style-Type" | "Content-Type" | "Content-Version" | "Cookie" | "Cookie2" | "Cross-Origin-Embedder-Policy" | "Cross-Origin-Embedder-Policy-Report-Only" | "Cross-Origin-Opener-Policy" | "Cross-Origin-Opener-Policy-Report-Only" | "Cross-Origin-Resource-Policy" | "CTA-Common-Access-Token" | "DASL" | "Date" | "DAV" | "Default-Style" | "Delta-Base" | "Deprecation" | "Depth" | "Derived-From" | "Destination" | "Differential-ID" | "Dictionary-ID" | "Digest" | "DPoP" | "DPoP-Nonce" | "Early-Data" | "EDIINT-Features" | "ETag" | "Expect" | "Expect-CT" | "Expires" | "Ext" | "Forwarded" | "From" | "GetProfile" | "Hobareg" | "Host" | "HTTP2-Settings" | "If" | "If-Match" | "If-Modified-Since" | "If-None-Match" | "If-Range" | "If-Schedule-Tag-Match" | "If-Unmodified-Since" | "IM" | "Include-Referred-Token-Binding-ID" | "Isolation" | "Keep-Alive" | "Label" | "Last-Event-ID" | "Last-Modified" | "Link" | "Link-Template" | "Location" | "Lock-Token" | "Man" | "Max-Forwards" | "Memento-Datetime" | "Meter" | "Method-Check" | "Method-Check-Expires" | "MIME-Version" | "Negotiate" | "NEL" | "OData-EntityId" | "OData-Isolation" | "OData-MaxVersion" | "OData-Version" | "Opt" | "Optional-WWW-Authenticate" | "Ordering-Type" | "Origin" | "Origin-Agent-Cluster" | "OSCORE" | "OSLC-Core-Version" | "Overwrite" | "P3P" | "PEP" | "PEP-Info" | "Permissions-Policy" | "PICS-Label" | "Ping-From" | "Ping-To" | "Position" | "Pragma" | "Prefer" | "Preference-Applied" | "Priority" | "ProfileObject" | "Protocol" | "Protocol-Info" | "Protocol-Query" | "Protocol-Request" | "Proxy-Authenticate" | "Proxy-Authentication-Info" | "Proxy-Authorization" | "Proxy-Features" | "Proxy-Instruction" | "Proxy-Status" | "Public" | "Public-Key-Pins" | "Public-Key-Pins-Report-Only" | "Range" | "Redirect-Ref" | "Referer" | "Referer-Root" | "Referrer-Policy" | "Refresh" | "Repeatability-Client-ID" | "Repeatability-First-Sent" | "Repeatability-Request-ID" | "Repeatability-Result" | "Replay-Nonce" | "Reporting-Endpoints" | "Repr-Digest" | "Retry-After" | "Safe" | "Schedule-Reply" | "Schedule-Tag" | "Sec-GPC" | "Sec-Purpose" | "Sec-Token-Binding" | "Sec-WebSocket-Accept" | "Sec-WebSocket-Extensions" | "Sec-WebSocket-Key" | "Sec-WebSocket-Protocol" | "Sec-WebSocket-Version" | "Security-Scheme" | "Server" | "Server-Timing" | "Set-Cookie" | "Set-Cookie2" | "SetProfile" | "Signature" | "Signature-Input" | "SLUG" | "SoapAction" | "Status-URI" | "Strict-Transport-Security" | "Sunset" | "Surrogate-Capability" | "Surrogate-Control" | "TCN" | "TE" | "Timeout" | "Timing-Allow-Origin" | "Topic" | "Traceparent" | "Tracestate" | "Trailer" | "Transfer-Encoding" | "TTL" | "Upgrade" | "Urgency" | "URI" | "Use-As-Dictionary" | "User-Agent" | "Variant-Vary" | "Vary" | "Via" | "Want-Content-Digest" | "Want-Digest" | "Want-Repr-Digest" | "Warning" | "WWW-Authenticate" | "X-Content-Type-Options" | "X-Frame-Options";
2
+ export type ResponseHeader = "Access-Control-Allow-Credentials" | "Access-Control-Allow-Headers" | "Access-Control-Allow-Methods" | "Access-Control-Allow-Origin" | "Access-Control-Expose-Headers" | "Access-Control-Max-Age" | "Age" | "Allow" | "Cache-Control" | "Clear-Site-Data" | "Content-Disposition" | "Content-Encoding" | "Content-Language" | "Content-Length" | "Content-Location" | "Content-Range" | "Content-Security-Policy" | "Content-Security-Policy-Report-Only" | "Content-Type" | "Cookie" | "Cross-Origin-Embedder-Policy" | "Cross-Origin-Opener-Policy" | "Cross-Origin-Resource-Policy" | "Date" | "ETag" | "Expires" | "Last-Modified" | "Location" | "Permissions-Policy" | "Pragma" | "Retry-After" | "Save-Data" | "Sec-CH-Prefers-Color-Scheme" | "Sec-CH-Prefers-Reduced-Motion" | "Sec-CH-UA" | "Sec-CH-UA-Arch" | "Sec-CH-UA-Bitness" | "Sec-CH-UA-Form-Factor" | "Sec-CH-UA-Full-Version" | "Sec-CH-UA-Full-Version-List" | "Sec-CH-UA-Mobile" | "Sec-CH-UA-Model" | "Sec-CH-UA-Platform" | "Sec-CH-UA-Platform-Version" | "Sec-CH-UA-WoW64" | "Sec-Fetch-Dest" | "Sec-Fetch-Mode" | "Sec-Fetch-Site" | "Sec-Fetch-User" | "Sec-GPC" | "Server" | "Server-Timing" | "Service-Worker-Navigation-Preload" | "Set-Cookie" | "Strict-Transport-Security" | "Timing-Allow-Origin" | "Trailer" | "Transfer-Encoding" | "Upgrade" | "Vary" | "WWW-Authenticate" | "Warning" | "X-Content-Type-Options" | "X-DNS-Prefetch-Control" | "X-Frame-Options" | "X-Permitted-Cross-Domain-Policies" | "X-Powered-By" | "X-Robots-Tag" | "X-XSS-Protection";
@@ -0,0 +1 @@
1
+ export {};