tezx 2.0.11 → 3.0.0

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 (234) hide show
  1. package/README.md +122 -89
  2. package/bun/getConnInfo.d.ts +21 -0
  3. package/bun/getConnInfo.js +9 -0
  4. package/bun/index.d.ts +10 -4
  5. package/bun/index.js +8 -4
  6. package/bun/ws.d.ts +48 -0
  7. package/bun/ws.js +58 -0
  8. package/cjs/bun/getConnInfo.js +12 -0
  9. package/cjs/bun/index.js +35 -7
  10. package/cjs/bun/ws.js +63 -0
  11. package/cjs/core/config.js +2 -12
  12. package/cjs/core/context.js +131 -379
  13. package/cjs/core/error.js +49 -0
  14. package/cjs/core/request.js +79 -131
  15. package/cjs/core/router.js +54 -387
  16. package/cjs/core/server.js +83 -202
  17. package/cjs/deno/env.js +4 -4
  18. package/cjs/deno/getConnInfo.js +18 -0
  19. package/cjs/deno/index.js +11 -18
  20. package/cjs/deno/serveStatic.js +53 -0
  21. package/cjs/deno/ws.js +39 -0
  22. package/cjs/helper/index.js +46 -10
  23. package/cjs/index.js +5 -7
  24. package/cjs/jwt/node.js +94 -0
  25. package/cjs/jwt/web.js +178 -0
  26. package/cjs/middleware/basic-auth.js +42 -0
  27. package/cjs/middleware/bearer-auth.js +34 -0
  28. package/cjs/middleware/cache-control.js +44 -0
  29. package/cjs/middleware/cors.js +11 -21
  30. package/cjs/middleware/detect-bot.js +57 -0
  31. package/cjs/middleware/i18n.js +73 -60
  32. package/cjs/middleware/index.js +8 -46
  33. package/cjs/middleware/logger.js +9 -4
  34. package/cjs/middleware/pagination.js +3 -2
  35. package/cjs/middleware/powered-by.js +3 -2
  36. package/cjs/middleware/rate-limiter.js +38 -0
  37. package/cjs/middleware/request-id.js +4 -5
  38. package/cjs/middleware/sanitize-headers.js +22 -0
  39. package/cjs/middleware/secure-headers copy.js +143 -0
  40. package/cjs/middleware/secure-headers.js +157 -0
  41. package/cjs/middleware/{xssProtection.js → xss-protection.js} +5 -8
  42. package/cjs/node/env.js +7 -7
  43. package/cjs/node/getConnInfo.js +16 -0
  44. package/cjs/node/index.js +17 -18
  45. package/cjs/node/mount-node.js +59 -0
  46. package/cjs/node/serveStatic.js +56 -0
  47. package/cjs/node/toWebRequest.js +25 -0
  48. package/cjs/node/ws.js +82 -0
  49. package/cjs/registry/RadixRouter.js +148 -0
  50. package/cjs/registry/index.js +17 -0
  51. package/cjs/types/headers.js +2 -0
  52. package/cjs/types/index.js +13 -0
  53. package/cjs/utils/buffer.js +17 -0
  54. package/cjs/utils/colors.js +2 -0
  55. package/cjs/utils/cookie.js +59 -0
  56. package/cjs/utils/file.js +136 -0
  57. package/cjs/utils/formData.js +60 -10
  58. package/cjs/utils/generateID.js +37 -0
  59. package/cjs/utils/low-level.js +115 -0
  60. package/cjs/utils/{staticFile.js → mimeTypes.js} +0 -87
  61. package/cjs/utils/rateLimit.js +41 -0
  62. package/cjs/utils/response.js +65 -0
  63. package/cjs/{core/environment.js → utils/runtime.js} +2 -1
  64. package/cjs/utils/url.js +65 -30
  65. package/core/config.d.ts +2 -7
  66. package/core/config.js +2 -12
  67. package/core/context.d.ts +209 -164
  68. package/core/context.js +131 -346
  69. package/core/error.d.ts +96 -0
  70. package/core/error.js +44 -0
  71. package/core/request.d.ts +67 -107
  72. package/core/request.js +78 -130
  73. package/core/router.d.ts +138 -133
  74. package/core/router.js +53 -352
  75. package/core/server.d.ts +99 -38
  76. package/core/server.js +83 -202
  77. package/deno/env.js +3 -3
  78. package/deno/getConnInfo.d.ts +21 -0
  79. package/deno/getConnInfo.js +15 -0
  80. package/deno/index.d.ts +9 -4
  81. package/deno/index.js +7 -4
  82. package/deno/serveStatic.d.ts +28 -0
  83. package/deno/serveStatic.js +49 -0
  84. package/deno/ws.d.ts +42 -0
  85. package/deno/ws.js +36 -0
  86. package/helper/index.d.ts +29 -15
  87. package/helper/index.js +27 -7
  88. package/index.d.ts +10 -8
  89. package/index.js +4 -5
  90. package/jwt/node.d.ts +39 -0
  91. package/jwt/node.js +87 -0
  92. package/jwt/web.d.ts +14 -0
  93. package/jwt/web.js +174 -0
  94. package/middleware/basic-auth.d.ts +56 -0
  95. package/middleware/basic-auth.js +38 -0
  96. package/middleware/bearer-auth.d.ts +53 -0
  97. package/middleware/bearer-auth.js +30 -0
  98. package/middleware/cache-control.d.ts +30 -0
  99. package/middleware/cache-control.js +40 -0
  100. package/middleware/cors.d.ts +30 -3
  101. package/middleware/cors.js +12 -22
  102. package/middleware/detect-bot.d.ts +113 -0
  103. package/middleware/detect-bot.js +53 -0
  104. package/middleware/i18n.d.ts +166 -73
  105. package/middleware/i18n.js +73 -60
  106. package/middleware/index.d.ts +8 -32
  107. package/middleware/index.js +8 -44
  108. package/middleware/logger.d.ts +5 -2
  109. package/middleware/logger.js +9 -4
  110. package/middleware/pagination.d.ts +9 -6
  111. package/middleware/pagination.js +3 -2
  112. package/middleware/powered-by.d.ts +2 -1
  113. package/middleware/powered-by.js +3 -2
  114. package/middleware/{rateLimiter.d.ts → rate-limiter.d.ts} +15 -9
  115. package/middleware/rate-limiter.js +34 -0
  116. package/middleware/request-id.d.ts +2 -1
  117. package/middleware/request-id.js +5 -6
  118. package/middleware/{sanitizeHeader.d.ts → sanitize-headers.d.ts} +5 -19
  119. package/middleware/sanitize-headers.js +18 -0
  120. package/middleware/secure-headers copy.d.ts +15 -0
  121. package/middleware/secure-headers copy.js +136 -0
  122. package/middleware/secure-headers.d.ts +132 -0
  123. package/middleware/secure-headers.js +153 -0
  124. package/middleware/{xssProtection.d.ts → xss-protection.d.ts} +2 -1
  125. package/middleware/xss-protection.js +19 -0
  126. package/node/env.js +4 -4
  127. package/node/getConnInfo.d.ts +21 -0
  128. package/node/getConnInfo.js +13 -0
  129. package/node/index.d.ts +13 -4
  130. package/node/index.js +11 -4
  131. package/node/mount-node.d.ts +11 -0
  132. package/node/mount-node.js +56 -0
  133. package/node/serveStatic.d.ts +36 -0
  134. package/node/serveStatic.js +52 -0
  135. package/node/toWebRequest.js +22 -0
  136. package/node/ws.d.ts +56 -0
  137. package/node/ws.js +46 -0
  138. package/package.json +39 -30
  139. package/registry/RadixRouter.d.ts +40 -0
  140. package/registry/RadixRouter.js +144 -0
  141. package/registry/index.d.ts +2 -0
  142. package/registry/index.js +1 -0
  143. package/types/headers.d.ts +2 -0
  144. package/types/headers.js +1 -0
  145. package/types/index.d.ts +318 -18
  146. package/types/index.js +12 -1
  147. package/utils/buffer.d.ts +1 -0
  148. package/utils/buffer.js +14 -0
  149. package/utils/colors.d.ts +24 -0
  150. package/utils/colors.js +2 -0
  151. package/utils/cookie.d.ts +55 -0
  152. package/utils/cookie.js +53 -0
  153. package/utils/file.d.ts +38 -0
  154. package/utils/file.js +96 -0
  155. package/utils/formData.d.ts +41 -1
  156. package/utils/formData.js +58 -9
  157. package/utils/generateID.d.ts +42 -0
  158. package/utils/generateID.js +32 -0
  159. package/utils/httpStatusMap.d.ts +14 -0
  160. package/utils/low-level.d.ts +58 -0
  161. package/utils/low-level.js +108 -0
  162. package/utils/mimeTypes.d.ts +4 -0
  163. package/utils/{staticFile.js → mimeTypes.js} +0 -53
  164. package/utils/rateLimit.d.ts +18 -0
  165. package/utils/rateLimit.js +37 -0
  166. package/utils/response.d.ts +18 -0
  167. package/utils/response.js +58 -0
  168. package/{core/environment.d.ts → utils/runtime.d.ts} +1 -0
  169. package/{core/environment.js → utils/runtime.js} +1 -0
  170. package/utils/url.d.ts +42 -14
  171. package/utils/url.js +61 -27
  172. package/bun/adapter.d.ts +0 -127
  173. package/bun/adapter.js +0 -97
  174. package/cjs/bun/adapter.js +0 -100
  175. package/cjs/core/MiddlewareConfigure.js +0 -68
  176. package/cjs/core/common.js +0 -15
  177. package/cjs/deno/adpater.js +0 -67
  178. package/cjs/helper/common.js +0 -17
  179. package/cjs/middleware/basicAuth.js +0 -71
  180. package/cjs/middleware/cacheControl.js +0 -90
  181. package/cjs/middleware/detectBot.js +0 -104
  182. package/cjs/middleware/detectLocale.js +0 -43
  183. package/cjs/middleware/lazyLoadModules.js +0 -73
  184. package/cjs/middleware/rateLimiter.js +0 -24
  185. package/cjs/middleware/requestTimeout.js +0 -42
  186. package/cjs/middleware/sanitizeHeader.js +0 -51
  187. package/cjs/middleware/secureHeaders.js +0 -42
  188. package/cjs/node/adapter.js +0 -138
  189. package/cjs/utils/regexRouter.js +0 -58
  190. package/cjs/utils/state.js +0 -34
  191. package/cjs/utils/toWebRequest.js +0 -35
  192. package/cjs/ws/deno.js +0 -20
  193. package/cjs/ws/index.js +0 -53
  194. package/cjs/ws/node.js +0 -65
  195. package/core/MiddlewareConfigure.d.ts +0 -15
  196. package/core/MiddlewareConfigure.js +0 -63
  197. package/core/common.d.ts +0 -21
  198. package/core/common.js +0 -11
  199. package/deno/adpater.d.ts +0 -38
  200. package/deno/adpater.js +0 -64
  201. package/helper/common.d.ts +0 -5
  202. package/helper/common.js +0 -14
  203. package/middleware/basicAuth.d.ts +0 -81
  204. package/middleware/basicAuth.js +0 -67
  205. package/middleware/cacheControl.d.ts +0 -48
  206. package/middleware/cacheControl.js +0 -53
  207. package/middleware/detectBot.d.ts +0 -121
  208. package/middleware/detectBot.js +0 -98
  209. package/middleware/detectLocale.d.ts +0 -55
  210. package/middleware/detectLocale.js +0 -39
  211. package/middleware/lazyLoadModules.d.ts +0 -72
  212. package/middleware/lazyLoadModules.js +0 -69
  213. package/middleware/rateLimiter.js +0 -20
  214. package/middleware/requestTimeout.d.ts +0 -25
  215. package/middleware/requestTimeout.js +0 -38
  216. package/middleware/sanitizeHeader.js +0 -47
  217. package/middleware/secureHeaders.d.ts +0 -78
  218. package/middleware/secureHeaders.js +0 -38
  219. package/middleware/xssProtection.js +0 -22
  220. package/node/adapter.d.ts +0 -46
  221. package/node/adapter.js +0 -102
  222. package/utils/regexRouter.d.ts +0 -66
  223. package/utils/regexRouter.js +0 -53
  224. package/utils/state.d.ts +0 -50
  225. package/utils/state.js +0 -30
  226. package/utils/staticFile.d.ts +0 -10
  227. package/utils/toWebRequest.js +0 -32
  228. package/ws/deno.d.ts +0 -6
  229. package/ws/deno.js +0 -16
  230. package/ws/index.d.ts +0 -180
  231. package/ws/index.js +0 -50
  232. package/ws/node.d.ts +0 -7
  233. package/ws/node.js +0 -28
  234. /package/{utils → node}/toWebRequest.d.ts +0 -0
package/core/context.js CHANGED
@@ -1,388 +1,173 @@
1
- import { State } from "../utils/state.js";
2
- import { defaultMimeType, mimeTypes } from "../utils/staticFile.js";
3
- import { toWebRequest } from "../utils/toWebRequest.js";
4
- import { GlobalConfig } from "./config.js";
5
- import { Environment } from "./environment.js";
6
- import { Request as RequestParser } from "./request.js";
1
+ import { fileExists, fileSize, getFileBuffer, readStream, } from "../utils/file.js";
2
+ import { extensionExtract } from "../utils/low-level.js";
3
+ import { defaultMimeType, mimeTypes } from "../utils/mimeTypes.js";
4
+ import { determineContentTypeBody, toString } from "../utils/response.js";
5
+ import { TezXError } from "./error.js";
6
+ import { TezXRequest } from "./request.js";
7
7
  export class Context {
8
+ #status = 200;
9
+ #headers;
10
+ #req = null;
11
+ #params = {};
8
12
  rawRequest;
13
+ #args;
14
+ #body;
15
+ url;
16
+ res;
9
17
  env = {};
10
- headers = new Headers();
11
18
  pathname;
12
- url;
13
19
  method;
14
- #status = 200;
15
- state = new State();
16
- #params = {};
17
- resBody;
18
- #body;
19
- #options;
20
- constructor(req, options) {
21
- this.#options = options;
22
- this.method = req?.method?.toUpperCase();
23
- if (GlobalConfig.adapter == "node") {
24
- let request = toWebRequest(req, this.method);
25
- this.url = request.url;
26
- this.rawRequest = request;
27
- }
28
- else {
29
- this.url = req.url;
30
- this.rawRequest = req;
31
- }
32
- this.pathname = this.req.urlRef.pathname;
20
+ constructor(req, pathname, method, env, args) {
21
+ this.#args = args;
22
+ this.rawRequest = req;
23
+ this.url = req.url;
24
+ this.pathname = pathname;
25
+ this.env = env ?? {};
26
+ this.method = method;
27
+ }
28
+ get getStatus() {
29
+ return this.#status;
30
+ }
31
+ set setStatus(code) {
32
+ this.#status = code;
33
33
  }
34
- header(key, value, options) {
35
- let append = options?.append;
34
+ get headers() {
35
+ return this.res?.headers ?? (this.#headers ??= new Headers());
36
+ }
37
+ setHeader(key, value, options) {
38
+ if (!value)
39
+ return this;
40
+ const _key = key.toLowerCase();
41
+ const append = options?.append || _key === "set-cookie";
42
+ const target = this.res?.headers ?? (this.#headers ??= new Headers());
36
43
  if (append) {
37
- this.headers.append(key, value);
44
+ target.append(_key, value);
38
45
  }
39
46
  else {
40
- this.headers.set(key, value);
47
+ target.set(_key, value);
41
48
  }
42
49
  return this;
43
50
  }
44
- get cookies() {
45
- const c = this.req.headers.get("cookie");
46
- let cookies = {};
47
- if (typeof c == "string") {
48
- const cookieHeader = c.split(";");
49
- for (const pair of cookieHeader) {
50
- const [key, value] = pair?.trim()?.split("=");
51
- cookies[key] = decodeURIComponent(value);
52
- }
53
- }
54
- return {
55
- get: (cookie) => {
56
- return cookies?.[cookie];
57
- },
58
- all: () => {
59
- return cookies;
60
- },
61
- delete: (name, options) => {
62
- const value = "";
63
- const cookieOptions = {
64
- ...options,
65
- expires: new Date(0),
66
- };
67
- const cookieHeader = `${name}=${value};${serializeOptions(cookieOptions)}`;
68
- this.headers.set("Set-Cookie", cookieHeader);
69
- },
70
- set: (name, value, options) => {
71
- const cookieHeader = `${name}=${value};${serializeOptions(options || {})}`;
72
- this.headers.set("Set-Cookie", cookieHeader);
73
- },
74
- };
75
- }
76
- json(body, ...args) {
77
- let status = this.#status;
78
- let headers = {
79
- "Content-Type": "application/json; charset=utf-8",
80
- };
81
- if (typeof args[0] === "number") {
82
- status = args[0];
83
- if (typeof args[1] === "object") {
84
- headers = { ...headers, ...args[1] };
85
- }
86
- }
87
- else if (typeof args[0] === "object") {
88
- headers = { ...headers, ...args[0] };
89
- }
90
- return this.#handleResponse(JSON.stringify(body), {
91
- status: status,
92
- headers: headers,
93
- });
94
- }
95
- send(body, ...args) {
96
- let status = this.#status;
97
- let headers = {};
98
- if (typeof args[0] === "number") {
99
- status = args[0];
100
- if (typeof args[1] === "object") {
101
- headers = args[1];
102
- }
103
- }
104
- else if (typeof args[0] === "object") {
105
- headers = args[0];
106
- }
107
- const contentTypeHeader = headers["Content-Type"] || headers["content-type"] || "";
108
- if (!contentTypeHeader) {
109
- if (typeof body === "string") {
110
- headers["Content-Type"] = "text/plain; charset=utf-8";
111
- }
112
- else if (typeof body === "number" || typeof body === "boolean") {
113
- headers["Content-Type"] = "text/plain; charset=utf-8";
114
- }
115
- else if (typeof body === "object" &&
116
- body !== null &&
117
- !(body instanceof ReadableStream)) {
118
- headers["Content-Type"] = "application/json; charset=utf-8";
119
- body = JSON.stringify(body);
120
- }
121
- else {
122
- headers["Content-Type"] = "application/octet-stream";
123
- }
124
- }
125
- return this.#handleResponse(body, {
126
- status: status,
127
- headers,
128
- });
51
+ set params(params) {
52
+ this.#params = params;
129
53
  }
130
- html(strings, ...args) {
131
- let status = this.#status;
132
- let data = strings;
133
- if (Array.isArray(strings)) {
134
- data = strings.reduce((result, str, i) => {
135
- const value = args?.[i] ?? "";
136
- return result + str + value;
137
- }, "");
138
- }
139
- let headers = {
140
- "Content-Type": "text/html; charset=utf-8",
141
- };
142
- if (typeof args[0] === "number") {
143
- status = args[0];
144
- if (typeof args[1] === "object") {
145
- headers = { ...headers, ...args[1] };
146
- }
147
- }
148
- else if (typeof args[0] === "object") {
149
- headers = { ...headers, ...args[0] };
150
- }
151
- return this.#handleResponse(data, {
152
- status: status,
153
- headers: headers,
154
- });
54
+ get req() {
55
+ return (this.#req ??= new TezXRequest(this.rawRequest, this.method, this.pathname, this.#params));
155
56
  }
156
- text(data, ...args) {
157
- let status = this.#status;
158
- let headers = {
159
- "Content-Type": "text/plain; charset=utf-8",
160
- };
161
- if (typeof args[0] === "number") {
162
- status = args[0];
163
- if (typeof args[1] === "object") {
164
- headers = { ...headers, ...args[1] };
165
- }
166
- }
167
- else if (typeof args[0] === "object") {
168
- headers = { ...headers, ...args[0] };
169
- }
170
- return this.#handleResponse(data, {
171
- status: status,
172
- headers: headers,
173
- });
57
+ get body() {
58
+ return this.#body;
174
59
  }
175
- xml(data, ...args) {
176
- let status = this.#status;
177
- let headers = {
178
- "Content-Type": "application/xml; charset=utf-8",
179
- };
180
- if (typeof args[0] === "number") {
181
- status = args[0];
182
- if (typeof args[1] === "object") {
183
- headers = { ...headers, ...args[1] };
184
- }
185
- }
186
- else if (typeof args[0] === "object") {
187
- headers = { ...headers, ...args[0] };
188
- }
189
- return this.#handleResponse(data, {
190
- status: status,
191
- headers: headers,
192
- });
60
+ set body(value) {
61
+ this.#body = value;
193
62
  }
194
63
  status = (status) => {
195
64
  this.#status = status;
196
65
  return this;
197
66
  };
198
- set setStatus(status) {
199
- this.#status = status;
200
- }
201
- get getStatus() {
202
- return this.#status;
203
- }
204
- redirect(url, status = 302) {
205
- return new Response(null, {
206
- status: status,
207
- headers: { Location: url },
208
- });
209
- }
210
- async download(filePath, fileName) {
211
- try {
212
- let fileExists = false;
213
- const runtime = Environment.getEnvironment;
214
- if (runtime === "node") {
215
- const { existsSync } = await import("node:fs");
216
- fileExists = existsSync(filePath);
217
- }
218
- else if (runtime === "bun") {
219
- fileExists = Bun.file(filePath).exists();
220
- }
221
- else if (runtime === "deno") {
222
- try {
223
- await Deno.stat(filePath);
224
- fileExists = true;
67
+ #newResponse(body, type, init = {}) {
68
+ const headers = new Headers(this.#headers);
69
+ headers.set("Content-Type", type);
70
+ if (init.headers) {
71
+ for (const key in init.headers) {
72
+ const value = init.headers[key];
73
+ if (!value)
74
+ continue;
75
+ if (key.toLowerCase() === "set-cookie") {
76
+ headers.append(key, value);
225
77
  }
226
- catch {
227
- fileExists = false;
78
+ else {
79
+ headers.set(key, value);
228
80
  }
229
81
  }
230
- if (!fileExists) {
231
- throw Error("File not found");
232
- }
233
- let fileBuffer;
234
- if (runtime === "node") {
235
- const { readFileSync } = await import("node:fs");
236
- fileBuffer = await readFileSync(filePath);
237
- }
238
- else if (runtime === "bun") {
239
- fileBuffer = await Bun.file(filePath)
240
- .arrayBuffer()
241
- .then((buf) => new Uint8Array(buf));
242
- }
243
- else if (runtime === "deno") {
244
- fileBuffer = await Deno.readFile(filePath);
245
- }
246
- return this.#handleResponse(fileBuffer, {
247
- status: 200,
248
- headers: {
249
- "Content-Disposition": `attachment; filename="${fileName}"`,
250
- "Content-Type": "application/octet-stream",
251
- "Content-Length": fileBuffer.byteLength.toString(),
252
- },
253
- });
254
- }
255
- catch (error) {
256
- throw Error("Internal Server Error" + error?.message);
257
82
  }
83
+ return new Response(body, {
84
+ status: init.status ?? this.#status,
85
+ statusText: init.statusText,
86
+ headers,
87
+ });
258
88
  }
259
- async sendFile(filePath, ...args) {
260
- try {
261
- const runtime = Environment.getEnvironment;
262
- const resolvedPath = filePath;
263
- let fileExists = false;
264
- if (runtime === "node") {
265
- const { existsSync } = await import("node:fs");
266
- fileExists = existsSync(resolvedPath);
267
- }
268
- else if (runtime === "bun") {
269
- fileExists = Bun.file(resolvedPath).exists();
270
- }
271
- else if (runtime === "deno") {
272
- try {
273
- await Deno.stat(resolvedPath);
274
- fileExists = true;
89
+ newResponse(body, init = {}) {
90
+ const headers = new Headers(this.#headers);
91
+ if (init.headers) {
92
+ for (const key in init.headers) {
93
+ const value = init.headers[key];
94
+ if (!value) {
95
+ continue;
275
96
  }
276
- catch {
277
- fileExists = false;
97
+ if (key.toLowerCase() === "set-cookie") {
98
+ headers.append(key, value);
278
99
  }
279
- }
280
- if (!fileExists) {
281
- throw Error("File not found");
282
- }
283
- let fileSize = 0;
284
- if (runtime === "node") {
285
- const { statSync } = await import("node:fs");
286
- fileSize = statSync(resolvedPath).size;
287
- }
288
- else if (runtime === "bun") {
289
- fileSize = (await Bun.file(resolvedPath).arrayBuffer()).byteLength;
290
- }
291
- else if (runtime === "deno") {
292
- const fileInfo = await Deno.stat(resolvedPath);
293
- fileSize = fileInfo.size;
294
- }
295
- const ext = filePath.split(".").pop()?.toLowerCase() || "";
296
- const mimeType = mimeTypes[ext] || defaultMimeType;
297
- let fileStream;
298
- if (runtime === "node") {
299
- const { createReadStream } = await import("node:fs");
300
- fileStream = createReadStream(resolvedPath);
301
- }
302
- else if (runtime === "bun") {
303
- fileStream = Bun.file(resolvedPath).stream();
304
- }
305
- else if (runtime === "deno") {
306
- const file = await Deno.open(resolvedPath, { read: true });
307
- fileStream = file.readable;
308
- }
309
- let headers = {
310
- "Content-Type": mimeType,
311
- "Content-Length": fileSize.toString(),
312
- };
313
- let fileName = "";
314
- if (typeof args[0] === "string") {
315
- fileName = args[0];
316
- if (typeof args[1] === "object") {
317
- headers = { ...headers, ...args[1] };
100
+ else {
101
+ headers.set(key, value);
318
102
  }
319
103
  }
320
- else if (typeof args[0] === "object") {
321
- headers = { ...headers, ...args[0] };
322
- }
323
- if (fileName) {
324
- headers["Content-Disposition"] = `attachment; filename="${fileName}"`;
325
- }
326
- return this.#handleResponse(fileStream, {
327
- status: 200,
328
- headers,
329
- });
330
- }
331
- catch (error) {
332
- throw Error("Internal Server Error" + error?.message);
333
104
  }
334
- }
335
- #handleResponse(body, { headers, status }) {
336
- let response = new Response(body, {
337
- status: status,
105
+ return new Response(body, {
106
+ status: init.status ?? this.#status,
107
+ statusText: init.statusText,
338
108
  headers,
339
109
  });
340
- this.resBody = body;
341
- return response;
342
- }
343
- get req() {
344
- return new RequestParser({
345
- method: this.method,
346
- req: this.rawRequest,
347
- options: this.#options,
348
- params: this.#params,
349
- });
350
- }
351
- set params(params) {
352
- this.#params = params;
353
- }
354
- set body(body) {
355
- this.#body = body;
356
110
  }
357
- get body() {
358
- return this.#body;
111
+ text(content, init) {
112
+ return this.#newResponse(content, "text/plain; charset=utf-8", init);
359
113
  }
360
- get params() {
361
- return this.#params;
362
- }
363
- }
364
- function serializeOptions(options) {
365
- const parts = [];
366
- if (options.maxAge) {
367
- parts.push(`Max-Age=${options.maxAge}`);
114
+ html(strings, ...args) {
115
+ return this.#newResponse(toString(strings, args), "text/html; charset=utf-8", args?.[0]);
368
116
  }
369
- if (options.expires) {
370
- parts.push(`Expires=${options.expires.toUTCString()}`);
117
+ xml(strings, ...args) {
118
+ return this.#newResponse(toString(strings, args), "text/html; charset=utf-8", args?.[0]);
371
119
  }
372
- if (options.path) {
373
- parts.push(`Path=${options.path}`);
120
+ json(json, init) {
121
+ return this.#newResponse(JSON.stringify(json), "application/json; charset=utf-8", init);
374
122
  }
375
- if (options.domain) {
376
- parts.push(`Domain=${options.domain}`);
123
+ send(body, init) {
124
+ let { body: _body, type } = determineContentTypeBody(body);
125
+ const contentType = init?.headers?.["Content-Type"] ??
126
+ init?.headers?.["content-type"] ??
127
+ type;
128
+ return this.#newResponse(_body, contentType, init);
377
129
  }
378
- if (options.secure) {
379
- parts.push(`Secure`);
130
+ redirect(url, status = 302) {
131
+ const headers = new Headers(this.#headers);
132
+ headers.set("Location", url);
133
+ return new Response(null, { status, headers });
134
+ }
135
+ async download(filePath, filename) {
136
+ if (!(await fileExists(filePath)))
137
+ throw TezXError.notFound("File not found");
138
+ const buf = await getFileBuffer(filePath);
139
+ const headers = {
140
+ "Content-Disposition": `attachment; filename="${filename}"`,
141
+ "Content-Length": buf.byteLength.toString(),
142
+ };
143
+ return this.#newResponse(buf, "application/octet-stream", {
144
+ status: this.#status,
145
+ headers,
146
+ });
380
147
  }
381
- if (options.httpOnly) {
382
- parts.push(`HttpOnly`);
148
+ async sendFile(filePath, init) {
149
+ if (!(await fileExists(filePath)))
150
+ throw TezXError.notFound("File not found");
151
+ let { size, mtime } = await fileSize(filePath);
152
+ const ext = extensionExtract(filePath);
153
+ const mimeType = mimeTypes[ext] ?? defaultMimeType;
154
+ let fileStream = await readStream(filePath);
155
+ let headers = {
156
+ "Content-Type": mimeType,
157
+ "Content-Length": size.toString(),
158
+ ...init?.headers,
159
+ };
160
+ let filename = init?.filename;
161
+ if (filename) {
162
+ headers["Content-Disposition"] = `attachment; filename="${filename}"`;
163
+ }
164
+ return this.newResponse(fileStream, {
165
+ status: init?.status ?? this.#status,
166
+ statusText: init?.statusText,
167
+ headers,
168
+ });
383
169
  }
384
- if (options.sameSite) {
385
- parts.push(`SameSite=${options.sameSite}`);
170
+ get args() {
171
+ return this.#args;
386
172
  }
387
- return parts.join("; ");
388
173
  }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Custom error type used throughout the Tezx application.
3
+ *
4
+ * Extends the built-in `Error` and carries an HTTP status code plus optional
5
+ * structured `details` payload (useful for validation errors, metadata, etc.).
6
+ *
7
+ * @example
8
+ * // Throw a 404
9
+ * throw TezXError.notFound("User not found", { userId });
10
+ *
11
+ * @example
12
+ * // Create and throw a custom status
13
+ * throw new TezXError("Something went wrong", 502);
14
+ *
15
+ * @class TezXError
16
+ * @extends Error
17
+ */
18
+ export declare class TezXError extends Error {
19
+ /**
20
+ * HTTP status code representing the error (defaults to 500).
21
+ */
22
+ statusCode: number;
23
+ /**
24
+ * Optional additional details about the error (validation lists, meta, etc.).
25
+ */
26
+ details?: any;
27
+ /**
28
+ * Create an instance of TezXError.
29
+ *
30
+ * @param {string} message - Human readable error message.
31
+ * @param {number} [statusCode=500] - HTTP status code to associate with this error.
32
+ * @param {*} [details] - Optional additional error payload (e.g. validation errors).
33
+ */
34
+ constructor(message: string, statusCode?: number, details?: any);
35
+ /**
36
+ * Create a 400 Bad Request error.
37
+ *
38
+ * @param {string} [message="Bad Request"]
39
+ * @param {*} [details]
40
+ * @returns {TezXError}
41
+ */
42
+ static badRequest(message?: string, details?: any): TezXError;
43
+ /**
44
+ * Create a 401 Unauthorized error.
45
+ *
46
+ * @param {string} [message="Unauthorized"]
47
+ * @param {*} [details]
48
+ * @returns {TezXError}
49
+ */
50
+ static unauthorized(message?: string, details?: any): TezXError;
51
+ /**
52
+ * Create a 403 Forbidden error.
53
+ *
54
+ * @param {string} [message="Forbidden"]
55
+ * @param {*} [details]
56
+ * @returns {TezXError}
57
+ */
58
+ static forbidden(message?: string, details?: any): TezXError;
59
+ /**
60
+ * Create a 404 Not Found error.
61
+ *
62
+ * @param {string} [message="Resource Not Found"]
63
+ * @param {*} [details]
64
+ * @returns {TezXError}
65
+ */
66
+ static notFound(message?: string, details?: any): TezXError;
67
+ /**
68
+ * Create a 409 Conflict error.
69
+ *
70
+ * @param {string} [message="Conflict"]
71
+ * @param {*} [details]
72
+ * @returns {TezXError}
73
+ */
74
+ static conflict(message?: string, details?: any): TezXError;
75
+ /**
76
+ * Create a 500 Internal Server Error.
77
+ *
78
+ * @param {string} [message="Internal Server Error"]
79
+ * @param {*} [details]
80
+ * @returns {TezXError}
81
+ */
82
+ static internal(message?: string, details?: any): TezXError;
83
+ /**
84
+ * Convert the error into a JSON-serializable object that can be sent
85
+ * in HTTP responses or logged safely.
86
+ *
87
+ * @returns {{ error: boolean, message: string, statusCode: number, details: any }}
88
+ */
89
+ toJSON(): {
90
+ error: boolean;
91
+ message: string;
92
+ statusCode: number;
93
+ details: any;
94
+ };
95
+ }
96
+ export declare function TezXErrorParse(err: unknown, statusCode?: number): TezXError;
package/core/error.js ADDED
@@ -0,0 +1,44 @@
1
+ export class TezXError extends Error {
2
+ statusCode;
3
+ details;
4
+ constructor(message, statusCode = 500, details) {
5
+ super(message);
6
+ this.statusCode = statusCode;
7
+ this.details = details;
8
+ Object.setPrototypeOf(this, new.target.prototype);
9
+ Error.captureStackTrace(this, this.constructor);
10
+ }
11
+ static badRequest(message = "Bad Request", details) {
12
+ return new TezXError(message, 400, details);
13
+ }
14
+ static unauthorized(message = "Unauthorized", details) {
15
+ return new TezXError(message, 401, details);
16
+ }
17
+ static forbidden(message = "Forbidden", details) {
18
+ return new TezXError(message, 403, details);
19
+ }
20
+ static notFound(message = "Resource Not Found", details) {
21
+ return new TezXError(message, 404, details);
22
+ }
23
+ static conflict(message = "Conflict", details) {
24
+ return new TezXError(message, 409, details);
25
+ }
26
+ static internal(message = "Internal Server Error", details) {
27
+ return new TezXError(message, 500, details);
28
+ }
29
+ toJSON() {
30
+ return {
31
+ error: true,
32
+ message: this.message,
33
+ statusCode: this.statusCode,
34
+ details: this.details ?? null,
35
+ };
36
+ }
37
+ }
38
+ export function TezXErrorParse(err, statusCode) {
39
+ if (err instanceof TezXError)
40
+ return err;
41
+ else if (err instanceof Error)
42
+ return new TezXError(err?.message, 500, err?.stack);
43
+ return new TezXError(String(err), statusCode);
44
+ }