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
@@ -0,0 +1,136 @@
1
+ import crypto from "crypto";
2
+ const joinSrc = (v) => typeof v === "string" ? v : v.join(" ");
3
+ const buildCSPString = (cspObj) => {
4
+ const parts = [];
5
+ for (const key in cspObj) {
6
+ parts.push(`${key} ${joinSrc(cspObj[key])}`);
7
+ }
8
+ return parts.join("; ");
9
+ };
10
+ const defaultPresets = {
11
+ strict: {
12
+ preset: "strict",
13
+ hsts: true,
14
+ hstsMaxAge: 63072000,
15
+ frameGuard: "DENY",
16
+ noSniff: true,
17
+ xssProtection: true,
18
+ referrerPolicy: "strict-origin-when-cross-origin",
19
+ permissionsPolicy: "geolocation=(), microphone=(), camera=(), usb=()",
20
+ csp: {
21
+ "default-src": ["'self'"],
22
+ "script-src": ["'self'"],
23
+ "style-src": ["'self'", "'unsafe-inline'"],
24
+ "img-src": ["'self'", "data:", "blob:"],
25
+ "font-src": ["'self'"],
26
+ "connect-src": ["'self'"],
27
+ "object-src": ["'none'"],
28
+ "frame-ancestors": ["'none'"],
29
+ },
30
+ cspReportOnly: false,
31
+ },
32
+ balanced: {
33
+ preset: "balanced",
34
+ hsts: true,
35
+ hstsMaxAge: 31536000,
36
+ frameGuard: "SAMEORIGIN",
37
+ noSniff: true,
38
+ xssProtection: true,
39
+ referrerPolicy: "no-referrer-when-downgrade",
40
+ permissionsPolicy: "geolocation=(), microphone=()",
41
+ csp: {
42
+ "default-src": ["'self'"],
43
+ "script-src": ["'self'", "https://cdn.jsdelivr.net"],
44
+ "style-src": [
45
+ "'self'",
46
+ "'unsafe-inline'",
47
+ "https://fonts.googleapis.com",
48
+ ],
49
+ "img-src": ["'self'", "data:", "https://images.example.com"],
50
+ "connect-src": ["'self'", "https://api.example.com"],
51
+ },
52
+ cspReportOnly: true,
53
+ },
54
+ dev: {
55
+ preset: "dev",
56
+ hsts: false,
57
+ frameGuard: "SAMEORIGIN",
58
+ noSniff: false,
59
+ xssProtection: false,
60
+ referrerPolicy: "no-referrer",
61
+ permissionsPolicy: "",
62
+ csp: {
63
+ "default-src": [
64
+ "'self'",
65
+ "'unsafe-inline'",
66
+ "'unsafe-eval'",
67
+ "http://localhost:3000",
68
+ ],
69
+ "img-src": ["'self'", "data:", "blob:"],
70
+ },
71
+ cspReportOnly: true,
72
+ },
73
+ };
74
+ const setHeader = (ctx, name, value) => {
75
+ if (typeof ctx.setHeader === "function")
76
+ ctx.setHeader(name, value);
77
+ else if (ctx.response?.setHeader)
78
+ ctx.response.setHeader(name, value);
79
+ else if (ctx.headersOut)
80
+ ctx.headersOut[name] = value;
81
+ };
82
+ export const secureHeaders = (userOpts = {}) => {
83
+ const preset = userOpts.preset ?? "balanced";
84
+ const base = {
85
+ ...(defaultPresets[preset] || defaultPresets.balanced),
86
+ ...userOpts,
87
+ };
88
+ const hstsHeader = base.hsts
89
+ ? `max-age=${base.hstsMaxAge || 31536000}; includeSubDomains; preload`
90
+ : "";
91
+ const frameHeader = base.frameGuard || "SAMEORIGIN";
92
+ const noSniffHeader = base.noSniff ? "nosniff" : "";
93
+ const xssHeader = base.xssProtection ? "1; mode=block" : "0";
94
+ const referrerHeader = base.referrerPolicy || "no-referrer";
95
+ const permissionsHeader = base.permissionsPolicy || "";
96
+ let cspStatic = null;
97
+ let cspNeedsNonce = !!base.cspUseNonce;
98
+ if (typeof base.csp === "string")
99
+ cspStatic = base.csp;
100
+ else if (base.csp && typeof base.csp === "object")
101
+ cspStatic = buildCSPString(base.csp);
102
+ if (base.ultraFastMode)
103
+ cspNeedsNonce = false;
104
+ const cspReportOnly = !!base.cspReportOnly;
105
+ return async (ctx, next) => {
106
+ try {
107
+ if (base.hsts)
108
+ setHeader(ctx, "Strict-Transport-Security", hstsHeader);
109
+ setHeader(ctx, "X-Frame-Options", frameHeader);
110
+ setHeader(ctx, "X-Content-Type-Options", noSniffHeader);
111
+ setHeader(ctx, "X-XSS-Protection", xssHeader);
112
+ setHeader(ctx, "Referrer-Policy", referrerHeader);
113
+ if (permissionsHeader)
114
+ setHeader(ctx, "Permissions-Policy", permissionsHeader);
115
+ if (cspNeedsNonce) {
116
+ const nonce = crypto.randomBytes(12).toString("base64");
117
+ let cspHeader = cspStatic || `default-src 'self'; script-src 'self' 'nonce-${nonce}'`;
118
+ if (cspReportOnly)
119
+ setHeader(ctx, "Content-Security-Policy-Report-Only", cspHeader);
120
+ else
121
+ setHeader(ctx, "Content-Security-Policy", cspHeader);
122
+ ctx.cspNonce = nonce;
123
+ }
124
+ else if (cspStatic) {
125
+ if (cspReportOnly)
126
+ setHeader(ctx, "Content-Security-Policy-Report-Only", cspStatic);
127
+ else
128
+ setHeader(ctx, "Content-Security-Policy", cspStatic);
129
+ }
130
+ return await next();
131
+ }
132
+ catch {
133
+ return await next();
134
+ }
135
+ };
136
+ };
@@ -0,0 +1,132 @@
1
+ import { Middleware } from "../types/index.js";
2
+ /**
3
+ * Options for HTTP Strict Transport Security (HSTS) header.
4
+ */
5
+ export interface HstsOptions {
6
+ /**
7
+ * Max age in seconds for the `Strict-Transport-Security` header.
8
+ * Example: 31536000 (1 year)
9
+ */
10
+ maxAge?: number;
11
+ /**
12
+ * Apply HSTS to subdomains by adding `includeSubDomains` directive.
13
+ * Default: false
14
+ */
15
+ includeSubDomains?: boolean;
16
+ /**
17
+ * Add `preload` directive for browser preload lists.
18
+ * Default: false
19
+ */
20
+ preload?: boolean;
21
+ /**
22
+ * Only apply HSTS on HTTPS requests.
23
+ * If true, HTTP requests will not receive the HSTS header.
24
+ * Default: false
25
+ */
26
+ hstsOnlyOnHttps?: boolean;
27
+ }
28
+ /**
29
+ * Options for the secureHeaders middleware.
30
+ */
31
+ export type SecureHeadersOptions = {
32
+ /**
33
+ * Built-in preset to use.
34
+ * - "strict": strongest defaults for production.
35
+ * - "balanced": reasonable defaults for most apps (report-only CSP by default).
36
+ * - "dev": permissive settings useful for local development.
37
+ *
38
+ * @default "balanced"
39
+ */
40
+ preset?: "strict" | "balanced" | "dev";
41
+ /**
42
+ * HSTS (HTTP Strict Transport Security) options.
43
+ * If provided, the middleware will set the `Strict-Transport-Security` header.
44
+ *
45
+ * @example
46
+ * { maxAge: 31536000, includeSubDomains: true, preload: true }
47
+ */
48
+ hsts?: HstsOptions;
49
+ /**
50
+ * Value for `X-Frame-Options` header.
51
+ * Common values: "DENY", "SAMEORIGIN".
52
+ *
53
+ * @default "SAMEORIGIN"
54
+ */
55
+ frameGuard?: "DENY" | "SAMEORIGIN" | string;
56
+ /**
57
+ * If true, sets `X-Content-Type-Options: nosniff`.
58
+ *
59
+ * @default true (depends on preset)
60
+ */
61
+ noSniff?: boolean;
62
+ /**
63
+ * If true, sets `X-XSS-Protection: 1; mode=block`.
64
+ * Note: modern browsers use CSP; this header is legacy but harmless.
65
+ *
66
+ * @default true (depends on preset)
67
+ */
68
+ xssProtection?: boolean;
69
+ /**
70
+ * Value for `Referrer-Policy` header.
71
+ * Examples: "no-referrer", "strict-origin-when-cross-origin".
72
+ *
73
+ * @default "no-referrer" (depends on preset)
74
+ */
75
+ referrerPolicy?: string;
76
+ /**
77
+ * Value for `Permissions-Policy` (formerly Feature-Policy).
78
+ * Example: 'geolocation=(), microphone=()'
79
+ *
80
+ * @default '' (empty string = not set)
81
+ */
82
+ permissionsPolicy?: string;
83
+ /**
84
+ * Content Security Policy (CSP).
85
+ * - Pass a raw header string to use it unchanged.
86
+ * - Or pass an object mapping directives to sources (object will be prebuilt at init).
87
+ *
88
+ * Example object:
89
+ * {
90
+ * "default-src": ["'self'"],
91
+ * "script-src": ["'self'", "https://cdn.example.com"]
92
+ * }
93
+ */
94
+ csp?: string | Record<string, string | string[]>;
95
+ /**
96
+ * If true, send `Content-Security-Policy-Report-Only` instead of enforcement header.
97
+ * Useful when first testing policies.
98
+ *
99
+ * @default false
100
+ */
101
+ cspReportOnly?: boolean;
102
+ /**
103
+ * If true, middleware will generate a per-request nonce (string) and inject it
104
+ * into the `script-src` directive so inline scripts with that nonce are allowed.
105
+ * Note: nonce generation allocates a small string per-request unless `ultraFastMode` is enabled.
106
+ *
107
+ * @default false
108
+ */
109
+ cspUseNonce?: boolean;
110
+ /**
111
+ * Ultra-fast mode disables per-request allocations (e.g., nonce generation).
112
+ * Use this in high-QPS environments where inline scripts are not required.
113
+ *
114
+ * @default false
115
+ */
116
+ ultraFastMode?: boolean;
117
+ };
118
+ /**
119
+ * secureHeaders middleware
120
+ *
121
+ * Precomputes static headers (HSTS, static CSP, X-Frame-Options, etc.) at
122
+ * middleware creation time. Optionally supports per-request CSP nonces
123
+ * (disabled in ultraFastMode).
124
+ *
125
+ * @template T,Path
126
+ * @param {SecureHeadersOptions} [userOpts={}] - configuration overrides
127
+ * @returns {Middleware<T,Path>} TezX-compatible middleware
128
+ *
129
+ * @example
130
+ * app.use(secureHeaders({ preset: 'strict', cspUseNonce: true }));
131
+ */
132
+ export declare const secureHeaders: <T extends Record<string, any> = {}, Path extends string = any>(userOpts?: SecureHeadersOptions) => Middleware<T, Path>;
@@ -0,0 +1,153 @@
1
+ import { generateRandomBase64, GlobalConfig } from "../helper/index.js";
2
+ const joinSrc = (v) => typeof v === "string" ? v : v.join(" ");
3
+ const buildCSPString = (cspObj) => {
4
+ const parts = [];
5
+ for (const key in cspObj)
6
+ parts.push(`${key} ${joinSrc(cspObj[key])}`);
7
+ return parts.join("; ");
8
+ };
9
+ export const secureHeaders = (userOpts = {}) => {
10
+ const defaultPresets = {
11
+ strict: {
12
+ preset: "strict",
13
+ hsts: { maxAge: 63072000, includeSubDomains: true, preload: true },
14
+ frameGuard: "DENY",
15
+ noSniff: true,
16
+ xssProtection: true,
17
+ referrerPolicy: "strict-origin-when-cross-origin",
18
+ permissionsPolicy: "geolocation=(), microphone=(), camera=(), usb=()",
19
+ csp: {
20
+ "default-src": ["'self'"],
21
+ "script-src": ["'self'"],
22
+ "style-src": ["'self'", "'unsafe-inline'"],
23
+ "img-src": ["'self'", "data:", "blob:"],
24
+ "font-src": ["'self'"],
25
+ "connect-src": ["'self'"],
26
+ "object-src": ["'none'"],
27
+ "frame-ancestors": ["'none'"],
28
+ },
29
+ cspReportOnly: false,
30
+ },
31
+ balanced: {
32
+ preset: "balanced",
33
+ hsts: { maxAge: 31536000, includeSubDomains: true, preload: true },
34
+ frameGuard: "SAMEORIGIN",
35
+ noSniff: true,
36
+ xssProtection: true,
37
+ referrerPolicy: "no-referrer-when-downgrade",
38
+ permissionsPolicy: "geolocation=(), microphone=()",
39
+ csp: {
40
+ "default-src": ["'self'"],
41
+ "script-src": ["'self'", "https://cdn.jsdelivr.net"],
42
+ "style-src": [
43
+ "'self'",
44
+ "'unsafe-inline'",
45
+ "https://fonts.googleapis.com",
46
+ ],
47
+ "img-src": ["'self'", "data:", "https://images.example.com"],
48
+ "connect-src": ["'self'", "https://api.example.com"],
49
+ },
50
+ cspReportOnly: true,
51
+ },
52
+ dev: {
53
+ preset: "dev",
54
+ hsts: undefined,
55
+ frameGuard: "SAMEORIGIN",
56
+ noSniff: false,
57
+ xssProtection: false,
58
+ referrerPolicy: "no-referrer",
59
+ permissionsPolicy: "",
60
+ csp: {
61
+ "default-src": [
62
+ "'self'",
63
+ "'unsafe-inline'",
64
+ "'unsafe-eval'",
65
+ "http://localhost:3000",
66
+ ],
67
+ "img-src": ["'self'", "data:", "blob:"],
68
+ },
69
+ cspReportOnly: true,
70
+ },
71
+ };
72
+ const preset = userOpts.preset ?? "balanced";
73
+ const base = {
74
+ ...(defaultPresets[preset] || defaultPresets.balanced),
75
+ ...userOpts,
76
+ };
77
+ const frameHeader = base.frameGuard || "SAMEORIGIN";
78
+ const xssHeader = base.xssProtection ? "1; mode=block" : "0";
79
+ const noSniffHeader = base.noSniff ? "nosniff" : "";
80
+ const permissionsHeader = base.permissionsPolicy || "";
81
+ const referrerHeader = base.referrerPolicy || "no-referrer";
82
+ const hstsParts = [`max-age=${base.hsts?.maxAge || 31536000}`];
83
+ if (base.hsts?.includeSubDomains)
84
+ hstsParts.push("includeSubDomains");
85
+ if (base.hsts?.preload)
86
+ hstsParts.push("preload");
87
+ const hstsHeader = hstsParts.join("; ");
88
+ let cspStatic = null;
89
+ let cspNeedsNonce = !!base.cspUseNonce;
90
+ if (typeof base.csp === "string")
91
+ cspStatic = base.csp;
92
+ else if (base.csp)
93
+ cspStatic = buildCSPString(base.csp);
94
+ const cspReportOnly = !!base.cspReportOnly;
95
+ const ultraFast = !!base.ultraFastMode;
96
+ if (cspNeedsNonce && ultraFast) {
97
+ GlobalConfig.debugging.warn("secureHeaders: ultraFastMode disables CSP nonce support. Nonce will not be used.");
98
+ }
99
+ if (ultraFast)
100
+ cspNeedsNonce = false;
101
+ return async (ctx, next) => {
102
+ try {
103
+ if (base.hsts) {
104
+ const proto = (ctx.req?.header("x-forwarded-proto") || "").toString();
105
+ if (!base.hsts.hstsOnlyOnHttps || proto.includes("https")) {
106
+ ctx.headers.set("Strict-Transport-Security", hstsHeader);
107
+ }
108
+ }
109
+ ctx.headers.set("X-Frame-Options", frameHeader);
110
+ ctx.headers.set("X-Content-Type-Options", noSniffHeader);
111
+ ctx.headers.set("X-XSS-Protection", xssHeader);
112
+ ctx.headers.set("Referrer-Policy", referrerHeader);
113
+ if (permissionsHeader)
114
+ ctx.headers.set("Permissions-Policy", permissionsHeader);
115
+ if (cspNeedsNonce) {
116
+ const nonce = generateRandomBase64();
117
+ let cspHeader = cspStatic;
118
+ if (!cspHeader) {
119
+ cspHeader = `default-src 'self'; script-src 'self' 'nonce-${nonce}'`;
120
+ }
121
+ if (typeof base.csp === "object") {
122
+ const idx = cspHeader.indexOf("script-src");
123
+ if (idx >= 0) {
124
+ const parts = [];
125
+ parts.push(cspHeader.slice(0, idx + 10));
126
+ parts.push(" 'nonce-" + nonce + "'");
127
+ parts.push(cspHeader.slice(idx + 10));
128
+ cspHeader = parts.join("");
129
+ }
130
+ else {
131
+ cspHeader += "; script-src 'self' 'nonce-" + nonce + "'";
132
+ }
133
+ }
134
+ ctx.cspNonce = nonce;
135
+ if (cspReportOnly)
136
+ ctx.headers.set("Content-Security-Policy-Report-Only", cspHeader);
137
+ else
138
+ ctx.headers.set("Content-Security-Policy", cspHeader);
139
+ }
140
+ else if (cspStatic) {
141
+ if (cspReportOnly)
142
+ ctx.headers.set("Content-Security-Policy-Report-Only", cspStatic);
143
+ else
144
+ ctx.headers.set("Content-Security-Policy", cspStatic);
145
+ }
146
+ return await next();
147
+ }
148
+ catch (err) {
149
+ console.error("secureHeaders middleware error", err);
150
+ return await next();
151
+ }
152
+ };
153
+ };
package/node/env.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
- import { runtime } from "../utils/runtime.js";
2
+ import { TezXError } from "../core/error.js";
3
3
  import { colorText } from "../utils/colors.js";
4
+ import { runtime } from "../utils/runtime.js";
4
5
  function parseEnvFile(filePath, result) {
5
6
  try {
6
- if (runtime !== "bun" && runtime !== "node") {
7
- throw new Error(`Please use ${colorText(`import {loadEnv} from "tezx/${runtime}"`, "bgRed")} environment`);
7
+ if (runtime !== "node") {
8
+ throw new TezXError(`Please use ${colorText(`import {loadEnv} from "tezx/${runtime}"`, "bgRed")} environment`);
8
9
  }
9
10
  let fileExists = existsSync(filePath);
10
11
  if (!fileExists) {
@@ -15,6 +15,14 @@ import { ServeStatic, StaticFileArray, StaticServeOption } from "../types/index.
15
15
  * @param args - Either [route, folder, option] or [folder, option]
16
16
  * @returns A list of static files and their associated route paths.
17
17
  */
18
+ /**
19
+ * Universal ETag generator for Deno, Bun, and Node.js environments.
20
+ * Uses file size + modification time (mtimeMs) to create a unique hash-based ETag.
21
+ *
22
+ * @example
23
+ * const etag = await getETag("/path/to/file.txt");
24
+ * ctx.setHeader("ETag", etag);
25
+ */
18
26
  export declare function serveStatic(route: string, folder: string, option?: StaticServeOption): ServeStatic;
19
27
  export declare function serveStatic(folder: string, option?: StaticServeOption): ServeStatic;
20
28
  /**
@@ -1,6 +1,7 @@
1
1
  import { readdirSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { extensionExtract, sanitizePathSplitBasePath, } from "../utils/low-level.js";
4
+ import { TezXError } from "../core/error.js";
4
5
  export function serveStatic(...args) {
5
6
  let route = "";
6
7
  let dir;
@@ -21,7 +22,7 @@ export function serveStatic(...args) {
21
22
  [dir] = args;
22
23
  break;
23
24
  default:
24
- throw new Error(`\x1b[1;31m404 Not Found\x1b[0m \x1b[1;32mInvalid arguments\x1b[0m`);
25
+ throw new TezXError(`\x1b[1;31m404 Not Found\x1b[0m \x1b[1;32mInvalid arguments\x1b[0m`);
25
26
  }
26
27
  return {
27
28
  files: getFiles(dir, route, options),
package/node/ws.d.ts CHANGED
@@ -22,7 +22,7 @@ export type nodeWebSocketOptions = {
22
22
  *
23
23
  * @param {WebSocketCallback} callback - Function that returns WebSocket event handlers.
24
24
  * @param {WebSocketOptions} [options={}] - Options for WebSocket upgrade behavior.
25
- * @param {(error: Error, ctx: T) => any} [options.onUpgradeError] - Custom error handler for upgrade failures.
25
+ * @param {(error: TezXError, ctx: T) => any} [options.onUpgradeError] - Custom error handler for upgrade failures.
26
26
  * @param {number} [options.maxPayload=1048576] - Maximum allowed payload size (in bytes).
27
27
  * @param {boolean} [options.perMessageDeflate=false] - Whether to enable per-message deflate.
28
28
  *
package/node/ws.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { TezXError } from "../core/error.js";
1
2
  export function upgradeWebSocket(callback, options = {}) {
2
3
  const { onUpgradeError = (error, ctx) => {
3
4
  ctx.setStatus = 401;
@@ -13,13 +14,13 @@ export function upgradeWebSocket(callback, options = {}) {
13
14
  return next();
14
15
  }
15
16
  ctx.setStatus = 401;
16
- return onUpgradeError(new Error("401 Bad Request: Invalid WebSocket headers"), ctx);
17
+ return onUpgradeError(new TezXError("401 Bad Request: Invalid WebSocket headers", 401), ctx);
17
18
  }
18
19
  ctx.wsProtocol = ctx.url?.startsWith("https") ? "wss" : "ws";
19
20
  const server = ctx.args?.[2];
20
21
  if (!server?.on) {
21
22
  ctx.setStatus = 500;
22
- return onUpgradeError(new Error("Node server instance missing for WebSocket"), ctx);
23
+ return onUpgradeError(new TezXError("Node server instance missing for WebSocket", 426), ctx);
23
24
  }
24
25
  const { WebSocketServer } = await import("ws");
25
26
  const wss = new WebSocketServer({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tezx",
3
- "version": "3.0.14-beta",
3
+ "version": "3.0.14-beta2",
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
5
  "type": "module",
6
6
  "main": "cjs/index.js",
@@ -42,6 +42,16 @@
42
42
  "require": "./cjs/helper/index.js",
43
43
  "types": "./helper/index.d.ts"
44
44
  },
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
+ },
45
55
  "./registry": {
46
56
  "import": "./registry/index.js",
47
57
  "require": "./cjs/registry/index.js",
@@ -64,6 +74,7 @@
64
74
  "core/",
65
75
  "deno/",
66
76
  "helper/",
77
+ "jwt/",
67
78
  "middleware/",
68
79
  "node/",
69
80
  "registry/",
@@ -1,3 +1,4 @@
1
+ import { TezXError } from "../core/error.js";
1
2
  import { sanitizePathSplit } from "../helper/index.js";
2
3
  export class RadixRouter {
3
4
  root = { children: {} };
@@ -19,7 +20,7 @@ export class RadixRouter {
19
20
  }
20
21
  else if (node.children[":"]?.paramName !== paramName ||
21
22
  node.children[":"]?.isOptional !== isOptional) {
22
- throw new Error(`Conflicting param definition for ${paramName}`);
23
+ throw new TezXError(`Conflicting param definition for ${paramName}`);
23
24
  }
24
25
  node = node.children[":"];
25
26
  }
@@ -141,35 +142,3 @@ export class RadixRouter {
141
142
  return result;
142
143
  }
143
144
  }
144
- const routes = [
145
- "/",
146
- "/users",
147
- "/users/:id",
148
- "/users/:id/profile",
149
- "/posts/:postId?",
150
- "/files/*",
151
- "/admin/settings",
152
- "/search/:term?",
153
- "/categories/:categoryId/products/:productId",
154
- "/about",
155
- ];
156
- const testPaths = [
157
- "/",
158
- "/users",
159
- "/users/123",
160
- "/users/123/profile",
161
- "/posts",
162
- "/posts/456",
163
- "/files/path/to/file.txt",
164
- "/admin/settings",
165
- "/search",
166
- "/search/nodejs",
167
- "/categories/12/products/999",
168
- "/notfound",
169
- ];
170
- const router = new RadixRouter();
171
- let x = function xx() {
172
- return {
173
- body: "3453455",
174
- };
175
- };
package/types/index.d.ts CHANGED
@@ -61,7 +61,7 @@ export type WebSocketOptions = {
61
61
  /**
62
62
  * Called when an error occurs during the upgrade process.
63
63
  */
64
- onUpgradeError?: (err: Error, ctx: Context) => HttpBaseResponse;
64
+ onUpgradeError?: (err: TezXError, ctx: Context) => HttpBaseResponse;
65
65
  };
66
66
  /**
67
67
  * Represents a string key used for HTTP headers.
@@ -0,0 +1 @@
1
+ export declare function base64Decode(base64: string): string;
@@ -0,0 +1,14 @@
1
+ export function base64Decode(base64) {
2
+ const pad = base64.length % 4;
3
+ if (pad)
4
+ base64 += "=".repeat(4 - pad);
5
+ if (typeof Buffer !== "undefined") {
6
+ return Buffer.from(base64, "base64").toString("utf-8");
7
+ }
8
+ else if (typeof atob === "function") {
9
+ return new TextDecoder().decode(Uint8Array.from(atob(base64), (c) => c.charCodeAt(0)));
10
+ }
11
+ else {
12
+ throw new Error("Base64 decode not supported in this environment");
13
+ }
14
+ }
package/utils/file.d.ts CHANGED
@@ -29,6 +29,10 @@ export declare function readStream(path: string): Promise<ReadableStream>;
29
29
  * Supports Node.js, Bun, and Deno runtimes.
30
30
  *
31
31
  * @param {string} path - Path to the file.
32
- * @returns {Promise<number>} - Resolves to the file size in bytes.
32
+ * @returns {Promise<{size: number, mtime: Date}>} - Resolves to the file size in bytes.
33
33
  */
34
- export declare function fileSize(path: string): Promise<number>;
34
+ export declare function fileSize(path: string): Promise<{
35
+ mtime: Date;
36
+ size: number;
37
+ }>;
38
+ export declare function etagDigest(algo: string | undefined, data: any): Promise<string>;