tezx 3.0.14-beta → 3.0.14-beta2

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 (102) hide show
  1. package/bun/env.d.ts +5 -0
  2. package/bun/env.js +44 -0
  3. package/bun/index.d.ts +1 -1
  4. package/bun/index.js +1 -1
  5. package/bun/ws.js +4 -3
  6. package/cjs/bun/env.js +47 -0
  7. package/cjs/bun/index.js +1 -1
  8. package/cjs/bun/ws.js +4 -3
  9. package/cjs/core/context.js +4 -3
  10. package/cjs/core/error.js +8 -0
  11. package/cjs/core/request.js +3 -2
  12. package/cjs/core/router.js +11 -17
  13. package/cjs/core/server.js +14 -9
  14. package/cjs/deno/env.js +2 -1
  15. package/cjs/deno/serveStatic.js +2 -1
  16. package/cjs/deno/ws.js +4 -3
  17. package/cjs/helper/index.js +12 -10
  18. package/cjs/index.js +1 -1
  19. package/cjs/jwt/node.js +94 -0
  20. package/cjs/jwt/web.js +178 -0
  21. package/cjs/middleware/basic-auth.js +9 -14
  22. package/cjs/middleware/bearer-auth.js +5 -5
  23. package/cjs/middleware/cache-control.js +44 -0
  24. package/cjs/middleware/cors.js +1 -1
  25. package/cjs/middleware/detect-bot.js +57 -0
  26. package/cjs/middleware/i18n.js +92 -0
  27. package/cjs/middleware/index.js +5 -0
  28. package/cjs/middleware/logger.js +3 -2
  29. package/cjs/middleware/rate-limiter.js +1 -1
  30. package/cjs/middleware/sanitize-headers.js +1 -1
  31. package/cjs/middleware/secure-headers copy.js +143 -0
  32. package/cjs/middleware/secure-headers.js +157 -0
  33. package/cjs/node/env.js +4 -3
  34. package/cjs/node/serveStatic.js +2 -1
  35. package/cjs/node/ws.js +3 -2
  36. package/cjs/registry/RadixRouter.js +2 -33
  37. package/cjs/utils/buffer.js +17 -0
  38. package/cjs/utils/file.js +28 -6
  39. package/cjs/utils/generateID.js +10 -0
  40. package/cjs/utils/response.js +3 -1
  41. package/core/context.d.ts +3 -3
  42. package/core/context.js +4 -3
  43. package/core/error.d.ts +1 -0
  44. package/core/error.js +7 -0
  45. package/core/request.js +3 -2
  46. package/core/router.d.ts +3 -8
  47. package/core/router.js +11 -17
  48. package/core/server.d.ts +10 -23
  49. package/core/server.js +15 -10
  50. package/deno/env.js +2 -1
  51. package/deno/index.d.ts +1 -1
  52. package/deno/serveStatic.js +2 -1
  53. package/deno/ws.d.ts +1 -1
  54. package/deno/ws.js +4 -3
  55. package/helper/index.d.ts +7 -6
  56. package/helper/index.js +7 -6
  57. package/index.d.ts +5 -2
  58. package/index.js +1 -1
  59. package/jwt/node.d.ts +39 -0
  60. package/jwt/node.js +87 -0
  61. package/jwt/web.d.ts +14 -0
  62. package/jwt/web.js +174 -0
  63. package/middleware/basic-auth.d.ts +2 -1
  64. package/middleware/basic-auth.js +9 -14
  65. package/middleware/bearer-auth.d.ts +2 -1
  66. package/middleware/bearer-auth.js +5 -5
  67. package/middleware/cache-control.d.ts +30 -0
  68. package/middleware/cache-control.js +40 -0
  69. package/middleware/cors.js +1 -1
  70. package/middleware/detect-bot.d.ts +113 -0
  71. package/middleware/detect-bot.js +53 -0
  72. package/middleware/i18n.d.ts +194 -0
  73. package/middleware/i18n.js +88 -0
  74. package/middleware/index.d.ts +5 -0
  75. package/middleware/index.js +5 -0
  76. package/middleware/logger.d.ts +1 -1
  77. package/middleware/logger.js +3 -2
  78. package/middleware/rate-limiter.d.ts +3 -2
  79. package/middleware/rate-limiter.js +1 -1
  80. package/middleware/sanitize-headers.js +1 -1
  81. package/middleware/secure-headers copy.d.ts +15 -0
  82. package/middleware/secure-headers copy.js +136 -0
  83. package/middleware/secure-headers.d.ts +132 -0
  84. package/middleware/secure-headers.js +153 -0
  85. package/node/env.js +4 -3
  86. package/node/serveStatic.d.ts +8 -0
  87. package/node/serveStatic.js +2 -1
  88. package/node/ws.d.ts +1 -1
  89. package/node/ws.js +3 -2
  90. package/package.json +12 -1
  91. package/registry/RadixRouter.js +2 -33
  92. package/types/index.d.ts +1 -1
  93. package/utils/buffer.d.ts +1 -0
  94. package/utils/buffer.js +14 -0
  95. package/utils/file.d.ts +6 -2
  96. package/utils/file.js +27 -6
  97. package/utils/generateID.d.ts +9 -0
  98. package/utils/generateID.js +9 -0
  99. package/utils/response.js +3 -1
  100. package/cjs/utils/regexRouter.js +0 -57
  101. package/utils/regexRouter.d.ts +0 -66
  102. package/utils/regexRouter.js +0 -52
package/utils/file.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { TezXError } from "../core/error.js";
1
2
  import { runtime } from "./runtime.js";
2
3
  export async function fileExists(path) {
3
4
  switch (runtime) {
@@ -37,7 +38,7 @@ export async function getFileBuffer(path) {
37
38
  case "deno":
38
39
  return Deno.readFile(path);
39
40
  default:
40
- throw new Error("Unsupported runtime environment");
41
+ throw new TezXError("Unsupported runtime environment");
41
42
  }
42
43
  }
43
44
  export async function readStream(path) {
@@ -54,22 +55,42 @@ export async function readStream(path) {
54
55
  return (await Deno.open(path, { read: true })).readable;
55
56
  }
56
57
  default:
57
- throw new Error("Unsupported runtime environment");
58
+ throw new TezXError("Unsupported runtime environment");
58
59
  }
59
60
  }
60
61
  export async function fileSize(path) {
61
62
  switch (runtime) {
62
63
  case "node": {
63
64
  const { stat } = await import("node:fs/promises");
64
- return (await stat(path)).size;
65
+ const st = await stat(path);
66
+ return { size: st.size, mtime: st.mtime };
65
67
  }
66
68
  case "bun": {
67
- return Bun.file(path).size;
69
+ const st = await Bun.file(path).stat();
70
+ return { size: st.size, mtime: st.mtime };
68
71
  }
69
72
  case "deno": {
70
- return (await Deno.stat(path)).size;
73
+ const st = await Deno.stat(path);
74
+ return {
75
+ size: st.size,
76
+ mtime: st.mtime ?? new Date(),
77
+ };
71
78
  }
72
79
  default:
73
- return 0;
80
+ throw new TezXError("Unsupported runtime: " + runtime);
74
81
  }
75
82
  }
83
+ export async function etagDigest(algo = "MD5", data) {
84
+ const encoded = typeof data === "string" ? new TextEncoder().encode(data) : data;
85
+ if (runtime === "bun") {
86
+ return Bun.hash(data, 256).toString(16);
87
+ }
88
+ if (globalThis?.crypto?.subtle) {
89
+ const buffer = await crypto.subtle.digest(algo, encoded);
90
+ return Array.from(new Uint8Array(buffer))
91
+ .map((b) => b.toString(16).padStart(2, "0"))
92
+ .join("");
93
+ }
94
+ const { createHash } = await import("node:crypto");
95
+ return createHash(algo).update(encoded).digest("hex");
96
+ }
@@ -31,3 +31,12 @@ export declare function generateID(): string;
31
31
  * console.log(uuid); // "a63e47b6-6a3b-4d53-90b6-8db2f2d07943"
32
32
  */
33
33
  export declare function generateUUID(): string;
34
+ /**
35
+ * Generate a short nonce (JS-only, low-GC) by sampling the BASE64 charset.
36
+ * This function intentionally uses Math.random for speed and low allocation.
37
+ * If you require cryptographic randomness, swap with crypto.randomFillSync.
38
+ *
39
+ * @param {number} [length=16] - nonce length in characters
40
+ * @returns {string} generated nonce string
41
+ */
42
+ export declare function generateRandomBase64(length?: number): string;
@@ -21,3 +21,12 @@ export function generateUUID() {
21
21
  return crypto.randomUUID();
22
22
  return generateID();
23
23
  }
24
+ export function generateRandomBase64(length = 16) {
25
+ let result = "";
26
+ const BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
27
+ for (let i = 0; i < length; i++) {
28
+ const idx = Math.floor(Math.random() * 64);
29
+ result += BASE64[idx];
30
+ }
31
+ return result;
32
+ }
package/utils/response.js CHANGED
@@ -9,7 +9,9 @@ export let notFoundResponse = (ctx) => {
9
9
  export async function handleErrorResponse(err = TezXError.internal(), ctx) {
10
10
  if (err instanceof TezXError) {
11
11
  GlobalConfig.debugging.error(err.details ?? err?.message);
12
- return ctx.status(err.statusCode ?? 500).send(err.details ?? err?.message ?? "Internal Server Error");
12
+ return ctx
13
+ .status(err.statusCode ?? 500)
14
+ .send(err.details ?? err?.message ?? "Internal Server Error");
13
15
  }
14
16
  return await handleErrorResponse(TezXError.internal(), ctx);
15
17
  }
@@ -1,57 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.compileRegexRoute = compileRegexRoute;
4
- exports.addBaseToRegex = addBaseToRegex;
5
- exports.regexMatchRoute = regexMatchRoute;
6
- const low_level_js_1 = require("./low-level.js");
7
- function compileRegexRoute(seg) {
8
- const segments = typeof seg == "string" ? seg.split("/").filter(Boolean) : seg;
9
- let regexStr = "^";
10
- const paramNames = [];
11
- for (let seg of segments) {
12
- if (seg.startsWith(":")) {
13
- const isOptional = seg.endsWith("?");
14
- const name = seg.replace(":", "").replace("?", "");
15
- paramNames.push(name);
16
- regexStr += isOptional ? `(?:\\/([^\\/]+))?` : `\\/([^\\/]+)`;
17
- }
18
- else if (seg.startsWith("*")) {
19
- const name = seg.slice(1) || "*";
20
- paramNames.push(name);
21
- regexStr += `\\/(.+)`;
22
- break;
23
- }
24
- else {
25
- regexStr += `\\/${seg}`;
26
- }
27
- }
28
- regexStr += "\\/?$";
29
- return {
30
- regex: new RegExp(regexStr),
31
- paramNames,
32
- };
33
- }
34
- function addBaseToRegex(basePath, routeRegex) {
35
- basePath = "/" + (0, low_level_js_1.sanitizePathSplitBasePath)("/", basePath)?.join("/");
36
- if (basePath === "/")
37
- basePath = "";
38
- let body = routeRegex.source.replace(/^(\^)/, "").replace(/(\$)$/, "");
39
- body = body.replace(/\\\//g, "/");
40
- if (body.startsWith("/")) {
41
- body = body.slice(1);
42
- }
43
- const cleaned = body.replace(/^\/+|\/+$/g, "").replace(/\/?\?$/, "");
44
- const combined = basePath + "/" + cleaned + "/?";
45
- const finalRegex = new RegExp(`^${combined}$`);
46
- return finalRegex;
47
- }
48
- function regexMatchRoute(regex, url, paramNames = []) {
49
- const match = url.match(regex);
50
- if (!match)
51
- return { success: false, params: {} };
52
- const params = {};
53
- paramNames.forEach((name, idx) => {
54
- params[name] = match[idx + 1] ?? null;
55
- });
56
- return { params, success: true };
57
- }
@@ -1,66 +0,0 @@
1
- /**
2
- * Compiles a route string or segment array into a regular expression for matching URL paths.
3
- * Supports dynamic `:param`, optional `:param?`, and wildcard `*param` segments.
4
- *
5
- * @param {string | string[]} seg - The route pattern, either as a string (`'/user/:id'`)
6
- * or an array of segments (`['user', ':id']`).
7
- *
8
- * @returns {{
9
- * regex: RegExp,
10
- * paramNames: string[]
11
- * }}
12
- * @example
13
- * const { regex, paramNames } = compileRegexRoute('/user/:id/post/:slug?');
14
- * // regex: /^\/user\/([^\/]+)\/(?:([^\/]+))?\/?$/
15
- * // paramNames: ['id', 'slug']
16
- *
17
- * regex.test('/user/123/post/hello'); // ✅ true
18
- * regex.test('/user/123/post'); // ✅ true (because :slug? is optional)
19
- *
20
- * @example
21
- * const { regex, paramNames } = compileRegexRoute('/files/*path');
22
- * // regex: /^\/files\/(.+)\/?$/
23
- * // paramNames: ['path']
24
- *
25
- * regex.test('/files/images/cat.jpg'); // ✅ true
26
- */
27
- export declare function compileRegexRoute(seg: string | string[]): {
28
- regex: RegExp;
29
- paramNames: string[];
30
- };
31
- /**
32
- * Combines a base path with a route regex pattern.
33
- *
34
- * @param basePath - The base path to prepend (e.g., '/api/v1')
35
- * @param routeRegex - The original route regex (e.g., /^\/users\/([^/]+?)$/)
36
- * @returns A new regex that includes the base path
37
- */
38
- export declare function addBaseToRegex(basePath: string, routeRegex: RegExp): RegExp;
39
- /**
40
- * Matches a given URL against a provided regular expression and extracts named parameters.
41
- *
42
- * @param {RegExp} regex - The regular expression to match against the URL.
43
- * It should include capturing groups for each parameter.
44
- * Example: /^\/user\/(\d+)\/post\/(\w+)$/
45
- *
46
- * @param {string} url - The URL string to match.
47
- * Example: "/user/123/post/abc"
48
- *
49
- * @param {string[]} paramNames - An array of parameter names corresponding to the capturing groups in the regex.
50
- * Example: ["userId", "postId"]
51
- *
52
- * @returns {{ success: boolean, params: Record<string, string | null> }} An object indicating:
53
- * - `success`: whether the URL matched the regex.
54
- * - `params`: an object mapping parameter names to their matched values, or `null` if not found.
55
- *
56
- * @example
57
- * const regex = /^\/user\/(\d+)\/post\/(\w+)$/;
58
- * const url = "/user/123/post/abc";
59
- * const paramNames = ["userId", "postId"];
60
- * const result = regexMatchRoute(regex, url, paramNames);
61
- * // result = { success: true, params: { userId: "123", postId: "abc" } }
62
- */
63
- export declare function regexMatchRoute(regex: RegExp, url: string, paramNames?: string[]): {
64
- params: Record<string, string | null>;
65
- success: boolean;
66
- };
@@ -1,52 +0,0 @@
1
- import { sanitizePathSplitBasePath } from "./low-level.js";
2
- export function compileRegexRoute(seg) {
3
- const segments = typeof seg == "string" ? seg.split("/").filter(Boolean) : seg;
4
- let regexStr = "^";
5
- const paramNames = [];
6
- for (let seg of segments) {
7
- if (seg.startsWith(":")) {
8
- const isOptional = seg.endsWith("?");
9
- const name = seg.replace(":", "").replace("?", "");
10
- paramNames.push(name);
11
- regexStr += isOptional ? `(?:\\/([^\\/]+))?` : `\\/([^\\/]+)`;
12
- }
13
- else if (seg.startsWith("*")) {
14
- const name = seg.slice(1) || "*";
15
- paramNames.push(name);
16
- regexStr += `\\/(.+)`;
17
- break;
18
- }
19
- else {
20
- regexStr += `\\/${seg}`;
21
- }
22
- }
23
- regexStr += "\\/?$";
24
- return {
25
- regex: new RegExp(regexStr),
26
- paramNames,
27
- };
28
- }
29
- export function addBaseToRegex(basePath, routeRegex) {
30
- basePath = "/" + sanitizePathSplitBasePath("/", basePath)?.join("/");
31
- if (basePath === "/")
32
- basePath = "";
33
- let body = routeRegex.source.replace(/^(\^)/, "").replace(/(\$)$/, "");
34
- body = body.replace(/\\\//g, "/");
35
- if (body.startsWith("/")) {
36
- body = body.slice(1);
37
- }
38
- const cleaned = body.replace(/^\/+|\/+$/g, "").replace(/\/?\?$/, "");
39
- const combined = basePath + "/" + cleaned + "/?";
40
- const finalRegex = new RegExp(`^${combined}$`);
41
- return finalRegex;
42
- }
43
- export function regexMatchRoute(regex, url, paramNames = []) {
44
- const match = url.match(regex);
45
- if (!match)
46
- return { success: false, params: {} };
47
- const params = {};
48
- paramNames.forEach((name, idx) => {
49
- params[name] = match[idx + 1] ?? null;
50
- });
51
- return { params, success: true };
52
- }