tezx 1.0.73 → 1.0.75-beta
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.d.ts +29 -0
- package/adapter/deno.d.ts +30 -0
- package/adapter/index.d.ts +1 -1
- package/adapter/index.js +1 -1
- package/adapter/node/index.d.ts +47 -0
- package/adapter/{node.js → node/index.js} +2 -2
- package/cjs/adapter/index.js +1 -1
- package/cjs/adapter/{node.js → node/index.js} +2 -2
- package/cjs/core/context.js +13 -97
- package/cjs/core/environment.js +0 -8
- package/cjs/core/request.js +69 -25
- package/cjs/core/router.js +5 -0
- package/cjs/core/server.js +6 -5
- package/cjs/index.js +1 -1
- package/cjs/middleware/basicAuth.js +1 -1
- package/cjs/middleware/cacheControl.js +1 -1
- package/cjs/middleware/cors.js +2 -2
- package/cjs/middleware/detectBot.js +1 -1
- package/cjs/middleware/detectLocale.js +1 -1
- package/cjs/middleware/{i18nMiddleware.js → i18n.js} +4 -4
- package/cjs/middleware/index.js +1 -1
- package/cjs/middleware/lazyLoadModules.js +1 -1
- package/cjs/middleware/logger.js +1 -1
- package/cjs/middleware/pagination.js +1 -1
- package/cjs/middleware/powered-by.js +1 -1
- package/cjs/middleware/rateLimiter.js +1 -1
- package/cjs/middleware/request-id.js +1 -1
- package/cjs/middleware/requestTimeout.js +1 -1
- package/cjs/middleware/sanitizeHeader.js +3 -3
- package/cjs/middleware/secureHeaders.js +1 -1
- package/cjs/middleware/xssProtection.js +1 -1
- package/cjs/utils/formData.js +0 -235
- package/cjs/utils/httpStatusMap.js +68 -0
- package/cjs/utils/staticFile.js +4 -1
- package/cjs/utils/toWebRequest.js +35 -0
- package/core/context.d.ts +5 -6
- package/core/context.js +14 -98
- package/core/environment.d.ts +0 -2
- package/core/environment.js +0 -8
- package/core/request.d.ts +11 -32
- package/core/request.js +70 -26
- package/core/router.d.ts +30 -0
- package/core/router.js +5 -0
- package/core/server.js +5 -4
- package/index.js +1 -1
- package/middleware/basicAuth.js +1 -1
- package/middleware/cacheControl.js +1 -1
- package/middleware/cors.js +2 -2
- package/middleware/detectBot.js +1 -1
- package/middleware/detectLocale.js +1 -1
- package/middleware/{i18nMiddleware.d.ts → i18n.d.ts} +3 -3
- package/middleware/{i18nMiddleware.js → i18n.js} +2 -2
- package/middleware/index.d.ts +1 -1
- package/middleware/index.js +1 -1
- package/middleware/lazyLoadModules.js +1 -1
- package/middleware/logger.js +1 -1
- package/middleware/pagination.js +1 -1
- package/middleware/powered-by.js +1 -1
- package/middleware/rateLimiter.js +1 -1
- package/middleware/request-id.js +1 -1
- package/middleware/requestTimeout.js +1 -1
- package/middleware/sanitizeHeader.js +3 -3
- package/middleware/secureHeaders.js +1 -1
- package/middleware/xssProtection.js +1 -1
- package/package.json +1 -1
- package/utils/formData.d.ts +0 -5
- package/utils/formData.js +0 -231
- package/utils/httpStatusMap.d.ts +1 -0
- package/utils/httpStatusMap.js +65 -0
- package/utils/staticFile.js +4 -1
- package/utils/toWebRequest.d.ts +11 -0
- package/utils/toWebRequest.js +32 -0
- package/adapter/node.d.ts +0 -19
- package/cjs/core/header.js +0 -92
- package/core/header.d.ts +0 -77
- package/core/header.js +0 -88
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.paginationHandler = void 0;
|
|
4
4
|
const paginationHandler = (options = {}) => {
|
|
5
5
|
const { defaultPage = 1, defaultLimit = 10, maxLimit = 100, queryKeyPage = "page", queryKeyLimit = "limit", countKey = "total", dataKey = "data", getDataSource, } = options;
|
|
6
|
-
return async (ctx, next)
|
|
6
|
+
return async function paginationHandler(ctx, next) {
|
|
7
7
|
const rawPage = ctx.req.query[queryKeyPage];
|
|
8
8
|
const rawLimit = ctx.req.query[queryKeyLimit];
|
|
9
9
|
const page = Math.max(parseInt(rawPage || `${defaultPage}`, 10), 1);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.poweredBy = void 0;
|
|
4
4
|
const poweredBy = (serverName) => {
|
|
5
|
-
return (ctx, next)
|
|
5
|
+
return function poweredBy(ctx, next) {
|
|
6
6
|
ctx.header("X-Powered-By", serverName || "TezX");
|
|
7
7
|
return next();
|
|
8
8
|
};
|
|
@@ -7,7 +7,7 @@ const rateLimiter = (options) => {
|
|
|
7
7
|
ctx.setStatus = 429;
|
|
8
8
|
throw new Error(`Rate limit exceeded. Try again in ${retryAfter} seconds.`);
|
|
9
9
|
}, } = options;
|
|
10
|
-
return async (ctx, next)
|
|
10
|
+
return async function rateLimiter(ctx, next) {
|
|
11
11
|
const key = keyGenerator(ctx);
|
|
12
12
|
const { check, entry } = (0, detectBot_js_1.isRateLimit)(ctx, key, storage, maxRequests, windowMs);
|
|
13
13
|
if (check) {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.requestID = void 0;
|
|
4
4
|
const index_js_1 = require("../helper/index.js");
|
|
5
5
|
const requestID = (headerName = "X-Request-ID", contextKey = "requestID") => {
|
|
6
|
-
return (ctx, next)
|
|
6
|
+
return function requestID(ctx, next) {
|
|
7
7
|
const existingID = ctx.headers?.get(headerName.toLowerCase()) ||
|
|
8
8
|
ctx.headers?.get(headerName);
|
|
9
9
|
const requestId = existingID || `req-${(0, index_js_1.generateID)()}`;
|
|
@@ -10,7 +10,7 @@ const requestTimeout = (options) => {
|
|
|
10
10
|
config_js_1.GlobalConfig.debugging.warn(`[TIMEOUT] ${error.message}: ${ctx.method} ${ctx.path}`);
|
|
11
11
|
}, cleanup = () => {
|
|
12
12
|
}, } = options;
|
|
13
|
-
return async (ctx, next)
|
|
13
|
+
return async function requestTimeout(ctx, next) {
|
|
14
14
|
let timeoutId = null;
|
|
15
15
|
try {
|
|
16
16
|
const timeout = getTimeout(ctx);
|
|
@@ -4,7 +4,7 @@ exports.sanitizeHeaders = void 0;
|
|
|
4
4
|
const config_js_1 = require("../core/config.js");
|
|
5
5
|
const sanitizeHeaders = (options = {}) => {
|
|
6
6
|
const { whitelist = [], blacklist = [], normalizeKeys = true, allowUnsafeCharacters = false, } = options;
|
|
7
|
-
return async (ctx, next)
|
|
7
|
+
return async function sanitizeHeaders(ctx, next) {
|
|
8
8
|
const sanitizedHeaders = new Map();
|
|
9
9
|
for (const [key, values] of ctx.headers.entries()) {
|
|
10
10
|
if (!Array.isArray(values) || values.length === 0) {
|
|
@@ -31,9 +31,9 @@ const sanitizeHeaders = (options = {}) => {
|
|
|
31
31
|
config_js_1.GlobalConfig.debugging.warn(`⚠️ All values for "${normalizedKey}" invalid - removed`);
|
|
32
32
|
continue;
|
|
33
33
|
}
|
|
34
|
-
sanitizedHeaders.set(normalizedKey, sanitizedValues);
|
|
34
|
+
sanitizedHeaders.set(normalizedKey, sanitizedValues?.join(", "));
|
|
35
35
|
}
|
|
36
|
-
ctx.headers
|
|
36
|
+
ctx.headers = new Headers(sanitizedHeaders);
|
|
37
37
|
return await next();
|
|
38
38
|
};
|
|
39
39
|
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.secureHeaders = void 0;
|
|
4
4
|
const secureHeaders = (options = {}) => {
|
|
5
|
-
return async (ctx, next)
|
|
5
|
+
return async function secureHeaders(ctx, next) {
|
|
6
6
|
const resolveValue = (value) => {
|
|
7
7
|
return typeof value === "function" ? value(ctx) : value;
|
|
8
8
|
};
|
|
@@ -4,7 +4,7 @@ exports.xssProtection = void 0;
|
|
|
4
4
|
const config_js_1 = require("../core/config.js");
|
|
5
5
|
const xssProtection = (options = {}) => {
|
|
6
6
|
const { enabled = true, mode = "block", fallbackCSP = "default-src 'self'; script-src 'self';", } = options;
|
|
7
|
-
return async (ctx, next)
|
|
7
|
+
return async function xssProtection(ctx, next) {
|
|
8
8
|
const isEnabled = typeof enabled === "function" ? enabled(ctx) : enabled;
|
|
9
9
|
if (!isEnabled) {
|
|
10
10
|
config_js_1.GlobalConfig.debugging.warn("🟠 XSS protection is disabled.");
|
package/cjs/utils/formData.js
CHANGED
|
@@ -1,97 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseJsonBody = parseJsonBody;
|
|
4
|
-
exports.parseTextBody = parseTextBody;
|
|
5
|
-
exports.parseUrlEncodedBody = parseUrlEncodedBody;
|
|
6
3
|
exports.sanitized = sanitized;
|
|
7
|
-
exports.parseMultipartBody = parseMultipartBody;
|
|
8
|
-
const config_js_1 = require("../core/config.js");
|
|
9
|
-
async function parseJsonBody(req) {
|
|
10
|
-
const runtime = config_js_1.GlobalConfig.adapter;
|
|
11
|
-
if (runtime === "node") {
|
|
12
|
-
return new Promise((resolve, reject) => {
|
|
13
|
-
let body = "";
|
|
14
|
-
req.on("data", (chunk) => {
|
|
15
|
-
body += chunk.toString();
|
|
16
|
-
});
|
|
17
|
-
req.on("end", () => {
|
|
18
|
-
try {
|
|
19
|
-
resolve(JSON.parse(body));
|
|
20
|
-
}
|
|
21
|
-
catch (error) {
|
|
22
|
-
reject(new Error("Invalid JSON format"));
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
else if (runtime === "deno" || runtime === "bun") {
|
|
28
|
-
return await req.json();
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
throw new Error("Unsupported environment for multipart parsing");
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
async function parseTextBody(req) {
|
|
35
|
-
const runtime = config_js_1.GlobalConfig.adapter;
|
|
36
|
-
if (runtime === "node") {
|
|
37
|
-
return new Promise((resolve, reject) => {
|
|
38
|
-
let body = "";
|
|
39
|
-
req.on("data", (chunk) => {
|
|
40
|
-
body += chunk.toString();
|
|
41
|
-
});
|
|
42
|
-
req.on("end", () => {
|
|
43
|
-
try {
|
|
44
|
-
resolve(body);
|
|
45
|
-
}
|
|
46
|
-
catch (error) {
|
|
47
|
-
reject(new Error("Invalid JSON format"));
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
else if (runtime === "deno" || runtime === "bun") {
|
|
53
|
-
return await req.text();
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
throw new Error("Unsupported environment for multipart parsing");
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
async function parseUrlEncodedBody(req) {
|
|
60
|
-
const runtime = config_js_1.GlobalConfig.adapter;
|
|
61
|
-
if (runtime === "node") {
|
|
62
|
-
return new Promise((resolve, reject) => {
|
|
63
|
-
let body = "";
|
|
64
|
-
req.on("data", (chunk) => {
|
|
65
|
-
body += chunk.toString("binary");
|
|
66
|
-
});
|
|
67
|
-
req.on("end", () => {
|
|
68
|
-
try {
|
|
69
|
-
const pairs = body.split("&");
|
|
70
|
-
const formData = {};
|
|
71
|
-
pairs.forEach((pair) => {
|
|
72
|
-
const [key, value] = pair.split("=");
|
|
73
|
-
formData[decodeURIComponent(key)] = decodeURIComponent(value || "");
|
|
74
|
-
});
|
|
75
|
-
resolve(formData);
|
|
76
|
-
}
|
|
77
|
-
catch {
|
|
78
|
-
reject(new Error("Invalid x-www-form-urlencoded format"));
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
else if (runtime === "deno" || runtime === "bun") {
|
|
84
|
-
const formData = await req.formData();
|
|
85
|
-
const result = {};
|
|
86
|
-
for (const [key, value] of formData.entries()) {
|
|
87
|
-
result[key] = value;
|
|
88
|
-
}
|
|
89
|
-
return result;
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
throw new Error("Unsupported environment for multipart parsing");
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
4
|
function sanitized(title) {
|
|
96
5
|
const base = title
|
|
97
6
|
.toLowerCase()
|
|
@@ -102,147 +11,3 @@ function sanitized(title) {
|
|
|
102
11
|
.replace(/^-+|-+$/g, "");
|
|
103
12
|
return base;
|
|
104
13
|
}
|
|
105
|
-
async function parseMultipartBody(req, boundary, options) {
|
|
106
|
-
const runtime = config_js_1.GlobalConfig.adapter;
|
|
107
|
-
if (runtime === "node") {
|
|
108
|
-
return new Promise((resolve, reject) => {
|
|
109
|
-
let body = "";
|
|
110
|
-
req.on("data", (chunk) => {
|
|
111
|
-
body += chunk.toString("binary");
|
|
112
|
-
});
|
|
113
|
-
req.on("end", () => {
|
|
114
|
-
try {
|
|
115
|
-
const formDataField = {};
|
|
116
|
-
const formDataFieldParts = body.split("----------------------------");
|
|
117
|
-
formDataFieldParts.forEach((part) => {
|
|
118
|
-
const match = part.match(/name="(.*)"\r\n\r\n(.*)\r\n/);
|
|
119
|
-
if (match && match.length === 3) {
|
|
120
|
-
const name = match[1];
|
|
121
|
-
const value = match[2];
|
|
122
|
-
if (formDataField[name]) {
|
|
123
|
-
if (Array.isArray(formDataField[name])) {
|
|
124
|
-
formDataField[name].push(value);
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
formDataField[name] = [formDataField[name], value];
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
else {
|
|
131
|
-
formDataField[name] = value;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
const parts = body.split(`--${boundary}`);
|
|
136
|
-
for (const part of parts) {
|
|
137
|
-
if (part.includes("filename")) {
|
|
138
|
-
const filenameMatch = part.match(/filename="([^"]+)"/);
|
|
139
|
-
const fieldNameMatch = part.match(/name="([^"]+)"/);
|
|
140
|
-
const contentTypeMatch = part.match(/Content-Type: ([^\r\n]+)/);
|
|
141
|
-
if (filenameMatch && fieldNameMatch && contentTypeMatch) {
|
|
142
|
-
let filename = filenameMatch[1];
|
|
143
|
-
const fieldName = fieldNameMatch[1];
|
|
144
|
-
const contentType = contentTypeMatch[1];
|
|
145
|
-
if (options?.sanitized) {
|
|
146
|
-
filename = `${Date.now()}-${sanitized(filename)}`;
|
|
147
|
-
}
|
|
148
|
-
if (Array.isArray(options?.allowedTypes) &&
|
|
149
|
-
!options.allowedTypes?.includes(contentType)) {
|
|
150
|
-
reject(new Error(`Invalid file type: "${contentType}". Allowed types: ${options.allowedTypes.join(", ")}`));
|
|
151
|
-
}
|
|
152
|
-
const fileContentStartIndex = part.indexOf("\r\n\r\n") + 4;
|
|
153
|
-
const fileContent = Buffer.from(part.substring(fileContentStartIndex), "binary");
|
|
154
|
-
const arrayBuffer = fileContent.buffer.slice(fileContent.byteOffset, fileContent.byteOffset + fileContent.byteLength);
|
|
155
|
-
if (typeof options?.maxSize !== "undefined" &&
|
|
156
|
-
fileContent.byteLength > options.maxSize) {
|
|
157
|
-
reject(new Error(`File size exceeds the limit: ${fileContent.byteLength} bytes (Max: ${options.maxSize} bytes)`));
|
|
158
|
-
}
|
|
159
|
-
const file = new File([arrayBuffer], filename, {
|
|
160
|
-
type: contentType,
|
|
161
|
-
});
|
|
162
|
-
if (typeof options?.maxFiles != "undefined" &&
|
|
163
|
-
options.maxFiles == 0) {
|
|
164
|
-
reject(new Error(`Field "${fieldName}" exceeds the maximum allowed file count of ${options.maxFiles}.`));
|
|
165
|
-
}
|
|
166
|
-
if (formDataField[fieldName]) {
|
|
167
|
-
if (Array.isArray(formDataField[fieldName])) {
|
|
168
|
-
const existingFiles = formDataField[fieldName].filter((f) => f instanceof File);
|
|
169
|
-
if (typeof options?.maxFiles != "undefined" &&
|
|
170
|
-
existingFiles.length >= options.maxFiles) {
|
|
171
|
-
reject(new Error(`Field "${fieldName}" exceeds the maximum allowed file count of ${options.maxFiles}.`));
|
|
172
|
-
}
|
|
173
|
-
formDataField[fieldName].push(file);
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
if (formDataField[fieldName] instanceof File &&
|
|
177
|
-
typeof options?.maxFiles != "undefined" &&
|
|
178
|
-
options.maxFiles == 1) {
|
|
179
|
-
reject(new Error(`Field "${fieldName}" exceeds the maximum allowed file count of ${options.maxFiles}.`));
|
|
180
|
-
}
|
|
181
|
-
formDataField[fieldName] = [formDataField[fieldName], file];
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
formDataField[fieldName] = file;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
resolve(formDataField);
|
|
191
|
-
}
|
|
192
|
-
catch { }
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
else if (runtime === "deno" || runtime === "bun") {
|
|
197
|
-
const formData = await req.formData();
|
|
198
|
-
const result = {};
|
|
199
|
-
for (const [key, value] of formData.entries()) {
|
|
200
|
-
let val = value;
|
|
201
|
-
if (val instanceof File && typeof options == "object") {
|
|
202
|
-
let filename = val.name;
|
|
203
|
-
if (options?.sanitized) {
|
|
204
|
-
filename = `${Date.now()}-${sanitized(filename)}`;
|
|
205
|
-
}
|
|
206
|
-
if (Array.isArray(options?.allowedTypes) &&
|
|
207
|
-
!options.allowedTypes?.includes(val.type)) {
|
|
208
|
-
throw new Error(`Invalid file type: "${val.type}". Allowed types: ${options.allowedTypes.join(", ")}`);
|
|
209
|
-
}
|
|
210
|
-
if (typeof options?.maxSize !== "undefined" &&
|
|
211
|
-
val.size > options.maxSize) {
|
|
212
|
-
throw new Error(`File size exceeds the limit: ${val.size} bytes (Max: ${options.maxSize} bytes)`);
|
|
213
|
-
}
|
|
214
|
-
if (typeof options?.maxFiles != "undefined" && options.maxFiles == 0) {
|
|
215
|
-
throw new Error(`Field "${key}" exceeds the maximum allowed file count of ${options.maxFiles}.`);
|
|
216
|
-
}
|
|
217
|
-
val = new File([await val.arrayBuffer()], filename, {
|
|
218
|
-
type: val.type,
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
if (result[key]) {
|
|
222
|
-
if (Array.isArray(result[key])) {
|
|
223
|
-
if (val instanceof File &&
|
|
224
|
-
typeof options?.maxFiles != "undefined" &&
|
|
225
|
-
result[key]?.length >= options.maxFiles) {
|
|
226
|
-
throw new Error(`Field "${key}" exceeds the maximum allowed file count of ${options.maxFiles}.`);
|
|
227
|
-
}
|
|
228
|
-
result[key].push(val);
|
|
229
|
-
}
|
|
230
|
-
else {
|
|
231
|
-
if (val instanceof File &&
|
|
232
|
-
typeof options?.maxFiles != "undefined" &&
|
|
233
|
-
options.maxFiles == 1) {
|
|
234
|
-
throw new Error(`Field "${key}" exceeds the maximum allowed file count of ${options.maxFiles}.`);
|
|
235
|
-
}
|
|
236
|
-
result[key] = [result[key], val];
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
else {
|
|
240
|
-
result[key] = val;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
return result;
|
|
244
|
-
}
|
|
245
|
-
else {
|
|
246
|
-
throw new Error("Unsupported environment for multipart parsing");
|
|
247
|
-
}
|
|
248
|
-
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.httpStatusMap = void 0;
|
|
4
|
+
exports.httpStatusMap = {
|
|
5
|
+
100: "Continue",
|
|
6
|
+
101: "Switching Protocols",
|
|
7
|
+
102: "Processing",
|
|
8
|
+
103: "Early Hints",
|
|
9
|
+
200: "OK",
|
|
10
|
+
201: "Created",
|
|
11
|
+
202: "Accepted",
|
|
12
|
+
203: "Non-Authoritative Information",
|
|
13
|
+
204: "No Content",
|
|
14
|
+
205: "Reset Content",
|
|
15
|
+
206: "Partial Content",
|
|
16
|
+
207: "Multi-Status",
|
|
17
|
+
208: "Already Reported",
|
|
18
|
+
226: "IM Used",
|
|
19
|
+
300: "Multiple Choices",
|
|
20
|
+
301: "Moved Permanently",
|
|
21
|
+
302: "Found",
|
|
22
|
+
303: "See Other",
|
|
23
|
+
304: "Not Modified",
|
|
24
|
+
305: "Use Proxy",
|
|
25
|
+
306: "Switch Proxy",
|
|
26
|
+
307: "Temporary Redirect",
|
|
27
|
+
308: "Permanent Redirect",
|
|
28
|
+
400: "Bad Request",
|
|
29
|
+
401: "Unauthorized",
|
|
30
|
+
402: "Payment Required",
|
|
31
|
+
403: "Forbidden",
|
|
32
|
+
404: "Not Found",
|
|
33
|
+
405: "Method Not Allowed",
|
|
34
|
+
406: "Not Acceptable",
|
|
35
|
+
407: "Proxy Authentication Required",
|
|
36
|
+
408: "Request Timeout",
|
|
37
|
+
409: "Conflict",
|
|
38
|
+
410: "Gone",
|
|
39
|
+
411: "Length Required",
|
|
40
|
+
412: "Precondition Failed",
|
|
41
|
+
413: "Payload Too Large",
|
|
42
|
+
414: "URI Too Long",
|
|
43
|
+
415: "Unsupported Media Type",
|
|
44
|
+
416: "Range Not Satisfiable",
|
|
45
|
+
417: "Expectation Failed",
|
|
46
|
+
418: "I'm a Teapot",
|
|
47
|
+
421: "Misdirected Request",
|
|
48
|
+
422: "Unprocessable Entity",
|
|
49
|
+
423: "Locked",
|
|
50
|
+
424: "Failed Dependency",
|
|
51
|
+
425: "Too Early",
|
|
52
|
+
426: "Upgrade Required",
|
|
53
|
+
428: "Precondition Required",
|
|
54
|
+
429: "Too Many Requests",
|
|
55
|
+
431: "Request Header Fields Too Large",
|
|
56
|
+
451: "Unavailable For Legal Reasons",
|
|
57
|
+
500: "Internal Server Error",
|
|
58
|
+
501: "Not Implemented",
|
|
59
|
+
502: "Bad Gateway",
|
|
60
|
+
503: "Service Unavailable",
|
|
61
|
+
504: "Gateway Timeout",
|
|
62
|
+
505: "HTTP Version Not Supported",
|
|
63
|
+
506: "Variant Also Negotiates",
|
|
64
|
+
507: "Insufficient Storage",
|
|
65
|
+
508: "Loop Detected",
|
|
66
|
+
510: "Not Extended",
|
|
67
|
+
511: "Network Authentication Required",
|
|
68
|
+
};
|
package/cjs/utils/staticFile.js
CHANGED
|
@@ -149,7 +149,10 @@ async function getFiles(dir, basePath = "/", ref, option) {
|
|
|
149
149
|
ctx.headers.set("Cache-Control", option.cacheControl);
|
|
150
150
|
}
|
|
151
151
|
if (option.headers) {
|
|
152
|
-
|
|
152
|
+
for (const key in option.headers) {
|
|
153
|
+
let value = option.headers?.[key];
|
|
154
|
+
ctx.headers.set(key, value);
|
|
155
|
+
}
|
|
153
156
|
}
|
|
154
157
|
return ctx.sendFile(r.file);
|
|
155
158
|
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toWebRequest = toWebRequest;
|
|
4
|
+
const node_stream_1 = require("node:stream");
|
|
5
|
+
function toWebRequest(req, method = "GET") {
|
|
6
|
+
const headers = {};
|
|
7
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
8
|
+
if (Array.isArray(value)) {
|
|
9
|
+
headers[key] = value.join(", ");
|
|
10
|
+
}
|
|
11
|
+
else if (typeof value === "string") {
|
|
12
|
+
headers[key] = value;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const isEncrypted = (req.socket && req.socket.encrypted) || false;
|
|
16
|
+
const protocol = isEncrypted ? "https:" : "http:";
|
|
17
|
+
let host = "localhost";
|
|
18
|
+
const hostHeader = req.headers.host;
|
|
19
|
+
if (typeof hostHeader === "string") {
|
|
20
|
+
host = hostHeader;
|
|
21
|
+
}
|
|
22
|
+
const urlStr = req.url ?? "/";
|
|
23
|
+
const fullUrl = new URL(urlStr, `${protocol}//${host}`);
|
|
24
|
+
const hasBody = !["GET", "HEAD"].includes(method.toUpperCase());
|
|
25
|
+
const body = hasBody ? node_stream_1.Readable.toWeb(req) : undefined;
|
|
26
|
+
const abortController = new AbortController();
|
|
27
|
+
req?.once("close", () => abortController.abort());
|
|
28
|
+
return new Request(fullUrl.href, {
|
|
29
|
+
method,
|
|
30
|
+
headers,
|
|
31
|
+
body,
|
|
32
|
+
signal: abortController.signal,
|
|
33
|
+
duplex: hasBody ? "half" : undefined,
|
|
34
|
+
});
|
|
35
|
+
}
|
package/core/context.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { State } from "../utils/state.js";
|
|
2
|
-
import {
|
|
3
|
-
import { HTTPMethod, Request } from "./request.js";
|
|
2
|
+
import { HTTPMethod, Request as RequestParser } from "./request.js";
|
|
4
3
|
import { TezXServeOptions } from "./server.js";
|
|
5
4
|
export interface CookieOptions {
|
|
6
5
|
expires?: Date;
|
|
@@ -11,11 +10,11 @@ export interface CookieOptions {
|
|
|
11
10
|
httpOnly?: boolean;
|
|
12
11
|
sameSite?: "Strict" | "Lax" | "None";
|
|
13
12
|
}
|
|
14
|
-
export declare const httpStatusMap: Record<number, string>;
|
|
15
13
|
export type ResponseHeaders = Record<string, string>;
|
|
16
14
|
export declare class Context<T extends Record<string, any> = {}> {
|
|
17
15
|
#private;
|
|
18
16
|
[key: string]: any;
|
|
17
|
+
rawRequest: Request;
|
|
19
18
|
/**
|
|
20
19
|
* Environment variables and configuration
|
|
21
20
|
* @type {object}
|
|
@@ -23,9 +22,9 @@ export declare class Context<T extends Record<string, any> = {}> {
|
|
|
23
22
|
env: Record<string, any> & T;
|
|
24
23
|
/**
|
|
25
24
|
* Parser for handling and manipulating HTTP headers
|
|
26
|
-
* @type {
|
|
25
|
+
* @type {Headers}
|
|
27
26
|
*/
|
|
28
|
-
headers:
|
|
27
|
+
headers: Headers;
|
|
29
28
|
/**
|
|
30
29
|
* Request path without query parameters
|
|
31
30
|
* @type {string}
|
|
@@ -193,7 +192,7 @@ export declare class Context<T extends Record<string, any> = {}> {
|
|
|
193
192
|
* // Access route params
|
|
194
193
|
* const id = request.params.get('id');
|
|
195
194
|
*/
|
|
196
|
-
get req():
|
|
195
|
+
get req(): RequestParser;
|
|
197
196
|
protected set params(params: Record<string, any>);
|
|
198
197
|
/**
|
|
199
198
|
* Set response body to be passed between middlewares or returned as final output.
|
package/core/context.js
CHANGED
|
@@ -1,79 +1,13 @@
|
|
|
1
1
|
import { State } from "../utils/state.js";
|
|
2
2
|
import { defaultMimeType, mimeTypes } from "../utils/staticFile.js";
|
|
3
|
-
import {
|
|
3
|
+
import { toWebRequest } from "../utils/toWebRequest.js";
|
|
4
4
|
import { GlobalConfig } from "./config.js";
|
|
5
5
|
import { EnvironmentDetector } from "./environment.js";
|
|
6
|
-
import {
|
|
7
|
-
import { Request } from "./request.js";
|
|
8
|
-
export const httpStatusMap = {
|
|
9
|
-
100: "Continue",
|
|
10
|
-
101: "Switching Protocols",
|
|
11
|
-
102: "Processing",
|
|
12
|
-
103: "Early Hints",
|
|
13
|
-
200: "OK",
|
|
14
|
-
201: "Created",
|
|
15
|
-
202: "Accepted",
|
|
16
|
-
203: "Non-Authoritative Information",
|
|
17
|
-
204: "No Content",
|
|
18
|
-
205: "Reset Content",
|
|
19
|
-
206: "Partial Content",
|
|
20
|
-
207: "Multi-Status",
|
|
21
|
-
208: "Already Reported",
|
|
22
|
-
226: "IM Used",
|
|
23
|
-
300: "Multiple Choices",
|
|
24
|
-
301: "Moved Permanently",
|
|
25
|
-
302: "Found",
|
|
26
|
-
303: "See Other",
|
|
27
|
-
304: "Not Modified",
|
|
28
|
-
305: "Use Proxy",
|
|
29
|
-
306: "Switch Proxy",
|
|
30
|
-
307: "Temporary Redirect",
|
|
31
|
-
308: "Permanent Redirect",
|
|
32
|
-
400: "Bad Request",
|
|
33
|
-
401: "Unauthorized",
|
|
34
|
-
402: "Payment Required",
|
|
35
|
-
403: "Forbidden",
|
|
36
|
-
404: "Not Found",
|
|
37
|
-
405: "Method Not Allowed",
|
|
38
|
-
406: "Not Acceptable",
|
|
39
|
-
407: "Proxy Authentication Required",
|
|
40
|
-
408: "Request Timeout",
|
|
41
|
-
409: "Conflict",
|
|
42
|
-
410: "Gone",
|
|
43
|
-
411: "Length Required",
|
|
44
|
-
412: "Precondition Failed",
|
|
45
|
-
413: "Payload Too Large",
|
|
46
|
-
414: "URI Too Long",
|
|
47
|
-
415: "Unsupported Media Type",
|
|
48
|
-
416: "Range Not Satisfiable",
|
|
49
|
-
417: "Expectation Failed",
|
|
50
|
-
418: "I'm a Teapot",
|
|
51
|
-
421: "Misdirected Request",
|
|
52
|
-
422: "Unprocessable Entity",
|
|
53
|
-
423: "Locked",
|
|
54
|
-
424: "Failed Dependency",
|
|
55
|
-
425: "Too Early",
|
|
56
|
-
426: "Upgrade Required",
|
|
57
|
-
428: "Precondition Required",
|
|
58
|
-
429: "Too Many Requests",
|
|
59
|
-
431: "Request Header Fields Too Large",
|
|
60
|
-
451: "Unavailable For Legal Reasons",
|
|
61
|
-
500: "Internal Server Error",
|
|
62
|
-
501: "Not Implemented",
|
|
63
|
-
502: "Bad Gateway",
|
|
64
|
-
503: "Service Unavailable",
|
|
65
|
-
504: "Gateway Timeout",
|
|
66
|
-
505: "HTTP Version Not Supported",
|
|
67
|
-
506: "Variant Also Negotiates",
|
|
68
|
-
507: "Insufficient Storage",
|
|
69
|
-
508: "Loop Detected",
|
|
70
|
-
510: "Not Extended",
|
|
71
|
-
511: "Network Authentication Required",
|
|
72
|
-
};
|
|
6
|
+
import { Request as RequestParser } from "./request.js";
|
|
73
7
|
export class Context {
|
|
74
|
-
|
|
8
|
+
rawRequest;
|
|
75
9
|
env = {};
|
|
76
|
-
headers = new
|
|
10
|
+
headers = new Headers();
|
|
77
11
|
pathname;
|
|
78
12
|
url;
|
|
79
13
|
method;
|
|
@@ -82,30 +16,20 @@ export class Context {
|
|
|
82
16
|
#params = {};
|
|
83
17
|
resBody;
|
|
84
18
|
#body;
|
|
85
|
-
#urlRef;
|
|
86
|
-
#requestHeaders;
|
|
87
19
|
#options;
|
|
88
20
|
constructor(req, options) {
|
|
89
21
|
this.#options = options;
|
|
90
|
-
this.#rawRequest = req;
|
|
91
22
|
this.method = req?.method?.toUpperCase();
|
|
92
|
-
this.#requestHeaders = new HeadersParser(req?.headers);
|
|
93
23
|
if (GlobalConfig.adapter == "node") {
|
|
94
|
-
let
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
? "https"
|
|
98
|
-
: "http"
|
|
99
|
-
: "http";
|
|
100
|
-
const host = EnvironmentDetector.getHost(this.#requestHeaders);
|
|
101
|
-
const path = req.url || "/";
|
|
102
|
-
this.url = `${protocol}://${host}${path}`;
|
|
24
|
+
let request = toWebRequest(req, this.method);
|
|
25
|
+
this.url = request.url;
|
|
26
|
+
this.rawRequest = request;
|
|
103
27
|
}
|
|
104
28
|
else {
|
|
105
29
|
this.url = req.url;
|
|
30
|
+
this.rawRequest = req;
|
|
106
31
|
}
|
|
107
|
-
this
|
|
108
|
-
this.pathname = this.#urlRef.pathname;
|
|
32
|
+
this.pathname = this.req.urlRef.pathname;
|
|
109
33
|
}
|
|
110
34
|
header(key, value, options) {
|
|
111
35
|
let append = options?.append;
|
|
@@ -118,16 +42,9 @@ export class Context {
|
|
|
118
42
|
return this;
|
|
119
43
|
}
|
|
120
44
|
get cookies() {
|
|
121
|
-
const c = this
|
|
45
|
+
const c = this.req.headers.get("cookie");
|
|
122
46
|
let cookies = {};
|
|
123
|
-
if (
|
|
124
|
-
const cookieHeader = c.join("; ").split(";");
|
|
125
|
-
for (const pair of cookieHeader) {
|
|
126
|
-
const [key, value] = pair?.trim()?.split("=");
|
|
127
|
-
cookies[key] = decodeURIComponent(value);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
else if (typeof c == "string") {
|
|
47
|
+
if (typeof c == "string") {
|
|
131
48
|
const cookieHeader = c.split(";");
|
|
132
49
|
for (const pair of cookieHeader) {
|
|
133
50
|
const [key, value] = pair?.trim()?.split("=");
|
|
@@ -418,10 +335,9 @@ export class Context {
|
|
|
418
335
|
return response;
|
|
419
336
|
}
|
|
420
337
|
get req() {
|
|
421
|
-
return new
|
|
422
|
-
|
|
423
|
-
req: this
|
|
424
|
-
urlRef: this.#urlRef,
|
|
338
|
+
return new RequestParser({
|
|
339
|
+
method: this.method,
|
|
340
|
+
req: this.rawRequest,
|
|
425
341
|
options: this.#options,
|
|
426
342
|
params: this.#params,
|
|
427
343
|
});
|
package/core/environment.d.ts
CHANGED
package/core/environment.js
CHANGED