tezx 4.0.1 → 4.0.3
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/cjs/core/context.js +16 -59
- package/cjs/core/request.js +0 -1
- package/cjs/core/server.js +41 -59
- package/cjs/helper/index.js +4 -0
- package/cjs/index.js +1 -1
- package/cjs/middleware/detect-bot.js +2 -1
- package/cjs/middleware/index.js +0 -1
- package/cjs/middleware/pagination.js +3 -2
- package/cjs/middleware/rate-limiter.js +5 -5
- package/cjs/registry/RadixRouter.js +11 -5
- package/cjs/utils/mimeTypes.js +17 -5
- package/cjs/utils/response.js +11 -11
- package/core/context.d.ts +30 -42
- package/core/context.js +16 -59
- package/core/request.d.ts +1 -13
- package/core/request.js +0 -1
- package/core/server.d.ts +1 -28
- package/core/server.js +41 -59
- package/helper/index.d.ts +15 -0
- package/helper/index.js +3 -0
- package/index.d.ts +1 -4
- package/index.js +1 -1
- package/middleware/detect-bot.d.ts +24 -42
- package/middleware/detect-bot.js +2 -1
- package/middleware/index.d.ts +0 -1
- package/middleware/index.js +0 -1
- package/middleware/pagination.js +3 -2
- package/middleware/rate-limiter.d.ts +27 -29
- package/middleware/rate-limiter.js +4 -4
- package/package.json +1 -1
- package/registry/RadixRouter.js +11 -5
- package/types/index.d.ts +12 -6
- package/utils/mimeTypes.d.ts +114 -1
- package/utils/mimeTypes.js +17 -5
- package/utils/response.d.ts +1 -1
- package/utils/response.js +11 -11
- package/cjs/config/index.js +0 -25
- package/cjs/middleware/getConnInfo.js +0 -13
- package/config/index.d.ts +0 -11
- package/config/index.js +0 -21
- package/middleware/getConnInfo.d.ts +0 -22
- package/middleware/getConnInfo.js +0 -10
package/cjs/core/context.js
CHANGED
|
@@ -12,7 +12,6 @@ class Context {
|
|
|
12
12
|
params = {};
|
|
13
13
|
rawRequest;
|
|
14
14
|
#server;
|
|
15
|
-
#body;
|
|
16
15
|
url;
|
|
17
16
|
res;
|
|
18
17
|
pathname;
|
|
@@ -32,7 +31,7 @@ class Context {
|
|
|
32
31
|
return this;
|
|
33
32
|
const _key = key.toLowerCase();
|
|
34
33
|
const append = options?.append || _key === "set-cookie";
|
|
35
|
-
const target = this.
|
|
34
|
+
const target = this.headers;
|
|
36
35
|
if (append) {
|
|
37
36
|
target.append(_key, value);
|
|
38
37
|
}
|
|
@@ -44,20 +43,15 @@ class Context {
|
|
|
44
43
|
get req() {
|
|
45
44
|
return (this.#req ??= new request_js_1.TezXRequest(this.rawRequest, this.method, this.pathname, this.params));
|
|
46
45
|
}
|
|
47
|
-
get body() {
|
|
48
|
-
return this.#body;
|
|
49
|
-
}
|
|
50
|
-
set body(value) {
|
|
51
|
-
this.#body = value;
|
|
52
|
-
}
|
|
53
46
|
status(status) {
|
|
54
47
|
this.#status = status;
|
|
55
48
|
return this;
|
|
56
49
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (
|
|
50
|
+
createResponse(body, type, init = {}) {
|
|
51
|
+
const headers = (0, response_js_1.mergeHeaders)(this.#headers, init.headers);
|
|
52
|
+
if (type) {
|
|
60
53
|
headers.set("Content-Type", type);
|
|
54
|
+
}
|
|
61
55
|
return new Response(body, {
|
|
62
56
|
status: init.status ?? this.#status,
|
|
63
57
|
statusText: init.statusText,
|
|
@@ -65,50 +59,16 @@ class Context {
|
|
|
65
59
|
});
|
|
66
60
|
}
|
|
67
61
|
newResponse(body, init = {}) {
|
|
68
|
-
|
|
69
|
-
return new Response(body, {
|
|
70
|
-
status: init.status ?? this.#status,
|
|
71
|
-
statusText: init.statusText,
|
|
72
|
-
headers,
|
|
73
|
-
});
|
|
62
|
+
return this.createResponse(body, null, init);
|
|
74
63
|
}
|
|
75
64
|
text(content, init) {
|
|
76
|
-
return this
|
|
65
|
+
return this.createResponse(content, "text/plain; charset=utf-8", init);
|
|
77
66
|
}
|
|
78
67
|
html(strings, init) {
|
|
79
|
-
return this
|
|
68
|
+
return this.createResponse(strings, "text/html; charset=utf-8", init);
|
|
80
69
|
}
|
|
81
70
|
json(json, init) {
|
|
82
|
-
return this
|
|
83
|
-
}
|
|
84
|
-
send(body, init) {
|
|
85
|
-
let _body;
|
|
86
|
-
let type;
|
|
87
|
-
if (body === null || body === undefined) {
|
|
88
|
-
_body = "";
|
|
89
|
-
type = "text/plain";
|
|
90
|
-
}
|
|
91
|
-
else if (typeof body === "string" || typeof body === "number") {
|
|
92
|
-
_body = body;
|
|
93
|
-
type = "text/plain";
|
|
94
|
-
}
|
|
95
|
-
else if (body instanceof Uint8Array || body instanceof ArrayBuffer || (typeof ReadableStream !== "undefined" && body instanceof ReadableStream)) {
|
|
96
|
-
_body = body;
|
|
97
|
-
type = "application/octet-stream";
|
|
98
|
-
}
|
|
99
|
-
else if (body instanceof Blob || (typeof File !== "undefined" && body instanceof File)) {
|
|
100
|
-
_body = body;
|
|
101
|
-
type = body.type || "application/octet-stream";
|
|
102
|
-
}
|
|
103
|
-
else if (typeof body === "object") {
|
|
104
|
-
_body = JSON.stringify(body);
|
|
105
|
-
type = "application/json";
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
_body = String(body);
|
|
109
|
-
type = "text/plain";
|
|
110
|
-
}
|
|
111
|
-
return this.#newResponse(_body, type, init);
|
|
71
|
+
return this.createResponse(JSON.stringify(json), "application/json; charset=utf-8", init);
|
|
112
72
|
}
|
|
113
73
|
redirect(url, status = 302) {
|
|
114
74
|
const headers = new Headers(this.#headers);
|
|
@@ -129,18 +89,15 @@ class Context {
|
|
|
129
89
|
if (init?.filename) {
|
|
130
90
|
headers["Content-Disposition"] = `attachment; filename="${init?.filename}"`;
|
|
131
91
|
}
|
|
92
|
+
let contentType = null;
|
|
132
93
|
if (init?.download || init?.filename) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
});
|
|
94
|
+
contentType = "application/octet-stream";
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
const ext = (0, utils_js_1.extensionExtract)(filePath);
|
|
98
|
+
contentType = mimeTypes_js_1.mimeTypes[ext] ?? mimeTypes_js_1.defaultMimeType;
|
|
139
99
|
}
|
|
140
|
-
|
|
141
|
-
const mimeType = mimeTypes_js_1.mimeTypes[ext] ?? mimeTypes_js_1.defaultMimeType;
|
|
142
|
-
headers["Content-Type"] = mimeType;
|
|
143
|
-
return this.newResponse(stream, {
|
|
100
|
+
return this.createResponse(stream, contentType, {
|
|
144
101
|
status: init?.status ?? this.#status,
|
|
145
102
|
statusText: init?.statusText,
|
|
146
103
|
headers,
|
package/cjs/core/request.js
CHANGED
package/cjs/core/server.js
CHANGED
|
@@ -4,23 +4,17 @@ exports.TezX = void 0;
|
|
|
4
4
|
const RadixRouter_js_1 = require("../registry/RadixRouter.js");
|
|
5
5
|
const response_js_1 = require("../utils/response.js");
|
|
6
6
|
const url_js_1 = require("../utils/url.js");
|
|
7
|
-
const index_js_1 = require("../config/index.js");
|
|
8
7
|
const context_js_1 = require("./context.js");
|
|
9
8
|
const router_js_1 = require("./router.js");
|
|
10
9
|
class TezX extends router_js_1.Router {
|
|
11
|
-
#pathResolver;
|
|
12
10
|
#notFound = response_js_1.notFoundResponse;
|
|
13
11
|
#errorHandler = response_js_1.handleErrorResponse;
|
|
14
|
-
constructor({ basePath = "/",
|
|
15
|
-
if (debugMode) {
|
|
16
|
-
index_js_1.Config.debugMode = debugMode;
|
|
17
|
-
}
|
|
12
|
+
constructor({ basePath = "/", routeRegistry = new RadixRouter_js_1.RadixRouter() } = {}) {
|
|
18
13
|
super({ basePath });
|
|
19
14
|
if (!routeRegistry) {
|
|
20
15
|
throw new Error("routeRegistry is required for TezX initialization");
|
|
21
16
|
}
|
|
22
17
|
this.router = routeRegistry;
|
|
23
|
-
this.#pathResolver = onPathResolve;
|
|
24
18
|
this.serve = this.serve.bind(this);
|
|
25
19
|
}
|
|
26
20
|
notFound(callback) {
|
|
@@ -31,64 +25,56 @@ class TezX extends router_js_1.Router {
|
|
|
31
25
|
this.#errorHandler = callback;
|
|
32
26
|
return this;
|
|
33
27
|
}
|
|
34
|
-
|
|
28
|
+
#composeChain(ctx, stack) {
|
|
35
29
|
let index = -1;
|
|
36
|
-
|
|
37
|
-
async function dispatch(i) {
|
|
30
|
+
const dispatch = (i) => {
|
|
38
31
|
if (i <= index)
|
|
39
|
-
|
|
32
|
+
return Promise.reject(new Error("next() called multiple times"));
|
|
40
33
|
index = i;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (typeof fn !== "function")
|
|
44
|
-
throw new TypeError(`Middleware[${i}] must be a function`);
|
|
45
|
-
res = (await fn(ctx, () => dispatch(i + 1)));
|
|
46
|
-
if (res !== undefined) {
|
|
47
|
-
ctx.res = res;
|
|
48
|
-
}
|
|
34
|
+
const fn = stack[i];
|
|
35
|
+
if (!fn)
|
|
49
36
|
return ctx.res;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
res = (await fn(ctx, () => dispatch(i + 1)));
|
|
57
|
-
if (res !== undefined) {
|
|
58
|
-
ctx.res = res;
|
|
37
|
+
try {
|
|
38
|
+
const result = fn(ctx, () => dispatch(i + 1));
|
|
39
|
+
if (!(result instanceof Promise)) {
|
|
40
|
+
if (result instanceof Response)
|
|
41
|
+
ctx.res = result;
|
|
42
|
+
return result ?? ctx.res;
|
|
59
43
|
}
|
|
60
|
-
return
|
|
44
|
+
return result.then((res) => {
|
|
45
|
+
if (res instanceof Response)
|
|
46
|
+
ctx.res = res;
|
|
47
|
+
return res ?? ctx.res;
|
|
48
|
+
}, (err) => Promise.reject(err));
|
|
61
49
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
50
|
+
catch (err) {
|
|
51
|
+
return Promise.reject(err);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
return dispatch(0);
|
|
66
55
|
}
|
|
67
56
|
async #handleRequest(req, method, server) {
|
|
68
|
-
|
|
69
|
-
throw new Error("Invalid request object provided to tezX server.");
|
|
70
|
-
const rawPath = (0, url_js_1.getPathname)(req.url);
|
|
71
|
-
const pathname = this.#pathResolver
|
|
72
|
-
? await this.#pathResolver(rawPath)
|
|
73
|
-
: rawPath;
|
|
57
|
+
const pathname = (0, url_js_1.getPathname)(req.url);
|
|
74
58
|
const ctx = new context_js_1.Context(req, pathname, method, server);
|
|
75
59
|
try {
|
|
76
60
|
const staticHandler = this.staticFile?.[`${method} ${pathname}`];
|
|
77
|
-
if (staticHandler)
|
|
61
|
+
if (staticHandler)
|
|
78
62
|
return staticHandler(ctx);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const mLen = route?.middlewares?.length;
|
|
82
|
-
const hLen = route?.handlers?.length;
|
|
83
|
-
if (!route || (hLen === 0 && mLen === 0)) {
|
|
63
|
+
const result = this.router?.search(method, pathname);
|
|
64
|
+
if (!result)
|
|
84
65
|
return this.#notFound(ctx);
|
|
66
|
+
const { match: middlewares, params } = result;
|
|
67
|
+
const mLen = middlewares.length;
|
|
68
|
+
if (mLen === 0)
|
|
69
|
+
return this.#notFound(ctx);
|
|
70
|
+
ctx.params = params;
|
|
71
|
+
if (mLen === 1) {
|
|
72
|
+
ctx.res = await middlewares[0](ctx);
|
|
85
73
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return ((await route.handlers[0](ctx)) ??
|
|
89
|
-
(ctx.body !== undefined ? ctx.send(ctx.body) : this.#notFound(ctx)));
|
|
74
|
+
else {
|
|
75
|
+
ctx.res = await this.#composeChain(ctx, middlewares);
|
|
90
76
|
}
|
|
91
|
-
return
|
|
77
|
+
return ctx.res ?? this.#notFound(ctx);
|
|
92
78
|
}
|
|
93
79
|
catch (err) {
|
|
94
80
|
let error = err instanceof Error ? err : new Error(String(err));
|
|
@@ -96,20 +82,16 @@ class TezX extends router_js_1.Router {
|
|
|
96
82
|
}
|
|
97
83
|
}
|
|
98
84
|
async serve(req, server) {
|
|
99
|
-
const method =
|
|
85
|
+
const method = req.method;
|
|
100
86
|
if (method === "HEAD") {
|
|
101
|
-
const
|
|
102
|
-
const headResponse = await this.#handleRequest(getRequest, method, server);
|
|
87
|
+
const res = await this.#handleRequest(req, "GET", server);
|
|
103
88
|
return new Response(null, {
|
|
104
|
-
status:
|
|
105
|
-
statusText:
|
|
106
|
-
headers:
|
|
89
|
+
status: res.status,
|
|
90
|
+
statusText: res.statusText,
|
|
91
|
+
headers: res.headers,
|
|
107
92
|
});
|
|
108
93
|
}
|
|
109
94
|
return this.#handleRequest(req, method, server);
|
|
110
95
|
}
|
|
111
96
|
}
|
|
112
97
|
exports.TezX = TezX;
|
|
113
|
-
if (!globalThis.TezX) {
|
|
114
|
-
globalThis.TezX = TezX;
|
|
115
|
-
}
|
package/cjs/helper/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.generateUUID = exports.generateRandomBase64 = exports.generateID = exports.useFormData = void 0;
|
|
4
|
+
exports.getConnInfo = getConnInfo;
|
|
4
5
|
const formData_js_1 = require("./formData.js");
|
|
5
6
|
Object.defineProperty(exports, "useFormData", { enumerable: true, get: function () { return formData_js_1.useFormData; } });
|
|
6
7
|
const generateID_js_1 = require("./generateID.js");
|
|
@@ -11,3 +12,6 @@ exports.default = {
|
|
|
11
12
|
useFormData: formData_js_1.useFormData,
|
|
12
13
|
generateID: generateID_js_1.generateID, generateRandomBase64: generateID_js_1.generateRandomBase64, generateUUID: generateID_js_1.generateUUID
|
|
13
14
|
};
|
|
15
|
+
function getConnInfo(ctx) {
|
|
16
|
+
return ctx?.server?.requestIP?.(ctx.rawRequest);
|
|
17
|
+
}
|
package/cjs/index.js
CHANGED
|
@@ -5,7 +5,7 @@ const router_js_1 = require("./core/router.js");
|
|
|
5
5
|
Object.defineProperty(exports, "Router", { enumerable: true, get: function () { return router_js_1.Router; } });
|
|
6
6
|
const server_js_1 = require("./core/server.js");
|
|
7
7
|
Object.defineProperty(exports, "TezX", { enumerable: true, get: function () { return server_js_1.TezX; } });
|
|
8
|
-
exports.version = "4.0.
|
|
8
|
+
exports.version = "4.0.3";
|
|
9
9
|
exports.default = {
|
|
10
10
|
Router: router_js_1.Router,
|
|
11
11
|
TezX: server_js_1.TezX,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.detectBot = void 0;
|
|
4
|
+
const index_js_1 = require("../helper/index.js");
|
|
4
5
|
const rateLimit_js_1 = require("../utils/rateLimit.js");
|
|
5
6
|
const detectBot = (opts = {}) => {
|
|
6
7
|
const botUAs = opts.botUserAgents || ["bot", "spider", "crawl", "slurp"];
|
|
@@ -8,7 +9,7 @@ const detectBot = (opts = {}) => {
|
|
|
8
9
|
const botRegex = new RegExp(botUAs.join("|"), "i");
|
|
9
10
|
checkBot = (ua) => botRegex.test(ua);
|
|
10
11
|
const keyGenerator = opts.keyGenerator ?? ((ctx) => {
|
|
11
|
-
const addr = ctx
|
|
12
|
+
const addr = (0, index_js_1.getConnInfo)(ctx);
|
|
12
13
|
return addr ? `${addr.address}:${addr.port}` : "unknown";
|
|
13
14
|
});
|
|
14
15
|
const maxReq = opts.maxRequests || 30;
|
package/cjs/middleware/index.js
CHANGED
|
@@ -20,7 +20,6 @@ __exportStar(require("./cache-control.js"), exports);
|
|
|
20
20
|
__exportStar(require("./cors.js"), exports);
|
|
21
21
|
__exportStar(require("./detect-bot.js"), exports);
|
|
22
22
|
__exportStar(require("./etag.js"), exports);
|
|
23
|
-
__exportStar(require("./getConnInfo.js"), exports);
|
|
24
23
|
__exportStar(require("./i18n.js"), exports);
|
|
25
24
|
__exportStar(require("./logger.js"), exports);
|
|
26
25
|
__exportStar(require("./pagination.js"), exports);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.rateLimiter = exports.default = void 0;
|
|
4
|
+
const index_js_1 = require("../helper/index.js");
|
|
4
5
|
const rateLimit_js_1 = require("../utils/rateLimit.js");
|
|
5
6
|
const rateLimiter = (options) => {
|
|
6
7
|
const { maxRequests, windowMs, keyGenerator = (ctx) => {
|
|
@@ -12,9 +13,8 @@ const rateLimiter = (options) => {
|
|
|
12
13
|
const clientIp = ctx.req.header("client-ip");
|
|
13
14
|
if (clientIp)
|
|
14
15
|
return clientIp;
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
return `${addr}:${port}`;
|
|
16
|
+
const { port, address } = (0, index_js_1.getConnInfo)(ctx) ?? {};
|
|
17
|
+
return `${address}:${port}`;
|
|
18
18
|
}, storage = (0, rateLimit_js_1.createRateLimitDefaultStorage)(), onError = (ctx, retryAfter, error) => {
|
|
19
19
|
ctx.status(429);
|
|
20
20
|
throw new Error(`Rate limit exceeded. Try again in ${retryAfter} seconds.`);
|
|
@@ -33,5 +33,5 @@ const rateLimiter = (options) => {
|
|
|
33
33
|
return await next();
|
|
34
34
|
};
|
|
35
35
|
};
|
|
36
|
-
exports.rateLimiter = rateLimiter;
|
|
37
36
|
exports.default = rateLimiter;
|
|
37
|
+
exports.rateLimiter = rateLimiter;
|
|
@@ -39,12 +39,18 @@ class RadixRouter {
|
|
|
39
39
|
search(method, path) {
|
|
40
40
|
let params = {};
|
|
41
41
|
let middlewares = [];
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return { method, params
|
|
42
|
+
const segments = path?.split("/")?.filter(Boolean);
|
|
43
|
+
const { success, node } = this._match(method, this.root, segments, 0, params, middlewares);
|
|
44
|
+
if (!success || !node) {
|
|
45
|
+
return { method, params: {}, match: [] };
|
|
46
46
|
}
|
|
47
|
-
|
|
47
|
+
const list = node.handlers?.[method];
|
|
48
|
+
if (list) {
|
|
49
|
+
for (let i = 0; i < list.length; i++) {
|
|
50
|
+
middlewares.push(list[i]);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return { method, params, match: middlewares };
|
|
48
54
|
}
|
|
49
55
|
_match(method, node, segments, index, params, middlewares) {
|
|
50
56
|
if (node?.handlers?.ALL) {
|
package/cjs/utils/mimeTypes.js
CHANGED
|
@@ -15,6 +15,10 @@ exports.mimeTypes = {
|
|
|
15
15
|
tsv: "text/tab-separated-values",
|
|
16
16
|
rtf: "application/rtf",
|
|
17
17
|
markdown: "text/markdown",
|
|
18
|
+
jsx: "text/javascript",
|
|
19
|
+
ts: "text/typescript",
|
|
20
|
+
tsx: "text/typescript",
|
|
21
|
+
jsonld: "application/ld+json",
|
|
18
22
|
png: "image/png",
|
|
19
23
|
jpg: "image/jpeg",
|
|
20
24
|
jpeg: "image/jpeg",
|
|
@@ -25,6 +29,13 @@ exports.mimeTypes = {
|
|
|
25
29
|
bmp: "image/bmp",
|
|
26
30
|
tiff: "image/tiff",
|
|
27
31
|
psd: "image/vnd.adobe.photoshop",
|
|
32
|
+
tif: "image/tiff",
|
|
33
|
+
avif: "image/avif",
|
|
34
|
+
woff: "font/woff",
|
|
35
|
+
woff2: "font/woff2",
|
|
36
|
+
ttf: "font/ttf",
|
|
37
|
+
otf: "font/otf",
|
|
38
|
+
eot: "application/vnd.ms-fontobject",
|
|
28
39
|
mp4: "video/mp4",
|
|
29
40
|
webm: "video/webm",
|
|
30
41
|
ogg: "video/ogg",
|
|
@@ -33,6 +44,9 @@ exports.mimeTypes = {
|
|
|
33
44
|
wmv: "video/x-ms-wmv",
|
|
34
45
|
flv: "video/x-flv",
|
|
35
46
|
"3gp": "video/3gpp",
|
|
47
|
+
mkv: "video/x-matroska",
|
|
48
|
+
mpeg: "video/mpeg",
|
|
49
|
+
mpg: "video/mpeg",
|
|
36
50
|
mp3: "audio/mpeg",
|
|
37
51
|
wav: "audio/wav",
|
|
38
52
|
aac: "audio/aac",
|
|
@@ -40,11 +54,7 @@ exports.mimeTypes = {
|
|
|
40
54
|
m4a: "audio/mp4",
|
|
41
55
|
mid: "audio/midi",
|
|
42
56
|
midi: "audio/midi",
|
|
43
|
-
|
|
44
|
-
woff2: "font/woff2",
|
|
45
|
-
ttf: "font/ttf",
|
|
46
|
-
otf: "font/otf",
|
|
47
|
-
eot: "application/vnd.ms-fontobject",
|
|
57
|
+
weba: "audio/webm",
|
|
48
58
|
pdf: "application/pdf",
|
|
49
59
|
odp: "application/vnd.oasis.opendocument.presentation",
|
|
50
60
|
zip: "application/zip",
|
|
@@ -83,6 +93,8 @@ exports.mimeTypes = {
|
|
|
83
93
|
deb: "application/x-debian-package",
|
|
84
94
|
rpm: "application/x-redhat-package-manager",
|
|
85
95
|
apk: "application/vnd.android.package-archive",
|
|
96
|
+
bin: "application/octet-stream",
|
|
97
|
+
iso: "application/octet-stream",
|
|
86
98
|
webmanifest: "application/manifest+json",
|
|
87
99
|
ics: "text/calendar",
|
|
88
100
|
vcf: "text/vcard",
|
package/cjs/utils/response.js
CHANGED
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.notFoundResponse = void 0;
|
|
4
4
|
exports.mergeHeaders = mergeHeaders;
|
|
5
5
|
exports.handleErrorResponse = handleErrorResponse;
|
|
6
|
-
const index_js_1 = require("../config/index.js");
|
|
7
6
|
let notFoundResponse = (ctx) => {
|
|
8
7
|
const { method, pathname } = ctx;
|
|
9
8
|
return ctx.text(`${method}: '${pathname}' could not find\n`, {
|
|
@@ -11,24 +10,25 @@ let notFoundResponse = (ctx) => {
|
|
|
11
10
|
});
|
|
12
11
|
};
|
|
13
12
|
exports.notFoundResponse = notFoundResponse;
|
|
14
|
-
function mergeHeaders(existing,
|
|
13
|
+
function mergeHeaders(existing, init) {
|
|
15
14
|
if (!existing)
|
|
16
|
-
return new Headers(
|
|
17
|
-
if (!
|
|
15
|
+
return new Headers(init);
|
|
16
|
+
if (!init)
|
|
18
17
|
return existing;
|
|
19
18
|
const out = new Headers(existing);
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
if (
|
|
23
|
-
out.append(
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
for (const key in init) {
|
|
20
|
+
const val = init[key];
|
|
21
|
+
if (val && key.toLowerCase() === "set-cookie") {
|
|
22
|
+
out.append(key, val);
|
|
23
|
+
}
|
|
24
|
+
else if (val) {
|
|
25
|
+
out.set(key, val);
|
|
26
|
+
}
|
|
26
27
|
}
|
|
27
28
|
return out;
|
|
28
29
|
}
|
|
29
30
|
async function handleErrorResponse(err = new Error("Internal Server Error"), ctx) {
|
|
30
31
|
if (err instanceof Error) {
|
|
31
|
-
index_js_1.Config.debugging.error(err?.message);
|
|
32
32
|
return ctx.status(500).send(err.message ?? "Internal Server Error");
|
|
33
33
|
}
|
|
34
34
|
return await handleErrorResponse(new Error(err), ctx);
|
package/core/context.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ExtractParamsFromPath, HttpBaseResponse, ResHeaderKey, ResponseInit, WebSocketEvent } from "../types/index.js";
|
|
2
|
+
import { ContentType } from "../utils/mimeTypes.js";
|
|
2
3
|
import { TezXRequest } from "./request.js";
|
|
3
4
|
export declare class Context<TPath extends string = any> {
|
|
4
5
|
#private;
|
|
@@ -102,16 +103,6 @@ export declare class Context<TPath extends string = any> {
|
|
|
102
103
|
* @returns {TezXRequest<TPath>} The wrapped request.
|
|
103
104
|
*/
|
|
104
105
|
get req(): TezXRequest<TPath>;
|
|
105
|
-
/**
|
|
106
|
-
* Gets the response body.
|
|
107
|
-
* @returns {*} The response body.
|
|
108
|
-
*/
|
|
109
|
-
get body(): any;
|
|
110
|
-
/**
|
|
111
|
-
* Sets the response body.
|
|
112
|
-
* @param {*} value - The response body.
|
|
113
|
-
*/
|
|
114
|
-
set body(value: any);
|
|
115
106
|
/**
|
|
116
107
|
* Sets the HTTP response status code.
|
|
117
108
|
*
|
|
@@ -122,6 +113,35 @@ export declare class Context<TPath extends string = any> {
|
|
|
122
113
|
* ctx.status(404).text("Not found");
|
|
123
114
|
*/
|
|
124
115
|
status(status: number): this;
|
|
116
|
+
/**
|
|
117
|
+
* Creates a native Response object with optional body, Content-Type, and headers.
|
|
118
|
+
*
|
|
119
|
+
* This function always overwrites the `Content-Type` header if `type` is provided.
|
|
120
|
+
* It merges any existing headers from the context (`this.#headers`) with headers
|
|
121
|
+
* provided in `init.headers`.
|
|
122
|
+
*
|
|
123
|
+
* @param {BodyInit | null} body - The response body. Can be string, Blob, ArrayBuffer, Uint8Array, or null.
|
|
124
|
+
* @param {string | null} type - The MIME type to set in the `Content-Type` header. If null, no Content-Type is set.
|
|
125
|
+
* @param {ResponseInit} [init={}] - Optional response initialization object (status, statusText, headers).
|
|
126
|
+
* @param {number} [init.status] - HTTP status code (default is `this.#status`).
|
|
127
|
+
* @param {string} [init.statusText] - Optional status text for the response.
|
|
128
|
+
* @param {HeadersInit} [init.headers] - Additional headers to merge with context headers.
|
|
129
|
+
*
|
|
130
|
+
* @returns {Response} A native Fetch API Response object.
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* // Simple text response
|
|
134
|
+
* const res = createResponse("Hello World", "text/plain");
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* // JSON response
|
|
138
|
+
* const res = createResponse(JSON.stringify({ ok: true }), "application/json", { status: 200 });
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* // Custom headers
|
|
142
|
+
* const res = createResponse("Hello", "text/plain", { headers: { "X-Custom": "test" } });
|
|
143
|
+
*/
|
|
144
|
+
createResponse(body: BodyInit | null, type: ContentType | null, init?: ResponseInit): Response;
|
|
125
145
|
/**
|
|
126
146
|
* Protected helper method to create a Response or PlainResponse
|
|
127
147
|
* based on runtime environment (Node.js or Web).
|
|
@@ -167,38 +187,6 @@ export declare class Context<TPath extends string = any> {
|
|
|
167
187
|
* ctx.json({ success: true });
|
|
168
188
|
*/
|
|
169
189
|
json(json: object, init?: ResponseInit): HttpBaseResponse;
|
|
170
|
-
/**
|
|
171
|
-
* Send a response with automatic content type detection.
|
|
172
|
-
*
|
|
173
|
-
* This method determines the proper `Content-Type` header based on the type of `body`.
|
|
174
|
-
* If a `Content-Type` is provided in `init.headers`, it will be used instead.
|
|
175
|
-
*
|
|
176
|
-
* Supported types:
|
|
177
|
-
* - `string` / `number` → "text/plain"
|
|
178
|
-
* - `object` → JSON serialized, "application/json"
|
|
179
|
-
* - `Uint8Array` / `ArrayBuffer` / `ReadableStream` → "application/octet-stream"
|
|
180
|
-
* - `Blob` / `File` → uses `body.type` or falls back to "application/octet-stream"
|
|
181
|
-
* - `null` / `undefined` → empty string, "text/plain"
|
|
182
|
-
* - any other → `String(body)`, "text/plain"
|
|
183
|
-
*
|
|
184
|
-
* @param {any} body - Response body of any type.
|
|
185
|
-
* @param {ResponseInit} [init] - Optional response init object, headers, status, etc.
|
|
186
|
-
* @returns {HttpBaseResponse} - A Bun-compatible response object.
|
|
187
|
-
*
|
|
188
|
-
* @example
|
|
189
|
-
* // Send a string
|
|
190
|
-
* ctx.send("Hello World");
|
|
191
|
-
*
|
|
192
|
-
* // Send JSON
|
|
193
|
-
* ctx.send({ user: "Alice", id: 123 });
|
|
194
|
-
*
|
|
195
|
-
* // Send binary
|
|
196
|
-
* ctx.send(new Uint8Array([1,2,3]));
|
|
197
|
-
*
|
|
198
|
-
* // Custom content-type
|
|
199
|
-
* ctx.send("Hello", { headers: { "Content-Type": "text/html" } });
|
|
200
|
-
*/
|
|
201
|
-
send(body: any, init?: ResponseInit): HttpBaseResponse;
|
|
202
190
|
/**
|
|
203
191
|
* Sends an HTTP redirect response to the specified URL.
|
|
204
192
|
*
|