tezx 1.0.58 → 1.0.60
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.
- package/adapter/bun.js +3 -3
- package/adapter/deno.js +2 -2
- package/adapter/node.d.ts +2 -2
- package/adapter/node.js +4 -7
- package/cjs/adapter/bun.js +3 -3
- package/cjs/adapter/deno.js +2 -2
- package/cjs/adapter/node.js +4 -7
- package/cjs/core/config.js +2 -1
- package/cjs/core/context.js +6 -7
- package/cjs/core/header.js +1 -1
- package/cjs/core/request.js +4 -3
- package/cjs/core/router.js +8 -9
- package/cjs/core/server.js +20 -13
- package/cjs/index.js +1 -1
- package/cjs/utils/formData.js +5 -5
- package/cjs/utils/staticFile.js +2 -2
- package/cjs/utils/url.js +2 -0
- package/core/MiddlewareConfigure.d.ts +1 -1
- package/core/config.js +2 -1
- package/core/context.js +6 -7
- package/core/header.d.ts +1 -1
- package/core/header.js +1 -1
- package/core/request.d.ts +1 -1
- package/core/request.js +4 -3
- package/core/router.js +9 -10
- package/core/server.js +20 -13
- package/index.js +1 -1
- package/package.json +1 -1
- package/utils/formData.js +5 -5
- package/utils/staticFile.js +2 -2
- package/utils/url.d.ts +1 -0
- package/utils/url.js +1 -0
package/adapter/bun.js
CHANGED
|
@@ -2,8 +2,8 @@ import { GlobalConfig } from "../core/config.js";
|
|
|
2
2
|
import { Context } from "../core/context.js";
|
|
3
3
|
export function bunAdapter(TezX, options = {}) {
|
|
4
4
|
function listen(...arg) {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const port = typeof arg[0] === "function" ? undefined : arg[0];
|
|
6
|
+
const callback = typeof arg[0] === "function" ? arg[0] : arg[1];
|
|
7
7
|
const serve = typeof Bun !== "undefined" ? Bun.serve : null;
|
|
8
8
|
try {
|
|
9
9
|
if (!serve) {
|
|
@@ -21,7 +21,7 @@ export function bunAdapter(TezX, options = {}) {
|
|
|
21
21
|
})
|
|
22
22
|
: serve({
|
|
23
23
|
error: (error) => {
|
|
24
|
-
return
|
|
24
|
+
return options?.error?.(server, error);
|
|
25
25
|
},
|
|
26
26
|
development: options?.development,
|
|
27
27
|
hostname: options?.hostname,
|
package/adapter/deno.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { GlobalConfig } from "../core/config.js";
|
|
2
2
|
export function denoAdapter(TezX, options = {}) {
|
|
3
3
|
function listen(...arg) {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const port = typeof arg[0] === "function" ? undefined : arg[0];
|
|
5
|
+
const callback = typeof arg[0] === "function" ? arg[0] : arg[1];
|
|
6
6
|
const isDeno = typeof Deno !== "undefined";
|
|
7
7
|
try {
|
|
8
8
|
async function handleRequest(req, connInfo) {
|
package/adapter/node.d.ts
CHANGED
|
@@ -11,9 +11,9 @@ type SSLOptions = ServerOptions & TlsOptions & {
|
|
|
11
11
|
type TezXServerOptions = UnixSocketOptions | SSLOptions;
|
|
12
12
|
export declare function nodeAdapter<T extends Record<string, any> = {}>(TezX: TezX<T>, options?: TezXServerOptions): {
|
|
13
13
|
listen: {
|
|
14
|
-
(callback?: (
|
|
14
|
+
(callback?: () => void): any;
|
|
15
15
|
(port?: number): any;
|
|
16
|
-
(port?: number, callback?: (
|
|
16
|
+
(port?: number, callback?: () => void): any;
|
|
17
17
|
};
|
|
18
18
|
};
|
|
19
19
|
export {};
|
package/adapter/node.js
CHANGED
|
@@ -58,7 +58,7 @@ export function nodeAdapter(TezX, options = {}) {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
});
|
|
61
|
-
const port = typeof arg[0] === "
|
|
61
|
+
const port = typeof arg[0] === "function" ? undefined : arg[0];
|
|
62
62
|
const callback = typeof arg[0] === "function" ? arg[0] : arg[1];
|
|
63
63
|
server.listen(options?.unix || port || 0, () => {
|
|
64
64
|
const protocol = ssl ? "\x1b[1;35mhttps\x1b[0m" : "\x1b[1;34mhttp\x1b[0m";
|
|
@@ -67,12 +67,9 @@ export function nodeAdapter(TezX, options = {}) {
|
|
|
67
67
|
? `\x1b[1mNodeJS TezX Server running at unix://${address}\x1b[0m`
|
|
68
68
|
: `\x1b[1mNodeJS TezX Server running at ${protocol}://localhost:${address?.port}/\x1b[0m`;
|
|
69
69
|
GlobalConfig.server = server;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
else {
|
|
74
|
-
GlobalConfig.debugging.success(message);
|
|
75
|
-
}
|
|
70
|
+
GlobalConfig.debugging.success(message);
|
|
71
|
+
if (typeof callback == "function")
|
|
72
|
+
callback();
|
|
76
73
|
return server;
|
|
77
74
|
});
|
|
78
75
|
})
|
package/cjs/adapter/bun.js
CHANGED
|
@@ -5,8 +5,8 @@ const config_js_1 = require("../core/config.js");
|
|
|
5
5
|
const context_js_1 = require("../core/context.js");
|
|
6
6
|
function bunAdapter(TezX, options = {}) {
|
|
7
7
|
function listen(...arg) {
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const port = typeof arg[0] === "function" ? undefined : arg[0];
|
|
9
|
+
const callback = typeof arg[0] === "function" ? arg[0] : arg[1];
|
|
10
10
|
const serve = typeof Bun !== "undefined" ? Bun.serve : null;
|
|
11
11
|
try {
|
|
12
12
|
if (!serve) {
|
|
@@ -24,7 +24,7 @@ function bunAdapter(TezX, options = {}) {
|
|
|
24
24
|
})
|
|
25
25
|
: serve({
|
|
26
26
|
error: (error) => {
|
|
27
|
-
return
|
|
27
|
+
return options?.error?.(server, error);
|
|
28
28
|
},
|
|
29
29
|
development: options?.development,
|
|
30
30
|
hostname: options?.hostname,
|
package/cjs/adapter/deno.js
CHANGED
|
@@ -4,8 +4,8 @@ exports.denoAdapter = denoAdapter;
|
|
|
4
4
|
const config_js_1 = require("../core/config.js");
|
|
5
5
|
function denoAdapter(TezX, options = {}) {
|
|
6
6
|
function listen(...arg) {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const port = typeof arg[0] === "function" ? undefined : arg[0];
|
|
8
|
+
const callback = typeof arg[0] === "function" ? arg[0] : arg[1];
|
|
9
9
|
const isDeno = typeof Deno !== "undefined";
|
|
10
10
|
try {
|
|
11
11
|
async function handleRequest(req, connInfo) {
|
package/cjs/adapter/node.js
CHANGED
|
@@ -60,7 +60,7 @@ function nodeAdapter(TezX, options = {}) {
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
});
|
|
63
|
-
const port = typeof arg[0] === "
|
|
63
|
+
const port = typeof arg[0] === "function" ? undefined : arg[0];
|
|
64
64
|
const callback = typeof arg[0] === "function" ? arg[0] : arg[1];
|
|
65
65
|
server.listen(options?.unix || port || 0, () => {
|
|
66
66
|
const protocol = ssl ? "\x1b[1;35mhttps\x1b[0m" : "\x1b[1;34mhttp\x1b[0m";
|
|
@@ -69,12 +69,9 @@ function nodeAdapter(TezX, options = {}) {
|
|
|
69
69
|
? `\x1b[1mNodeJS TezX Server running at unix://${address}\x1b[0m`
|
|
70
70
|
: `\x1b[1mNodeJS TezX Server running at ${protocol}://localhost:${address?.port}/\x1b[0m`;
|
|
71
71
|
config_js_1.GlobalConfig.server = server;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
else {
|
|
76
|
-
config_js_1.GlobalConfig.debugging.success(message);
|
|
77
|
-
}
|
|
72
|
+
config_js_1.GlobalConfig.debugging.success(message);
|
|
73
|
+
if (typeof callback == "function")
|
|
74
|
+
callback();
|
|
78
75
|
return server;
|
|
79
76
|
});
|
|
80
77
|
})
|
package/cjs/core/config.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.GlobalConfig = void 0;
|
|
4
4
|
const debugging_js_1 = require("../utils/debugging.js");
|
|
5
|
+
const environment_js_1 = require("./environment.js");
|
|
5
6
|
let GlobalConfig = class {
|
|
6
7
|
static notFound = (ctx) => {
|
|
7
8
|
const { method, urlRef: { pathname }, } = ctx.req;
|
|
@@ -14,7 +15,7 @@ let GlobalConfig = class {
|
|
|
14
15
|
static overwriteMethod = true;
|
|
15
16
|
static debugMode = false;
|
|
16
17
|
static server;
|
|
17
|
-
static adapter;
|
|
18
|
+
static adapter = environment_js_1.EnvironmentDetector.getEnvironment;
|
|
18
19
|
static get debugging() {
|
|
19
20
|
return this.debugMode
|
|
20
21
|
? {
|
package/cjs/core/context.js
CHANGED
|
@@ -93,8 +93,7 @@ class Context {
|
|
|
93
93
|
this.#rawRequest = req;
|
|
94
94
|
this.method = req?.method?.toUpperCase();
|
|
95
95
|
this.#requestHeaders = new header_js_1.HeadersParser(req?.headers);
|
|
96
|
-
if (
|
|
97
|
-
config_js_1.GlobalConfig.adapter == "node") {
|
|
96
|
+
if (config_js_1.GlobalConfig.adapter == "node") {
|
|
98
97
|
let encrypted = req?.socket?.encrypted;
|
|
99
98
|
const protocol = typeof encrypted === "boolean"
|
|
100
99
|
? encrypted
|
|
@@ -286,7 +285,7 @@ class Context {
|
|
|
286
285
|
let fileExists = false;
|
|
287
286
|
const runtime = environment_js_1.EnvironmentDetector.getEnvironment;
|
|
288
287
|
if (runtime === "node") {
|
|
289
|
-
const { existsSync } = await Promise.resolve().then(() => require("fs"));
|
|
288
|
+
const { existsSync } = await Promise.resolve().then(() => require("node:fs"));
|
|
290
289
|
fileExists = existsSync(filePath);
|
|
291
290
|
}
|
|
292
291
|
else if (runtime === "bun") {
|
|
@@ -306,7 +305,7 @@ class Context {
|
|
|
306
305
|
}
|
|
307
306
|
let fileBuffer;
|
|
308
307
|
if (runtime === "node") {
|
|
309
|
-
const { readFileSync } = await Promise.resolve().then(() => require("fs"));
|
|
308
|
+
const { readFileSync } = await Promise.resolve().then(() => require("node:fs"));
|
|
310
309
|
fileBuffer = await readFileSync(filePath);
|
|
311
310
|
}
|
|
312
311
|
else if (runtime === "bun") {
|
|
@@ -336,7 +335,7 @@ class Context {
|
|
|
336
335
|
const resolvedPath = filePath;
|
|
337
336
|
let fileExists = false;
|
|
338
337
|
if (runtime === "node") {
|
|
339
|
-
const { existsSync } = await Promise.resolve().then(() => require("fs"));
|
|
338
|
+
const { existsSync } = await Promise.resolve().then(() => require("node:fs"));
|
|
340
339
|
fileExists = existsSync(resolvedPath);
|
|
341
340
|
}
|
|
342
341
|
else if (runtime === "bun") {
|
|
@@ -356,7 +355,7 @@ class Context {
|
|
|
356
355
|
}
|
|
357
356
|
let fileSize = 0;
|
|
358
357
|
if (runtime === "node") {
|
|
359
|
-
const { statSync } = await Promise.resolve().then(() => require("fs"));
|
|
358
|
+
const { statSync } = await Promise.resolve().then(() => require("node:fs"));
|
|
360
359
|
fileSize = statSync(resolvedPath).size;
|
|
361
360
|
}
|
|
362
361
|
else if (runtime === "bun") {
|
|
@@ -370,7 +369,7 @@ class Context {
|
|
|
370
369
|
const mimeType = staticFile_js_1.mimeTypes[ext] || staticFile_js_1.defaultMimeType;
|
|
371
370
|
let fileStream;
|
|
372
371
|
if (runtime === "node") {
|
|
373
|
-
const { createReadStream } = await Promise.resolve().then(() => require("fs"));
|
|
372
|
+
const { createReadStream } = await Promise.resolve().then(() => require("node:fs"));
|
|
374
373
|
fileStream = createReadStream(resolvedPath);
|
|
375
374
|
}
|
|
376
375
|
else if (runtime === "bun") {
|
package/cjs/core/header.js
CHANGED
package/cjs/core/request.js
CHANGED
|
@@ -83,10 +83,11 @@ class Request {
|
|
|
83
83
|
return (0, formData_js_1.parseUrlEncodedBody)(this.rawRequest);
|
|
84
84
|
}
|
|
85
85
|
else if (contentType.includes("multipart/form-data")) {
|
|
86
|
-
const
|
|
87
|
-
if (!
|
|
88
|
-
throw Error("Boundary not found");
|
|
86
|
+
const boundaryMatch = contentType.match(/boundary=([^;]+)/);
|
|
87
|
+
if (!boundaryMatch) {
|
|
88
|
+
throw new Error("Boundary not found in multipart/form-data");
|
|
89
89
|
}
|
|
90
|
+
const boundary = boundaryMatch[1];
|
|
90
91
|
return await (0, formData_js_1.parseMultipartBody)(this.rawRequest, boundary, options);
|
|
91
92
|
}
|
|
92
93
|
else {
|
package/cjs/core/router.js
CHANGED
|
@@ -25,14 +25,13 @@ class Router extends MiddlewareConfigure_js_1.default {
|
|
|
25
25
|
this.basePath = basePath;
|
|
26
26
|
this.env = { ...env };
|
|
27
27
|
this.triRouter = new TrieRouter(basePath);
|
|
28
|
-
this.get.bind(this);
|
|
29
|
-
this.post.bind(this);
|
|
30
|
-
this.put.bind(this);
|
|
31
|
-
this.delete.bind(this);
|
|
32
|
-
this.all.bind(this);
|
|
33
|
-
this
|
|
34
|
-
this.
|
|
35
|
-
this.group.bind(this);
|
|
28
|
+
this.get = this.get.bind(this);
|
|
29
|
+
this.post = this.post.bind(this);
|
|
30
|
+
this.put = this.put.bind(this);
|
|
31
|
+
this.delete = this.delete.bind(this);
|
|
32
|
+
this.all = this.all.bind(this);
|
|
33
|
+
this.addRouter = this.addRouter.bind(this);
|
|
34
|
+
this.group = this.group.bind(this);
|
|
36
35
|
}
|
|
37
36
|
static(...args) {
|
|
38
37
|
let route = "";
|
|
@@ -179,7 +178,7 @@ class Router extends MiddlewareConfigure_js_1.default {
|
|
|
179
178
|
finalMiddleware = new Set(middlewares);
|
|
180
179
|
}
|
|
181
180
|
let p = parts.join("/");
|
|
182
|
-
if (
|
|
181
|
+
if (url_js_1.wildcardOrOptionalParamRegex.test(`/${p}`)) {
|
|
183
182
|
let handler = this.routers.get(p);
|
|
184
183
|
if (!handler) {
|
|
185
184
|
handler = new Map();
|
package/cjs/core/server.js
CHANGED
|
@@ -122,18 +122,22 @@ class TezX extends router_js_1.Router {
|
|
|
122
122
|
}
|
|
123
123
|
return middlewares;
|
|
124
124
|
}
|
|
125
|
-
async #
|
|
126
|
-
let ctx = new context_js_1.Context(req, options);
|
|
127
|
-
const urlRef = ctx.req.urlRef;
|
|
128
|
-
const { pathname } = urlRef;
|
|
125
|
+
async #resolvePath(pathname) {
|
|
129
126
|
let resolvePath = pathname;
|
|
130
127
|
if (this.#onPathResolve) {
|
|
131
|
-
resolvePath = this.#onPathResolve(pathname);
|
|
128
|
+
resolvePath = await this.#onPathResolve(pathname);
|
|
132
129
|
config_js_1.GlobalConfig.debugging.warn(`${colors_js_1.COLORS.white} PATH RESOLVE ${colors_js_1.COLORS.reset} ${colors_js_1.COLORS.red}${pathname}${colors_js_1.COLORS.reset} ➞ ${colors_js_1.COLORS.cyan}${resolvePath}${colors_js_1.COLORS.reset}`);
|
|
133
130
|
}
|
|
134
131
|
if (typeof resolvePath !== "string") {
|
|
135
132
|
throw new Error(`Path resolution failed: expected a string, got ${typeof resolvePath}`);
|
|
136
133
|
}
|
|
134
|
+
return resolvePath;
|
|
135
|
+
}
|
|
136
|
+
async #handleRequest(req, options) {
|
|
137
|
+
let ctx = new context_js_1.Context(req, options);
|
|
138
|
+
const urlRef = ctx.req.urlRef;
|
|
139
|
+
const { pathname } = urlRef;
|
|
140
|
+
let resolvePath = await this.#resolvePath(pathname);
|
|
137
141
|
let middlewares = this.#findMiddleware(resolvePath);
|
|
138
142
|
ctx.env = this.env;
|
|
139
143
|
try {
|
|
@@ -179,15 +183,18 @@ class TezX extends router_js_1.Router {
|
|
|
179
183
|
return finalResponse()(ctx);
|
|
180
184
|
}
|
|
181
185
|
catch (err) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
return res;
|
|
186
|
+
return this.#handleError(err, ctx);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async #handleError(err, ctx) {
|
|
190
|
+
let error = err;
|
|
191
|
+
if (err instanceof Error) {
|
|
192
|
+
error = err.stack;
|
|
190
193
|
}
|
|
194
|
+
config_js_1.GlobalConfig.debugging.error(`${colors_js_1.COLORS.bgRed} ${ctx.pathname}, Method: ${ctx.method} ${colors_js_1.COLORS.reset}`, `${context_js_1.httpStatusMap[500]}: ${error} `);
|
|
195
|
+
let res = await config_js_1.GlobalConfig.onError(error, ctx);
|
|
196
|
+
ctx.setStatus = res.status;
|
|
197
|
+
return res;
|
|
191
198
|
}
|
|
192
199
|
async serve(req, options) {
|
|
193
200
|
return this.#handleRequest(req, options);
|
package/cjs/index.js
CHANGED
|
@@ -7,4 +7,4 @@ var server_js_1 = require("./core/server.js");
|
|
|
7
7
|
Object.defineProperty(exports, "TezX", { enumerable: true, get: function () { return server_js_1.TezX; } });
|
|
8
8
|
var params_js_1 = require("./utils/params.js");
|
|
9
9
|
Object.defineProperty(exports, "useParams", { enumerable: true, get: function () { return params_js_1.useParams; } });
|
|
10
|
-
exports.version = "1.0.
|
|
10
|
+
exports.version = "1.0.60";
|
package/cjs/utils/formData.js
CHANGED
|
@@ -4,9 +4,9 @@ exports.parseJsonBody = parseJsonBody;
|
|
|
4
4
|
exports.parseTextBody = parseTextBody;
|
|
5
5
|
exports.parseUrlEncodedBody = parseUrlEncodedBody;
|
|
6
6
|
exports.parseMultipartBody = parseMultipartBody;
|
|
7
|
-
const
|
|
7
|
+
const config_js_1 = require("../core/config.js");
|
|
8
8
|
async function parseJsonBody(req) {
|
|
9
|
-
const runtime =
|
|
9
|
+
const runtime = config_js_1.GlobalConfig.adapter;
|
|
10
10
|
if (runtime === "node") {
|
|
11
11
|
return new Promise((resolve, reject) => {
|
|
12
12
|
let body = "";
|
|
@@ -31,7 +31,7 @@ async function parseJsonBody(req) {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
async function parseTextBody(req) {
|
|
34
|
-
const runtime =
|
|
34
|
+
const runtime = config_js_1.GlobalConfig.adapter;
|
|
35
35
|
if (runtime === "node") {
|
|
36
36
|
return new Promise((resolve, reject) => {
|
|
37
37
|
let body = "";
|
|
@@ -56,7 +56,7 @@ async function parseTextBody(req) {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
async function parseUrlEncodedBody(req) {
|
|
59
|
-
const runtime =
|
|
59
|
+
const runtime = config_js_1.GlobalConfig.adapter;
|
|
60
60
|
if (runtime === "node") {
|
|
61
61
|
return new Promise((resolve, reject) => {
|
|
62
62
|
let body = "";
|
|
@@ -92,7 +92,7 @@ async function parseUrlEncodedBody(req) {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
async function parseMultipartBody(req, boundary, options) {
|
|
95
|
-
const runtime =
|
|
95
|
+
const runtime = config_js_1.GlobalConfig.adapter;
|
|
96
96
|
if (runtime === "node") {
|
|
97
97
|
return new Promise((resolve, reject) => {
|
|
98
98
|
let body = "";
|
package/cjs/utils/staticFile.js
CHANGED
|
@@ -126,8 +126,8 @@ async function getFiles(dir, basePath = "/", ref, option) {
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
else {
|
|
129
|
-
const fs = await Promise.resolve().then(() => require("fs/promises"));
|
|
130
|
-
const path = await Promise.resolve().then(() => require("path"));
|
|
129
|
+
const fs = await Promise.resolve().then(() => require("node:fs/promises"));
|
|
130
|
+
const path = await Promise.resolve().then(() => require("node:path"));
|
|
131
131
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
132
132
|
for (const entry of entries) {
|
|
133
133
|
const fullPath = path.join(dir, entry.name);
|
package/cjs/utils/url.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wildcardOrOptionalParamRegex = void 0;
|
|
3
4
|
exports.sanitizePathSplit = sanitizePathSplit;
|
|
4
5
|
exports.urlParse = urlParse;
|
|
5
6
|
function sanitizePathSplit(basePath, path) {
|
|
@@ -9,6 +10,7 @@ function sanitizePathSplit(basePath, path) {
|
|
|
9
10
|
.filter(Boolean);
|
|
10
11
|
return parts;
|
|
11
12
|
}
|
|
13
|
+
exports.wildcardOrOptionalParamRegex = /\/\*|:[^/]+[?*]/;
|
|
12
14
|
function urlParse(url) {
|
|
13
15
|
let u = URL.parse(url);
|
|
14
16
|
let query = {};
|
|
@@ -10,7 +10,7 @@ export declare class TriMiddleware {
|
|
|
10
10
|
constructor(pathname?: string);
|
|
11
11
|
}
|
|
12
12
|
export default class MiddlewareConfigure<T extends Record<string, any> = {}> extends CommonHandler {
|
|
13
|
-
triMiddlewares: TriMiddleware;
|
|
13
|
+
protected triMiddlewares: TriMiddleware;
|
|
14
14
|
protected basePath: string;
|
|
15
15
|
constructor(basePath?: string);
|
|
16
16
|
protected addMiddleware(pathname: string, middlewares: Middleware<T>[]): void;
|
package/core/config.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { loggerOutput } from "../utils/debugging.js";
|
|
2
|
+
import { EnvironmentDetector } from "./environment.js";
|
|
2
3
|
export let GlobalConfig = class {
|
|
3
4
|
static notFound = (ctx) => {
|
|
4
5
|
const { method, urlRef: { pathname }, } = ctx.req;
|
|
@@ -11,7 +12,7 @@ export let GlobalConfig = class {
|
|
|
11
12
|
static overwriteMethod = true;
|
|
12
13
|
static debugMode = false;
|
|
13
14
|
static server;
|
|
14
|
-
static adapter;
|
|
15
|
+
static adapter = EnvironmentDetector.getEnvironment;
|
|
15
16
|
static get debugging() {
|
|
16
17
|
return this.debugMode
|
|
17
18
|
? {
|
package/core/context.js
CHANGED
|
@@ -90,8 +90,7 @@ export class Context {
|
|
|
90
90
|
this.#rawRequest = req;
|
|
91
91
|
this.method = req?.method?.toUpperCase();
|
|
92
92
|
this.#requestHeaders = new HeadersParser(req?.headers);
|
|
93
|
-
if (
|
|
94
|
-
GlobalConfig.adapter == "node") {
|
|
93
|
+
if (GlobalConfig.adapter == "node") {
|
|
95
94
|
let encrypted = req?.socket?.encrypted;
|
|
96
95
|
const protocol = typeof encrypted === "boolean"
|
|
97
96
|
? encrypted
|
|
@@ -283,7 +282,7 @@ export class Context {
|
|
|
283
282
|
let fileExists = false;
|
|
284
283
|
const runtime = EnvironmentDetector.getEnvironment;
|
|
285
284
|
if (runtime === "node") {
|
|
286
|
-
const { existsSync } = await import("fs");
|
|
285
|
+
const { existsSync } = await import("node:fs");
|
|
287
286
|
fileExists = existsSync(filePath);
|
|
288
287
|
}
|
|
289
288
|
else if (runtime === "bun") {
|
|
@@ -303,7 +302,7 @@ export class Context {
|
|
|
303
302
|
}
|
|
304
303
|
let fileBuffer;
|
|
305
304
|
if (runtime === "node") {
|
|
306
|
-
const { readFileSync } = await import("fs");
|
|
305
|
+
const { readFileSync } = await import("node:fs");
|
|
307
306
|
fileBuffer = await readFileSync(filePath);
|
|
308
307
|
}
|
|
309
308
|
else if (runtime === "bun") {
|
|
@@ -333,7 +332,7 @@ export class Context {
|
|
|
333
332
|
const resolvedPath = filePath;
|
|
334
333
|
let fileExists = false;
|
|
335
334
|
if (runtime === "node") {
|
|
336
|
-
const { existsSync } = await import("fs");
|
|
335
|
+
const { existsSync } = await import("node:fs");
|
|
337
336
|
fileExists = existsSync(resolvedPath);
|
|
338
337
|
}
|
|
339
338
|
else if (runtime === "bun") {
|
|
@@ -353,7 +352,7 @@ export class Context {
|
|
|
353
352
|
}
|
|
354
353
|
let fileSize = 0;
|
|
355
354
|
if (runtime === "node") {
|
|
356
|
-
const { statSync } = await import("fs");
|
|
355
|
+
const { statSync } = await import("node:fs");
|
|
357
356
|
fileSize = statSync(resolvedPath).size;
|
|
358
357
|
}
|
|
359
358
|
else if (runtime === "bun") {
|
|
@@ -367,7 +366,7 @@ export class Context {
|
|
|
367
366
|
const mimeType = mimeTypes[ext] || defaultMimeType;
|
|
368
367
|
let fileStream;
|
|
369
368
|
if (runtime === "node") {
|
|
370
|
-
const { createReadStream } = await import("fs");
|
|
369
|
+
const { createReadStream } = await import("node:fs");
|
|
371
370
|
fileStream = createReadStream(resolvedPath);
|
|
372
371
|
}
|
|
373
372
|
else if (runtime === "bun") {
|
package/core/header.d.ts
CHANGED
|
@@ -62,7 +62,7 @@ export declare class HeadersParser {
|
|
|
62
62
|
* Iterates over headers and executes a callback function.
|
|
63
63
|
* @param callback - Function to execute for each header.
|
|
64
64
|
*/
|
|
65
|
-
forEach(callback: (
|
|
65
|
+
forEach(callback: (value: string[], key: string) => void): void;
|
|
66
66
|
/**
|
|
67
67
|
* Converts headers into a plain object.
|
|
68
68
|
* @returns A record of headers where single-value headers are returned as a string.
|
package/core/header.js
CHANGED
package/core/request.d.ts
CHANGED
|
@@ -128,7 +128,7 @@ export declare class Request {
|
|
|
128
128
|
* console.log(key, value);
|
|
129
129
|
* });
|
|
130
130
|
*/
|
|
131
|
-
forEach: (callback: (
|
|
131
|
+
forEach: (callback: (value: string[], key: string) => void) => void;
|
|
132
132
|
/**
|
|
133
133
|
* Converts all headers into a plain JavaScript object.
|
|
134
134
|
* Single-value headers are represented as a string, and multi-value headers as an array.
|
package/core/request.js
CHANGED
|
@@ -80,10 +80,11 @@ export class Request {
|
|
|
80
80
|
return parseUrlEncodedBody(this.rawRequest);
|
|
81
81
|
}
|
|
82
82
|
else if (contentType.includes("multipart/form-data")) {
|
|
83
|
-
const
|
|
84
|
-
if (!
|
|
85
|
-
throw Error("Boundary not found");
|
|
83
|
+
const boundaryMatch = contentType.match(/boundary=([^;]+)/);
|
|
84
|
+
if (!boundaryMatch) {
|
|
85
|
+
throw new Error("Boundary not found in multipart/form-data");
|
|
86
86
|
}
|
|
87
|
+
const boundary = boundaryMatch[1];
|
|
87
88
|
return await parseMultipartBody(this.rawRequest, boundary, options);
|
|
88
89
|
}
|
|
89
90
|
else {
|
package/core/router.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getFiles } from "../utils/staticFile.js";
|
|
2
|
-
import { sanitizePathSplit } from "../utils/url.js";
|
|
2
|
+
import { sanitizePathSplit, wildcardOrOptionalParamRegex } from "../utils/url.js";
|
|
3
3
|
import { GlobalConfig } from "./config.js";
|
|
4
4
|
import MiddlewareConfigure, { TriMiddleware, } from "./MiddlewareConfigure.js";
|
|
5
5
|
class TrieRouter {
|
|
@@ -22,14 +22,13 @@ export class Router extends MiddlewareConfigure {
|
|
|
22
22
|
this.basePath = basePath;
|
|
23
23
|
this.env = { ...env };
|
|
24
24
|
this.triRouter = new TrieRouter(basePath);
|
|
25
|
-
this.get.bind(this);
|
|
26
|
-
this.post.bind(this);
|
|
27
|
-
this.put.bind(this);
|
|
28
|
-
this.delete.bind(this);
|
|
29
|
-
this.all.bind(this);
|
|
30
|
-
this
|
|
31
|
-
this.
|
|
32
|
-
this.group.bind(this);
|
|
25
|
+
this.get = this.get.bind(this);
|
|
26
|
+
this.post = this.post.bind(this);
|
|
27
|
+
this.put = this.put.bind(this);
|
|
28
|
+
this.delete = this.delete.bind(this);
|
|
29
|
+
this.all = this.all.bind(this);
|
|
30
|
+
this.addRouter = this.addRouter.bind(this);
|
|
31
|
+
this.group = this.group.bind(this);
|
|
33
32
|
}
|
|
34
33
|
static(...args) {
|
|
35
34
|
let route = "";
|
|
@@ -176,7 +175,7 @@ export class Router extends MiddlewareConfigure {
|
|
|
176
175
|
finalMiddleware = new Set(middlewares);
|
|
177
176
|
}
|
|
178
177
|
let p = parts.join("/");
|
|
179
|
-
if (
|
|
178
|
+
if (wildcardOrOptionalParamRegex.test(`/${p}`)) {
|
|
180
179
|
let handler = this.routers.get(p);
|
|
181
180
|
if (!handler) {
|
|
182
181
|
handler = new Map();
|
package/core/server.js
CHANGED
|
@@ -119,18 +119,22 @@ export class TezX extends Router {
|
|
|
119
119
|
}
|
|
120
120
|
return middlewares;
|
|
121
121
|
}
|
|
122
|
-
async #
|
|
123
|
-
let ctx = new Context(req, options);
|
|
124
|
-
const urlRef = ctx.req.urlRef;
|
|
125
|
-
const { pathname } = urlRef;
|
|
122
|
+
async #resolvePath(pathname) {
|
|
126
123
|
let resolvePath = pathname;
|
|
127
124
|
if (this.#onPathResolve) {
|
|
128
|
-
resolvePath = this.#onPathResolve(pathname);
|
|
125
|
+
resolvePath = await this.#onPathResolve(pathname);
|
|
129
126
|
GlobalConfig.debugging.warn(`${COLORS.white} PATH RESOLVE ${COLORS.reset} ${COLORS.red}${pathname}${COLORS.reset} ➞ ${COLORS.cyan}${resolvePath}${COLORS.reset}`);
|
|
130
127
|
}
|
|
131
128
|
if (typeof resolvePath !== "string") {
|
|
132
129
|
throw new Error(`Path resolution failed: expected a string, got ${typeof resolvePath}`);
|
|
133
130
|
}
|
|
131
|
+
return resolvePath;
|
|
132
|
+
}
|
|
133
|
+
async #handleRequest(req, options) {
|
|
134
|
+
let ctx = new Context(req, options);
|
|
135
|
+
const urlRef = ctx.req.urlRef;
|
|
136
|
+
const { pathname } = urlRef;
|
|
137
|
+
let resolvePath = await this.#resolvePath(pathname);
|
|
134
138
|
let middlewares = this.#findMiddleware(resolvePath);
|
|
135
139
|
ctx.env = this.env;
|
|
136
140
|
try {
|
|
@@ -176,15 +180,18 @@ export class TezX extends Router {
|
|
|
176
180
|
return finalResponse()(ctx);
|
|
177
181
|
}
|
|
178
182
|
catch (err) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
return res;
|
|
183
|
+
return this.#handleError(err, ctx);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
async #handleError(err, ctx) {
|
|
187
|
+
let error = err;
|
|
188
|
+
if (err instanceof Error) {
|
|
189
|
+
error = err.stack;
|
|
187
190
|
}
|
|
191
|
+
GlobalConfig.debugging.error(`${COLORS.bgRed} ${ctx.pathname}, Method: ${ctx.method} ${COLORS.reset}`, `${httpStatusMap[500]}: ${error} `);
|
|
192
|
+
let res = await GlobalConfig.onError(error, ctx);
|
|
193
|
+
ctx.setStatus = res.status;
|
|
194
|
+
return res;
|
|
188
195
|
}
|
|
189
196
|
async serve(req, options) {
|
|
190
197
|
return this.#handleRequest(req, options);
|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tezx",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.60",
|
|
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
|
"main": "cjs/index.js",
|
|
6
6
|
"module": "index.js",
|
package/utils/formData.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { GlobalConfig } from "../core/config.js";
|
|
2
2
|
export async function parseJsonBody(req) {
|
|
3
|
-
const runtime =
|
|
3
|
+
const runtime = GlobalConfig.adapter;
|
|
4
4
|
if (runtime === "node") {
|
|
5
5
|
return new Promise((resolve, reject) => {
|
|
6
6
|
let body = "";
|
|
@@ -25,7 +25,7 @@ export async function parseJsonBody(req) {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
export async function parseTextBody(req) {
|
|
28
|
-
const runtime =
|
|
28
|
+
const runtime = GlobalConfig.adapter;
|
|
29
29
|
if (runtime === "node") {
|
|
30
30
|
return new Promise((resolve, reject) => {
|
|
31
31
|
let body = "";
|
|
@@ -50,7 +50,7 @@ export async function parseTextBody(req) {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
export async function parseUrlEncodedBody(req) {
|
|
53
|
-
const runtime =
|
|
53
|
+
const runtime = GlobalConfig.adapter;
|
|
54
54
|
if (runtime === "node") {
|
|
55
55
|
return new Promise((resolve, reject) => {
|
|
56
56
|
let body = "";
|
|
@@ -86,7 +86,7 @@ export async function parseUrlEncodedBody(req) {
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
export async function parseMultipartBody(req, boundary, options) {
|
|
89
|
-
const runtime =
|
|
89
|
+
const runtime = GlobalConfig.adapter;
|
|
90
90
|
if (runtime === "node") {
|
|
91
91
|
return new Promise((resolve, reject) => {
|
|
92
92
|
let body = "";
|
package/utils/staticFile.js
CHANGED
|
@@ -122,8 +122,8 @@ export async function getFiles(dir, basePath = "/", ref, option) {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
else {
|
|
125
|
-
const fs = await import("fs/promises");
|
|
126
|
-
const path = await import("path");
|
|
125
|
+
const fs = await import("node:fs/promises");
|
|
126
|
+
const path = await import("node:path");
|
|
127
127
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
128
128
|
for (const entry of entries) {
|
|
129
129
|
const fullPath = path.join(dir, entry.name);
|
package/utils/url.d.ts
CHANGED
|
@@ -10,4 +10,5 @@ export type UrlRef = {
|
|
|
10
10
|
pathname: string | undefined;
|
|
11
11
|
};
|
|
12
12
|
export declare function sanitizePathSplit(basePath: string, path: string): string[];
|
|
13
|
+
export declare const wildcardOrOptionalParamRegex: RegExp;
|
|
13
14
|
export declare function urlParse(url: string): UrlRef;
|