@ozanarslan/corpus 0.1.5 → 0.1.9
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/README.md +24 -25
- package/dist/index.cjs +2346 -1047
- package/dist/index.d.ts +633 -269
- package/dist/index.js +2353 -1028
- package/package.json +8 -4
package/dist/index.cjs
CHANGED
|
@@ -60,38 +60,9 @@ var __export = (target, all) => {
|
|
|
60
60
|
set: __exportSetter.bind(all, name)
|
|
61
61
|
});
|
|
62
62
|
};
|
|
63
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
63
64
|
|
|
64
|
-
// src/
|
|
65
|
-
var exports_src = {};
|
|
66
|
-
__export(exports_src, {
|
|
67
|
-
default: () => src_default,
|
|
68
|
-
_router: () => _router,
|
|
69
|
-
_globalPrefix: () => _globalPrefix,
|
|
70
|
-
Status: () => Status,
|
|
71
|
-
StaticRoute: () => StaticRoute,
|
|
72
|
-
Server: () => Server,
|
|
73
|
-
Route: () => Route,
|
|
74
|
-
Response: () => HttpResponse,
|
|
75
|
-
Request: () => HttpRequest,
|
|
76
|
-
Repository: () => RepositoryAbstract,
|
|
77
|
-
Parser: () => Parser,
|
|
78
|
-
Middleware: () => Middleware,
|
|
79
|
-
Method: () => Method,
|
|
80
|
-
MemoiristAdapter: () => MemoiristAdapter,
|
|
81
|
-
Headers: () => HttpHeaders,
|
|
82
|
-
FileWalker: () => FileWalker,
|
|
83
|
-
Error: () => HttpError,
|
|
84
|
-
DefaultStatusTexts: () => DefaultStatusTexts,
|
|
85
|
-
Cookies: () => Cookies,
|
|
86
|
-
Controller: () => ControllerAbstract,
|
|
87
|
-
Context: () => Context,
|
|
88
|
-
Config: () => Config,
|
|
89
|
-
CommonHeaders: () => CommonHeaders,
|
|
90
|
-
C: () => exports_exports
|
|
91
|
-
});
|
|
92
|
-
module.exports = __toCommonJS(exports_src);
|
|
93
|
-
|
|
94
|
-
// src/Store/StoreAbstract.ts
|
|
65
|
+
// src/store/StoreAbstract.ts
|
|
95
66
|
class StoreAbstract {
|
|
96
67
|
set(value) {
|
|
97
68
|
this.value = value;
|
|
@@ -101,52 +72,55 @@ class StoreAbstract {
|
|
|
101
72
|
}
|
|
102
73
|
}
|
|
103
74
|
|
|
104
|
-
// src/
|
|
105
|
-
|
|
106
|
-
|
|
75
|
+
// src/store/GlobalPrefixStore.ts
|
|
76
|
+
var GlobalPrefixStore;
|
|
77
|
+
var init_GlobalPrefixStore = __esm(() => {
|
|
78
|
+
GlobalPrefixStore = class GlobalPrefixStore extends StoreAbstract {
|
|
79
|
+
value = "";
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// src/utils/internalLogger.ts
|
|
84
|
+
function logFatal(...args) {
|
|
85
|
+
console.error(...args);
|
|
86
|
+
process.exit(1);
|
|
107
87
|
}
|
|
88
|
+
var log;
|
|
89
|
+
var init_internalLogger = __esm(() => {
|
|
90
|
+
log = console;
|
|
91
|
+
});
|
|
108
92
|
|
|
109
|
-
// src/
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
93
|
+
// src/store/GlobalRouterStore.ts
|
|
94
|
+
var GlobalRouterStore;
|
|
95
|
+
var init_GlobalRouterStore = __esm(() => {
|
|
96
|
+
init_internalLogger();
|
|
97
|
+
GlobalRouterStore = class GlobalRouterStore extends StoreAbstract {
|
|
98
|
+
value = null;
|
|
99
|
+
get() {
|
|
100
|
+
if (!this.value) {
|
|
101
|
+
logFatal("Router instance is not set. Please instantiate your Server before your routes.");
|
|
102
|
+
}
|
|
103
|
+
return this.value;
|
|
116
104
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
105
|
+
};
|
|
106
|
+
});
|
|
120
107
|
|
|
121
|
-
// src/
|
|
122
|
-
var
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
Route: () => Route,
|
|
128
|
-
Response: () => HttpResponse,
|
|
129
|
-
Request: () => HttpRequest,
|
|
130
|
-
Repository: () => RepositoryAbstract,
|
|
131
|
-
Parser: () => Parser,
|
|
132
|
-
Middleware: () => Middleware,
|
|
133
|
-
Method: () => Method,
|
|
134
|
-
Headers: () => HttpHeaders,
|
|
135
|
-
FileWalker: () => FileWalker,
|
|
136
|
-
Error: () => HttpError,
|
|
137
|
-
DefaultStatusTexts: () => DefaultStatusTexts,
|
|
138
|
-
Cookies: () => Cookies,
|
|
139
|
-
Controller: () => ControllerAbstract,
|
|
140
|
-
Context: () => Context,
|
|
141
|
-
Config: () => Config,
|
|
142
|
-
CommonHeaders: () => CommonHeaders
|
|
108
|
+
// src/store/GlobalCorsStore.ts
|
|
109
|
+
var GlobalCorsStore;
|
|
110
|
+
var init_GlobalCorsStore = __esm(() => {
|
|
111
|
+
GlobalCorsStore = class GlobalCorsStore extends StoreAbstract {
|
|
112
|
+
value = null;
|
|
113
|
+
};
|
|
143
114
|
});
|
|
144
115
|
|
|
145
116
|
// src/Config/enums/RuntimeOptions.ts
|
|
146
|
-
var RuntimeOptions
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
117
|
+
var RuntimeOptions;
|
|
118
|
+
var init_RuntimeOptions = __esm(() => {
|
|
119
|
+
RuntimeOptions = {
|
|
120
|
+
bun: "bun",
|
|
121
|
+
node: "node"
|
|
122
|
+
};
|
|
123
|
+
});
|
|
150
124
|
|
|
151
125
|
// src/utils/strIsDefined.ts
|
|
152
126
|
function strIsDefined(input) {
|
|
@@ -154,8 +128,6 @@ function strIsDefined(input) {
|
|
|
154
128
|
}
|
|
155
129
|
|
|
156
130
|
// src/Config/Config.ts
|
|
157
|
-
var import_path = __toESM(require("path"));
|
|
158
|
-
|
|
159
131
|
class Config {
|
|
160
132
|
static get runtime() {
|
|
161
133
|
if (typeof Bun !== "undefined") {
|
|
@@ -164,7 +136,7 @@ class Config {
|
|
|
164
136
|
if (typeof process !== "undefined" && process?.env) {
|
|
165
137
|
return RuntimeOptions.node;
|
|
166
138
|
}
|
|
167
|
-
|
|
139
|
+
log.warn("\u26A0\uFE0F Runtime isn't Bun or NodeJS. Features may not be available. App might not start.");
|
|
168
140
|
return "unknown";
|
|
169
141
|
}
|
|
170
142
|
static get nodeEnv() {
|
|
@@ -177,7 +149,7 @@ class Config {
|
|
|
177
149
|
case RuntimeOptions.node:
|
|
178
150
|
return process.env;
|
|
179
151
|
default:
|
|
180
|
-
|
|
152
|
+
log.warn("\u26A0\uFE0F process.env wasn't available. Your environment variables are in memory.");
|
|
181
153
|
return {};
|
|
182
154
|
}
|
|
183
155
|
}
|
|
@@ -195,7 +167,7 @@ class Config {
|
|
|
195
167
|
if (opts?.fallback !== undefined) {
|
|
196
168
|
return opts?.fallback;
|
|
197
169
|
}
|
|
198
|
-
|
|
170
|
+
log.warn(`${key} doesn't exist in env`);
|
|
199
171
|
return;
|
|
200
172
|
}
|
|
201
173
|
static set(key, value) {
|
|
@@ -210,120 +182,140 @@ class Config {
|
|
|
210
182
|
this.env[key] = value;
|
|
211
183
|
}
|
|
212
184
|
}
|
|
213
|
-
|
|
214
|
-
var
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
OK: 200,
|
|
220
|
-
CREATED: 201,
|
|
221
|
-
ACCEPTED: 202,
|
|
222
|
-
NON_AUTHORITATIVE_INFORMATION: 203,
|
|
223
|
-
NO_CONTENT: 204,
|
|
224
|
-
RESET_CONTENT: 205,
|
|
225
|
-
PARTIAL_CONTENT: 206,
|
|
226
|
-
MULTI_STATUS: 207,
|
|
227
|
-
ALREADY_REPORTED: 208,
|
|
228
|
-
IM_USED: 226,
|
|
229
|
-
MULTIPLE_CHOICES: 300,
|
|
230
|
-
MOVED_PERMANENTLY: 301,
|
|
231
|
-
FOUND: 302,
|
|
232
|
-
SEE_OTHER: 303,
|
|
233
|
-
NOT_MODIFIED: 304,
|
|
234
|
-
USE_PROXY: 305,
|
|
235
|
-
TEMPORARY_REDIRECT: 307,
|
|
236
|
-
PERMANENT_REDIRECT: 308,
|
|
237
|
-
BAD_REQUEST: 400,
|
|
238
|
-
UNAUTHORIZED: 401,
|
|
239
|
-
PAYMENT_REQUIRED: 402,
|
|
240
|
-
FORBIDDEN: 403,
|
|
241
|
-
NOT_FOUND: 404,
|
|
242
|
-
METHOD_NOT_ALLOWED: 405,
|
|
243
|
-
NOT_ACCEPTABLE: 406,
|
|
244
|
-
PROXY_AUTHENTICATION_REQUIRED: 407,
|
|
245
|
-
REQUEST_TIMEOUT: 408,
|
|
246
|
-
CONFLICT: 409,
|
|
247
|
-
GONE: 410,
|
|
248
|
-
LENGTH_REQUIRED: 411,
|
|
249
|
-
PRECONDITION_FAILED: 412,
|
|
250
|
-
PAYLOAD_TOO_LARGE: 413,
|
|
251
|
-
URI_TOO_LONG: 414,
|
|
252
|
-
UNSUPPORTED_MEDIA_TYPE: 415,
|
|
253
|
-
RANGE_NOT_SATISFIABLE: 416,
|
|
254
|
-
EXPECTATION_FAILED: 417,
|
|
255
|
-
IM_A_TEAPOT: 418,
|
|
256
|
-
MISDIRECTED_REQUEST: 421,
|
|
257
|
-
UNPROCESSABLE_ENTITY: 422,
|
|
258
|
-
LOCKED: 423,
|
|
259
|
-
FAILED_DEPENDENCY: 424,
|
|
260
|
-
TOO_EARLY: 425,
|
|
261
|
-
UPGRADE_REQUIRED: 426,
|
|
262
|
-
PRECONDITION_REQUIRED: 428,
|
|
263
|
-
TOO_MANY_REQUESTS: 429,
|
|
264
|
-
REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
|
|
265
|
-
UNAVAILABLE_FOR_LEGAL_REASONS: 451,
|
|
266
|
-
INTERNAL_SERVER_ERROR: 500,
|
|
267
|
-
NOT_IMPLEMENTED: 501,
|
|
268
|
-
BAD_GATEWAY: 502,
|
|
269
|
-
SERVICE_UNAVAILABLE: 503,
|
|
270
|
-
GATEWAY_TIMEOUT: 504,
|
|
271
|
-
HTTP_VERSION_NOT_SUPPORTED: 505,
|
|
272
|
-
VARIANT_ALSO_NEGOTIATES: 506,
|
|
273
|
-
INSUFFICIENT_STORAGE: 507,
|
|
274
|
-
LOOP_DETECTED: 508,
|
|
275
|
-
NOT_EXTENDED: 510,
|
|
276
|
-
NETWORK_AUTHENTICATION_REQUIRED: 511
|
|
277
|
-
};
|
|
185
|
+
var import_path;
|
|
186
|
+
var init_Config = __esm(() => {
|
|
187
|
+
init_RuntimeOptions();
|
|
188
|
+
init_internalLogger();
|
|
189
|
+
import_path = __toESM(require("path"));
|
|
190
|
+
});
|
|
278
191
|
|
|
279
|
-
// src/
|
|
280
|
-
var
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
192
|
+
// src/CResponse/enums/Status.ts
|
|
193
|
+
var Status;
|
|
194
|
+
var init_Status = __esm(() => {
|
|
195
|
+
Status = {
|
|
196
|
+
CONTINUE: 100,
|
|
197
|
+
SWITCHING_PROTOCOLS: 101,
|
|
198
|
+
PROCESSING: 102,
|
|
199
|
+
EARLY_HINTS: 103,
|
|
200
|
+
OK: 200,
|
|
201
|
+
CREATED: 201,
|
|
202
|
+
ACCEPTED: 202,
|
|
203
|
+
NON_AUTHORITATIVE_INFORMATION: 203,
|
|
204
|
+
NO_CONTENT: 204,
|
|
205
|
+
RESET_CONTENT: 205,
|
|
206
|
+
PARTIAL_CONTENT: 206,
|
|
207
|
+
MULTI_STATUS: 207,
|
|
208
|
+
ALREADY_REPORTED: 208,
|
|
209
|
+
IM_USED: 226,
|
|
210
|
+
MULTIPLE_CHOICES: 300,
|
|
211
|
+
MOVED_PERMANENTLY: 301,
|
|
212
|
+
FOUND: 302,
|
|
213
|
+
SEE_OTHER: 303,
|
|
214
|
+
NOT_MODIFIED: 304,
|
|
215
|
+
USE_PROXY: 305,
|
|
216
|
+
TEMPORARY_REDIRECT: 307,
|
|
217
|
+
PERMANENT_REDIRECT: 308,
|
|
218
|
+
BAD_REQUEST: 400,
|
|
219
|
+
UNAUTHORIZED: 401,
|
|
220
|
+
PAYMENT_REQUIRED: 402,
|
|
221
|
+
FORBIDDEN: 403,
|
|
222
|
+
NOT_FOUND: 404,
|
|
223
|
+
METHOD_NOT_ALLOWED: 405,
|
|
224
|
+
NOT_ACCEPTABLE: 406,
|
|
225
|
+
PROXY_AUTHENTICATION_REQUIRED: 407,
|
|
226
|
+
REQUEST_TIMEOUT: 408,
|
|
227
|
+
CONFLICT: 409,
|
|
228
|
+
GONE: 410,
|
|
229
|
+
LENGTH_REQUIRED: 411,
|
|
230
|
+
PRECONDITION_FAILED: 412,
|
|
231
|
+
PAYLOAD_TOO_LARGE: 413,
|
|
232
|
+
URI_TOO_LONG: 414,
|
|
233
|
+
UNSUPPORTED_MEDIA_TYPE: 415,
|
|
234
|
+
RANGE_NOT_SATISFIABLE: 416,
|
|
235
|
+
EXPECTATION_FAILED: 417,
|
|
236
|
+
IM_A_TEAPOT: 418,
|
|
237
|
+
MISDIRECTED_REQUEST: 421,
|
|
238
|
+
UNPROCESSABLE_ENTITY: 422,
|
|
239
|
+
LOCKED: 423,
|
|
240
|
+
FAILED_DEPENDENCY: 424,
|
|
241
|
+
TOO_EARLY: 425,
|
|
242
|
+
UPGRADE_REQUIRED: 426,
|
|
243
|
+
PRECONDITION_REQUIRED: 428,
|
|
244
|
+
TOO_MANY_REQUESTS: 429,
|
|
245
|
+
REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
|
|
246
|
+
UNAVAILABLE_FOR_LEGAL_REASONS: 451,
|
|
247
|
+
INTERNAL_SERVER_ERROR: 500,
|
|
248
|
+
NOT_IMPLEMENTED: 501,
|
|
249
|
+
BAD_GATEWAY: 502,
|
|
250
|
+
SERVICE_UNAVAILABLE: 503,
|
|
251
|
+
GATEWAY_TIMEOUT: 504,
|
|
252
|
+
HTTP_VERSION_NOT_SUPPORTED: 505,
|
|
253
|
+
VARIANT_ALSO_NEGOTIATES: 506,
|
|
254
|
+
INSUFFICIENT_STORAGE: 507,
|
|
255
|
+
LOOP_DETECTED: 508,
|
|
256
|
+
NOT_EXTENDED: 510,
|
|
257
|
+
NETWORK_AUTHENTICATION_REQUIRED: 511
|
|
258
|
+
};
|
|
259
|
+
});
|
|
295
260
|
|
|
296
|
-
// src/
|
|
297
|
-
var
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
261
|
+
// src/CResponse/enums/DefaultStatusTexts.ts
|
|
262
|
+
var DefaultStatusTexts;
|
|
263
|
+
var init_DefaultStatusTexts = __esm(() => {
|
|
264
|
+
init_Status();
|
|
265
|
+
DefaultStatusTexts = {
|
|
266
|
+
[Status.OK]: "OK",
|
|
267
|
+
[Status.CREATED]: "Created",
|
|
268
|
+
[Status.NO_CONTENT]: "No Content",
|
|
269
|
+
[Status.MOVED_PERMANENTLY]: "Moved Permanently",
|
|
270
|
+
[Status.FOUND]: "Found",
|
|
271
|
+
[Status.SEE_OTHER]: "See Other",
|
|
272
|
+
[Status.TEMPORARY_REDIRECT]: "Temporary Redirect",
|
|
273
|
+
[Status.PERMANENT_REDIRECT]: "Permanent Redirect",
|
|
274
|
+
[Status.BAD_REQUEST]: "Bad Request",
|
|
275
|
+
[Status.UNAUTHORIZED]: "Unauthorized",
|
|
276
|
+
[Status.FORBIDDEN]: "Forbidden",
|
|
277
|
+
[Status.NOT_FOUND]: "Not Found",
|
|
278
|
+
[Status.INTERNAL_SERVER_ERROR]: "Internal Server Error"
|
|
279
|
+
};
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// src/CHeaders/enums/CommonHeaders.ts
|
|
283
|
+
var CommonHeaders;
|
|
284
|
+
var init_CommonHeaders = __esm(() => {
|
|
285
|
+
CommonHeaders = {
|
|
286
|
+
CacheControl: "Cache-Control",
|
|
287
|
+
ContentType: "Content-Type",
|
|
288
|
+
ContentLength: "Content-Length",
|
|
289
|
+
ContentDisposition: "Content-Disposition",
|
|
290
|
+
AcceptEncoding: "Accept-Encoding",
|
|
291
|
+
Accept: "Accept",
|
|
292
|
+
Authorization: "Authorization",
|
|
293
|
+
UserAgent: "User-Agent",
|
|
294
|
+
Host: "Host",
|
|
295
|
+
Referer: "Referer",
|
|
296
|
+
Connection: "Connection",
|
|
297
|
+
Upgrade: "Upgrade",
|
|
298
|
+
Pragma: "Pragma",
|
|
299
|
+
Date: "Date",
|
|
300
|
+
IfNoneMatch: "If-None-Match",
|
|
301
|
+
IfModifiedSince: "If-Modified-Since",
|
|
302
|
+
ETag: "ETag",
|
|
303
|
+
Expires: "Expires",
|
|
304
|
+
LastModified: "Last-Modified",
|
|
305
|
+
Location: "Location",
|
|
306
|
+
WWWAuthenticate: "WWW-Authenticate",
|
|
307
|
+
AccessControlAllowOrigin: "Access-Control-Allow-Origin",
|
|
308
|
+
AccessControlMaxAge: "Access-Control-Max-Age",
|
|
309
|
+
AccessControlAllowCredentials: "Access-Control-Allow-Credentials",
|
|
310
|
+
AccessControlRequestMethod: "Access-Control-Request-Method",
|
|
311
|
+
SetCookie: "Set-Cookie",
|
|
312
|
+
Cookie: "Cookie"
|
|
313
|
+
};
|
|
314
|
+
});
|
|
324
315
|
|
|
325
316
|
// src/Cookies/CookiesAbstract.ts
|
|
326
317
|
class CookiesAbstract {
|
|
318
|
+
constructor(_) {}
|
|
327
319
|
applyInit(init) {
|
|
328
320
|
if (!init)
|
|
329
321
|
return;
|
|
@@ -342,116 +334,465 @@ class CookiesAbstract {
|
|
|
342
334
|
}
|
|
343
335
|
}
|
|
344
336
|
|
|
345
|
-
// src/Cookies/
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
337
|
+
// src/Cookies/Cookies.bun.ts
|
|
338
|
+
var exports_Cookies_bun = {};
|
|
339
|
+
__export(exports_Cookies_bun, {
|
|
340
|
+
default: () => CookiesUsingBun
|
|
341
|
+
});
|
|
342
|
+
var CookiesUsingBun;
|
|
343
|
+
var init_Cookies_bun = __esm(() => {
|
|
344
|
+
CookiesUsingBun = class CookiesUsingBun extends CookiesAbstract {
|
|
345
|
+
constructor(init) {
|
|
346
|
+
super(init);
|
|
347
|
+
this.applyInit(init);
|
|
348
|
+
}
|
|
349
|
+
map = new Bun.CookieMap;
|
|
350
|
+
toSetCookieHeaders() {
|
|
351
|
+
return this.map.toSetCookieHeaders();
|
|
352
|
+
}
|
|
353
|
+
set(opts) {
|
|
354
|
+
this.map.set(opts.name, opts.value, opts);
|
|
355
|
+
}
|
|
356
|
+
setMany(optsArr) {
|
|
357
|
+
for (const opts of optsArr) {
|
|
358
|
+
this.set(opts);
|
|
359
|
+
}
|
|
361
360
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
}
|
|
361
|
+
get(name) {
|
|
362
|
+
return this.map.get(name);
|
|
363
|
+
}
|
|
364
|
+
has(name) {
|
|
365
|
+
return this.map.has(name);
|
|
366
|
+
}
|
|
367
|
+
get count() {
|
|
368
|
+
return this.values().length;
|
|
369
|
+
}
|
|
370
|
+
delete(name) {
|
|
371
|
+
this.map.delete(name);
|
|
372
|
+
}
|
|
373
|
+
entries() {
|
|
374
|
+
return this.map.entries();
|
|
375
|
+
}
|
|
376
|
+
values() {
|
|
377
|
+
return Array.from(this.map.values());
|
|
378
|
+
}
|
|
379
|
+
keys() {
|
|
380
|
+
return Array.from(this.map.keys());
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
// src/utils/strAfterMark.ts
|
|
386
|
+
function strAfterMark(mark, input) {
|
|
387
|
+
const index = input.indexOf(mark);
|
|
388
|
+
return index === -1 ? "" : input.slice(index + mark.length);
|
|
384
389
|
}
|
|
385
390
|
|
|
386
|
-
// src/
|
|
387
|
-
|
|
391
|
+
// src/utils/strBeforeMark.ts
|
|
392
|
+
function strBeforeMark(mark, input) {
|
|
393
|
+
const index = input.indexOf(mark);
|
|
394
|
+
return index === -1 ? input : input.slice(0, index);
|
|
388
395
|
}
|
|
389
396
|
|
|
390
|
-
// src/
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
return super.has(name) || super.has(name.toLowerCase());
|
|
397
|
+
// src/utils/strCapitalize.ts
|
|
398
|
+
function strCapitalize(input) {
|
|
399
|
+
return input.length > 0 ? input.split(" ").map((part) => part.charAt(0).toLocaleUpperCase() + input.slice(1)).join(" ") : input;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// src/utils/assert.ts
|
|
403
|
+
function assert(condition, message) {
|
|
404
|
+
const conditionName = String(condition);
|
|
405
|
+
if (!condition) {
|
|
406
|
+
if (!message) {
|
|
407
|
+
message = `Assertion failed for ${conditionName}`;
|
|
408
|
+
} else {
|
|
409
|
+
message = `${conditionName}: ${message}`;
|
|
410
|
+
}
|
|
411
|
+
throw new Error(message);
|
|
406
412
|
}
|
|
407
|
-
|
|
408
|
-
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// src/utils/strSplit.ts
|
|
416
|
+
function strSplit(mark, input, minLength) {
|
|
417
|
+
const parts = input.split(mark).map((part) => part.trim()).filter(Boolean);
|
|
418
|
+
if (minLength) {
|
|
419
|
+
assert(parts.length >= minLength);
|
|
420
|
+
return parts;
|
|
409
421
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
422
|
+
return parts;
|
|
423
|
+
}
|
|
424
|
+
var init_strSplit = () => {};
|
|
425
|
+
|
|
426
|
+
// src/Cookies/Cookies.node.ts
|
|
427
|
+
var exports_Cookies_node = {};
|
|
428
|
+
__export(exports_Cookies_node, {
|
|
429
|
+
default: () => CookiesUsingMap
|
|
430
|
+
});
|
|
431
|
+
var CookiesUsingMap;
|
|
432
|
+
var init_Cookies_node = __esm(() => {
|
|
433
|
+
init_strSplit();
|
|
434
|
+
init_internalLogger();
|
|
435
|
+
CookiesUsingMap = class CookiesUsingMap extends CookiesAbstract {
|
|
436
|
+
constructor(init) {
|
|
437
|
+
super(init);
|
|
438
|
+
this.applyInit(init);
|
|
439
|
+
}
|
|
440
|
+
map = new Map;
|
|
441
|
+
toSetCookieHeaders() {
|
|
442
|
+
return Array.from(this.map.values());
|
|
443
|
+
}
|
|
444
|
+
set(opts) {
|
|
445
|
+
this.map.set(opts.name, this.createHeader(opts));
|
|
446
|
+
}
|
|
447
|
+
setMany(optsArr) {
|
|
448
|
+
for (const opts of optsArr) {
|
|
449
|
+
this.set(opts);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
get(name) {
|
|
453
|
+
const cookieString = this.map.get(name);
|
|
454
|
+
if (!cookieString)
|
|
455
|
+
return null;
|
|
456
|
+
const value = this.extractValue(cookieString);
|
|
457
|
+
return strIsDefined(value) ? value : null;
|
|
458
|
+
}
|
|
459
|
+
has(name) {
|
|
460
|
+
const has = this.map.has(name);
|
|
461
|
+
if (!has)
|
|
462
|
+
return false;
|
|
463
|
+
const value = this.get(name);
|
|
464
|
+
return !!value;
|
|
465
|
+
}
|
|
466
|
+
get count() {
|
|
467
|
+
return this.values().filter((value) => strIsDefined(value)).length;
|
|
468
|
+
}
|
|
469
|
+
delete(name) {
|
|
470
|
+
const cookieString = this.map.get(name);
|
|
471
|
+
if (!cookieString)
|
|
472
|
+
return;
|
|
473
|
+
const opts = this.extractOptions(cookieString);
|
|
474
|
+
this.set({ ...opts, value: "", expires: new Date(0) });
|
|
475
|
+
}
|
|
476
|
+
entries() {
|
|
477
|
+
return this.map.entries();
|
|
478
|
+
}
|
|
479
|
+
values() {
|
|
480
|
+
return Array.from(this.map.values()).map((cookieString) => this.extractValue(cookieString));
|
|
481
|
+
}
|
|
482
|
+
keys() {
|
|
483
|
+
return Array.from(this.map.keys());
|
|
484
|
+
}
|
|
485
|
+
extractValue(cookieString) {
|
|
486
|
+
const encodedRest = strAfterMark("=", cookieString);
|
|
487
|
+
if (!strIsDefined(encodedRest))
|
|
488
|
+
return "";
|
|
489
|
+
const encodedValue = strBeforeMark(";", encodedRest);
|
|
490
|
+
return decodeURIComponent(encodedValue);
|
|
491
|
+
}
|
|
492
|
+
extractOptions(cookieString) {
|
|
493
|
+
const keyMap = {
|
|
494
|
+
Domain: "domain",
|
|
495
|
+
Path: "path",
|
|
496
|
+
Expires: "expires",
|
|
497
|
+
Secure: "secure",
|
|
498
|
+
SameSite: "sameSite",
|
|
499
|
+
HttpOnly: "httpOnly",
|
|
500
|
+
Partitioned: "partitioned",
|
|
501
|
+
"Max-Age": "maxAge"
|
|
502
|
+
};
|
|
503
|
+
const opts = {};
|
|
504
|
+
const first = strBeforeMark(";", cookieString).trim();
|
|
505
|
+
const rest = strAfterMark(";", cookieString).trim();
|
|
506
|
+
const [name, value] = strSplit("=", first);
|
|
507
|
+
opts["name"] = name;
|
|
508
|
+
opts["value"] = value;
|
|
509
|
+
for (const part of strSplit(";", rest)) {
|
|
510
|
+
if (part.includes("=")) {
|
|
511
|
+
const [key, val] = strSplit("=", part, 2);
|
|
512
|
+
if (!key || !keyMap[key]) {
|
|
513
|
+
log.warn(`cookie extracting and ${key} is not a cookie key`);
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
opts[keyMap[key]] = val;
|
|
517
|
+
} else {
|
|
518
|
+
if (!keyMap[part]) {
|
|
519
|
+
log.warn(`cookie extracting and ${part} is not a cookie key`);
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
opts[keyMap[part]] = true;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return opts;
|
|
526
|
+
}
|
|
527
|
+
createHeader(opts) {
|
|
528
|
+
let result = `${encodeURIComponent(opts.name)}=${encodeURIComponent(opts.value)}`;
|
|
529
|
+
if (strIsDefined(opts.domain)) {
|
|
530
|
+
result += `; Domain=${opts.domain}`;
|
|
531
|
+
}
|
|
532
|
+
if (strIsDefined(opts.path)) {
|
|
533
|
+
result += `; Path=${opts.path}`;
|
|
414
534
|
} else {
|
|
415
|
-
|
|
535
|
+
result += `; Path=/`;
|
|
416
536
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
537
|
+
if (opts.expires) {
|
|
538
|
+
if (typeof opts.expires === "number") {
|
|
539
|
+
result += `; Expires=${new Date(opts.expires).toUTCString()}`;
|
|
540
|
+
} else {
|
|
541
|
+
result += `; Expires=${opts.expires.toUTCString()}`;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
if (opts.maxAge && Number.isInteger(opts.maxAge)) {
|
|
545
|
+
result += `; Max-Age=${opts.maxAge}`;
|
|
546
|
+
}
|
|
547
|
+
if (opts.secure === true) {
|
|
548
|
+
result += "; Secure";
|
|
549
|
+
}
|
|
550
|
+
if (opts.httpOnly === true) {
|
|
551
|
+
result += "; HttpOnly";
|
|
552
|
+
}
|
|
553
|
+
if (opts.partitioned === true) {
|
|
554
|
+
result += "; Partitioned";
|
|
555
|
+
}
|
|
556
|
+
if (strIsDefined(opts.sameSite)) {
|
|
557
|
+
result += `; SameSite=${strCapitalize(opts.sameSite)}`;
|
|
558
|
+
} else {
|
|
559
|
+
result += `; SameSite=Lax`;
|
|
560
|
+
}
|
|
561
|
+
return result;
|
|
429
562
|
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
563
|
+
};
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
// src/Cookies/Cookies.ts
|
|
567
|
+
var Adapted, Cookies;
|
|
568
|
+
var init_Cookies = __esm(() => {
|
|
569
|
+
Adapted = (typeof Bun !== "undefined" ? (init_Cookies_bun(), __toCommonJS(exports_Cookies_bun)) : (init_Cookies_node(), __toCommonJS(exports_Cookies_node))).default;
|
|
570
|
+
Cookies = class Cookies extends Adapted {
|
|
571
|
+
};
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
// src/CHeaders/CHeaders.ts
|
|
575
|
+
var CHeaders;
|
|
576
|
+
var init_CHeaders = __esm(() => {
|
|
577
|
+
CHeaders = class CHeaders extends Headers {
|
|
578
|
+
constructor(init) {
|
|
579
|
+
super(init);
|
|
580
|
+
}
|
|
581
|
+
append(name, value) {
|
|
582
|
+
super.append(name, value);
|
|
583
|
+
}
|
|
584
|
+
set(name, value) {
|
|
585
|
+
super.set(name, value);
|
|
586
|
+
}
|
|
587
|
+
get(name) {
|
|
588
|
+
return super.get(name) || super.get(name.toLowerCase());
|
|
589
|
+
}
|
|
590
|
+
has(name) {
|
|
591
|
+
return super.has(name) || super.has(name.toLowerCase());
|
|
592
|
+
}
|
|
593
|
+
delete(name) {
|
|
594
|
+
return super.delete(name);
|
|
595
|
+
}
|
|
596
|
+
static combine(source, target) {
|
|
597
|
+
source.forEach((value, key) => {
|
|
598
|
+
if (key.toLowerCase() === "set-cookie") {
|
|
599
|
+
target.append(key, value);
|
|
600
|
+
} else {
|
|
601
|
+
target.set(key, value);
|
|
602
|
+
}
|
|
603
|
+
});
|
|
604
|
+
return target;
|
|
605
|
+
}
|
|
606
|
+
innerCombine(source) {
|
|
607
|
+
CHeaders.combine(source, this);
|
|
608
|
+
}
|
|
609
|
+
setMany(init) {
|
|
610
|
+
const entries = Array.isArray(init) ? init : Object.entries(init);
|
|
611
|
+
for (const [key, value] of entries) {
|
|
612
|
+
if (!strIsDefined(value))
|
|
613
|
+
continue;
|
|
614
|
+
this.set(key, value);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
static findHeaderInInit(init, name) {
|
|
618
|
+
if (init instanceof CHeaders || init instanceof Headers) {
|
|
619
|
+
return init.get(name);
|
|
620
|
+
} else if (Array.isArray(init)) {
|
|
621
|
+
return init.find((entry) => entry[0] === name)?.[1] ?? null;
|
|
622
|
+
} else {
|
|
623
|
+
return init[name] ?? null;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
// src/utils/isNil.ts
|
|
630
|
+
function isNil(input) {
|
|
631
|
+
return input === null || input === undefined;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// src/utils/isPrimitive.ts
|
|
635
|
+
function isPrimitive(input) {
|
|
636
|
+
return typeof input === "string" || typeof input === "number" || typeof input === "boolean" || typeof input === "bigint";
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// src/utils/isPlainObject.ts
|
|
640
|
+
function isPlainObject(input) {
|
|
641
|
+
return typeof input === "object" && input !== null && input.constructor === Object;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// src/CError/CError.ts
|
|
645
|
+
var CError;
|
|
646
|
+
var init_CError = __esm(() => {
|
|
647
|
+
init_CResponse();
|
|
648
|
+
CError = class CError extends Error {
|
|
649
|
+
message;
|
|
650
|
+
status;
|
|
651
|
+
data;
|
|
652
|
+
constructor(message, status, data) {
|
|
653
|
+
super(message);
|
|
654
|
+
this.message = message;
|
|
655
|
+
this.status = status;
|
|
656
|
+
this.data = data;
|
|
657
|
+
}
|
|
658
|
+
toResponse() {
|
|
659
|
+
if (this.data instanceof CResponse) {
|
|
660
|
+
this.data.status = this.status;
|
|
661
|
+
return this.data;
|
|
662
|
+
}
|
|
663
|
+
return new CResponse({ error: this.data ?? true, message: this.message }, { status: this.status });
|
|
664
|
+
}
|
|
665
|
+
isStatusOf(status) {
|
|
666
|
+
return this.status === status;
|
|
438
667
|
}
|
|
668
|
+
};
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
// src/XFile/XFileAbstract.ts
|
|
672
|
+
class XFileAbstract {
|
|
673
|
+
path;
|
|
674
|
+
fallbackExtension;
|
|
675
|
+
constructor(path2, fallbackExtension) {
|
|
676
|
+
this.path = path2;
|
|
677
|
+
this.fallbackExtension = fallbackExtension;
|
|
678
|
+
}
|
|
679
|
+
get name() {
|
|
680
|
+
return this.path.split("/").pop() ?? this.path;
|
|
681
|
+
}
|
|
682
|
+
get extension() {
|
|
683
|
+
return this.path.split(".").pop() ?? this.fallbackExtension ?? "txt";
|
|
684
|
+
}
|
|
685
|
+
get mimeType() {
|
|
686
|
+
const mimeTypes = {
|
|
687
|
+
html: "text/html",
|
|
688
|
+
htm: "text/html",
|
|
689
|
+
css: "text/css",
|
|
690
|
+
js: "application/javascript",
|
|
691
|
+
ts: "application/javascript",
|
|
692
|
+
mjs: "application/javascript",
|
|
693
|
+
json: "application/json",
|
|
694
|
+
png: "image/png",
|
|
695
|
+
jpg: "image/jpeg",
|
|
696
|
+
jpeg: "image/jpeg",
|
|
697
|
+
gif: "image/gif",
|
|
698
|
+
svg: "image/svg+xml",
|
|
699
|
+
ico: "image/x-icon",
|
|
700
|
+
txt: "text/plain",
|
|
701
|
+
xml: "application/xml",
|
|
702
|
+
pdf: "application/pdf",
|
|
703
|
+
zip: "application/zip",
|
|
704
|
+
mp3: "audio/mpeg",
|
|
705
|
+
mp4: "video/mp4",
|
|
706
|
+
webm: "video/webm",
|
|
707
|
+
woff: "font/woff",
|
|
708
|
+
woff2: "font/woff2",
|
|
709
|
+
ttf: "font/ttf"
|
|
710
|
+
};
|
|
711
|
+
return mimeTypes[this.extension] ?? "application/octet-stream";
|
|
439
712
|
}
|
|
440
713
|
}
|
|
441
714
|
|
|
442
|
-
// src/
|
|
443
|
-
|
|
444
|
-
|
|
715
|
+
// src/XFile/XFile.bun.ts
|
|
716
|
+
var exports_XFile_bun = {};
|
|
717
|
+
__export(exports_XFile_bun, {
|
|
718
|
+
default: () => XFileUsingBun
|
|
719
|
+
});
|
|
720
|
+
var XFileUsingBun;
|
|
721
|
+
var init_XFile_bun = __esm(() => {
|
|
722
|
+
XFileUsingBun = class XFileUsingBun extends XFileAbstract {
|
|
723
|
+
constructor(...args) {
|
|
724
|
+
super(...args);
|
|
725
|
+
this.file = Bun.file(args[0]);
|
|
726
|
+
}
|
|
727
|
+
file;
|
|
728
|
+
async exists() {
|
|
729
|
+
return await this.file.exists();
|
|
730
|
+
}
|
|
731
|
+
async text() {
|
|
732
|
+
return await this.file.text();
|
|
733
|
+
}
|
|
734
|
+
stream() {
|
|
735
|
+
return this.file.stream();
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
// src/XFile/XFile.node.ts
|
|
741
|
+
var exports_XFile_node = {};
|
|
742
|
+
__export(exports_XFile_node, {
|
|
743
|
+
default: () => XFileUsingNode
|
|
744
|
+
});
|
|
745
|
+
var import_node_fs, XFileUsingNode;
|
|
746
|
+
var init_XFile_node = __esm(() => {
|
|
747
|
+
import_node_fs = __toESM(require("fs"));
|
|
748
|
+
XFileUsingNode = class XFileUsingNode extends XFileAbstract {
|
|
749
|
+
async exists() {
|
|
750
|
+
return import_node_fs.default.existsSync(this.path);
|
|
751
|
+
}
|
|
752
|
+
async text() {
|
|
753
|
+
return import_node_fs.default.readFileSync(this.path, "utf-8");
|
|
754
|
+
}
|
|
755
|
+
stream() {
|
|
756
|
+
const nodeStream = import_node_fs.default.createReadStream(this.path);
|
|
757
|
+
const encoder = new TextEncoder;
|
|
758
|
+
return new ReadableStream({
|
|
759
|
+
start(controller) {
|
|
760
|
+
nodeStream.on("data", (chunk) => {
|
|
761
|
+
controller.enqueue(typeof chunk === "string" ? encoder.encode(chunk) : new Uint8Array(chunk));
|
|
762
|
+
});
|
|
763
|
+
nodeStream.on("end", () => controller.close());
|
|
764
|
+
nodeStream.on("error", (err) => controller.error(err));
|
|
765
|
+
},
|
|
766
|
+
cancel() {
|
|
767
|
+
nodeStream.destroy();
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
// src/XFile/XFile.ts
|
|
775
|
+
var Adapted2, XFile;
|
|
776
|
+
var init_XFile = __esm(() => {
|
|
777
|
+
Adapted2 = (typeof Bun !== "undefined" ? (init_XFile_bun(), __toCommonJS(exports_XFile_bun)) : (init_XFile_node(), __toCommonJS(exports_XFile_node))).default;
|
|
778
|
+
XFile = class XFile extends Adapted2 {
|
|
779
|
+
};
|
|
780
|
+
});
|
|
781
|
+
|
|
782
|
+
// src/CResponse/CResponse.ts
|
|
783
|
+
class CResponse {
|
|
784
|
+
data;
|
|
445
785
|
init;
|
|
446
|
-
constructor(
|
|
447
|
-
this.
|
|
786
|
+
constructor(data, init) {
|
|
787
|
+
this.data = data;
|
|
448
788
|
this.init = init;
|
|
449
|
-
this.cookies = this.
|
|
450
|
-
this.headers = this.
|
|
451
|
-
this.body = this.
|
|
452
|
-
this.status = this.
|
|
453
|
-
this.statusText =
|
|
789
|
+
this.cookies = this.resolveCookies();
|
|
790
|
+
this.headers = this.resolveHeaders();
|
|
791
|
+
this.body = this.resolveBody();
|
|
792
|
+
this.status = this.resolveStatus();
|
|
793
|
+
this.statusText = CResponse.getDefaultStatusText(this.status);
|
|
454
794
|
}
|
|
795
|
+
body;
|
|
455
796
|
headers;
|
|
456
797
|
status;
|
|
457
798
|
statusText;
|
|
@@ -463,11 +804,128 @@ class HttpResponse {
|
|
|
463
804
|
headers: this.headers
|
|
464
805
|
});
|
|
465
806
|
}
|
|
466
|
-
|
|
467
|
-
|
|
807
|
+
static redirect(url, init) {
|
|
808
|
+
const res = new CResponse(undefined, {
|
|
809
|
+
...init,
|
|
810
|
+
status: init?.status ?? Status.FOUND,
|
|
811
|
+
statusText: init?.statusText ?? DefaultStatusTexts[Status.FOUND]
|
|
812
|
+
});
|
|
813
|
+
const urlString = url instanceof URL ? url.toString() : url;
|
|
814
|
+
res.headers.set(CommonHeaders.Location, urlString);
|
|
815
|
+
return res;
|
|
816
|
+
}
|
|
817
|
+
static permanentRedirect(url, init) {
|
|
818
|
+
return this.redirect(url, {
|
|
819
|
+
...init,
|
|
820
|
+
status: Status.MOVED_PERMANENTLY
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
static temporaryRedirect(url, init) {
|
|
824
|
+
return this.redirect(url, { ...init, status: Status.TEMPORARY_REDIRECT });
|
|
825
|
+
}
|
|
826
|
+
static seeOther(url, init) {
|
|
827
|
+
return this.redirect(url, { ...init, status: Status.SEE_OTHER });
|
|
828
|
+
}
|
|
829
|
+
static createStream(execute) {
|
|
830
|
+
let cancelled = false;
|
|
831
|
+
let cleanup;
|
|
832
|
+
return new ReadableStream({
|
|
833
|
+
start(controller) {
|
|
834
|
+
try {
|
|
835
|
+
cleanup = execute(controller, () => cancelled);
|
|
836
|
+
if (typeof cleanup !== "function") {
|
|
837
|
+
controller.close();
|
|
838
|
+
}
|
|
839
|
+
} catch (err) {
|
|
840
|
+
controller.error(err);
|
|
841
|
+
}
|
|
842
|
+
},
|
|
843
|
+
cancel() {
|
|
844
|
+
cancelled = true;
|
|
845
|
+
cleanup?.();
|
|
846
|
+
}
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
static sse(source, init, retry) {
|
|
850
|
+
const encoder = new TextEncoder;
|
|
851
|
+
const stream = CResponse.createStream((controller, isCancelled) => {
|
|
852
|
+
return source((event) => {
|
|
853
|
+
if (isCancelled())
|
|
854
|
+
return;
|
|
855
|
+
let chunk = "";
|
|
856
|
+
if (retry !== undefined)
|
|
857
|
+
chunk += `retry: ${retry}
|
|
858
|
+
`;
|
|
859
|
+
if (event.id)
|
|
860
|
+
chunk += `id: ${event.id}
|
|
861
|
+
`;
|
|
862
|
+
if (event.event)
|
|
863
|
+
chunk += `event: ${event.event}
|
|
864
|
+
`;
|
|
865
|
+
chunk += `data: ${JSON.stringify(event.data)}
|
|
866
|
+
|
|
867
|
+
`;
|
|
868
|
+
controller.enqueue(encoder.encode(chunk));
|
|
869
|
+
});
|
|
870
|
+
});
|
|
871
|
+
const res = new CResponse(stream, { ...init, status: Status.OK });
|
|
872
|
+
res.headers.setMany({
|
|
873
|
+
[CommonHeaders.ContentType]: "text/event-stream",
|
|
874
|
+
[CommonHeaders.CacheControl]: "no-cache",
|
|
875
|
+
[CommonHeaders.Connection]: "keep-alive"
|
|
876
|
+
});
|
|
877
|
+
return res;
|
|
878
|
+
}
|
|
879
|
+
static ndjson(source, init) {
|
|
880
|
+
const encoder = new TextEncoder;
|
|
881
|
+
const stream = CResponse.createStream((controller, isCancelled) => {
|
|
882
|
+
return source((item) => {
|
|
883
|
+
if (isCancelled())
|
|
884
|
+
return;
|
|
885
|
+
controller.enqueue(encoder.encode(`${JSON.stringify(item)}
|
|
886
|
+
`));
|
|
887
|
+
});
|
|
888
|
+
});
|
|
889
|
+
const res = new CResponse(stream, { ...init, status: Status.OK });
|
|
890
|
+
res.headers.setMany({
|
|
891
|
+
[CommonHeaders.ContentType]: "application/x-ndjson",
|
|
892
|
+
[CommonHeaders.CacheControl]: "no-cache"
|
|
893
|
+
});
|
|
894
|
+
return res;
|
|
895
|
+
}
|
|
896
|
+
static async streamFile(filePath, disposition = "attachment", init) {
|
|
897
|
+
const file = new XFile(filePath);
|
|
898
|
+
const exists = await file.exists();
|
|
899
|
+
if (!exists) {
|
|
900
|
+
throw new CError(Status.NOT_FOUND.toString(), Status.NOT_FOUND, new CResponse({ filePath }, init));
|
|
901
|
+
}
|
|
902
|
+
const stream = file.stream();
|
|
903
|
+
const res = new CResponse(stream, { ...init, status: Status.OK });
|
|
904
|
+
res.headers.setMany({
|
|
905
|
+
[CommonHeaders.ContentType]: file.mimeType,
|
|
906
|
+
[CommonHeaders.ContentDisposition]: `${disposition}; filename="${file.name}"`
|
|
907
|
+
});
|
|
908
|
+
return res;
|
|
909
|
+
}
|
|
910
|
+
static async file(filePath, init) {
|
|
911
|
+
const file = new XFile(filePath);
|
|
912
|
+
const exists = await file.exists();
|
|
913
|
+
if (!exists) {
|
|
914
|
+
throw new CError(Status.NOT_FOUND.toString(), Status.NOT_FOUND, new CResponse({ filePath }, init));
|
|
915
|
+
}
|
|
916
|
+
const content = await file.text();
|
|
917
|
+
const res = new CResponse(content, init);
|
|
918
|
+
res.headers.setMany({
|
|
919
|
+
[CommonHeaders.ContentType]: file.mimeType,
|
|
920
|
+
[CommonHeaders.ContentLength]: content.length.toString()
|
|
921
|
+
});
|
|
922
|
+
return res;
|
|
923
|
+
}
|
|
924
|
+
resolveCookies() {
|
|
925
|
+
return this.init?.cookies instanceof Cookies ? this.init.cookies : new Cookies(this.init?.cookies);
|
|
468
926
|
}
|
|
469
|
-
|
|
470
|
-
const headers = new
|
|
927
|
+
resolveHeaders() {
|
|
928
|
+
const headers = new CHeaders(this.init?.headers);
|
|
471
929
|
const setCookieHeaders = this.cookies.toSetCookieHeaders();
|
|
472
930
|
if (setCookieHeaders.length > 0) {
|
|
473
931
|
for (const header of setCookieHeaders) {
|
|
@@ -476,7 +934,7 @@ class HttpResponse {
|
|
|
476
934
|
}
|
|
477
935
|
return headers;
|
|
478
936
|
}
|
|
479
|
-
|
|
937
|
+
resolveStatus() {
|
|
480
938
|
if (this.init?.status)
|
|
481
939
|
return this.init.status;
|
|
482
940
|
if (this.headers.has(CommonHeaders.Location)) {
|
|
@@ -489,108 +947,76 @@ class HttpResponse {
|
|
|
489
947
|
this.headers.set(CommonHeaders.ContentType, value);
|
|
490
948
|
}
|
|
491
949
|
}
|
|
492
|
-
|
|
493
|
-
if (this.
|
|
950
|
+
resolveBody() {
|
|
951
|
+
if (isNil(this.data)) {
|
|
494
952
|
this.setContentType("text/plain");
|
|
495
953
|
return "";
|
|
496
954
|
}
|
|
497
|
-
if (
|
|
955
|
+
if (isPrimitive(this.data)) {
|
|
498
956
|
this.setContentType("text/plain");
|
|
499
|
-
return String(this.
|
|
957
|
+
return String(this.data);
|
|
958
|
+
}
|
|
959
|
+
if (this.data instanceof ArrayBuffer) {
|
|
960
|
+
this.setContentType("application/octet-stream");
|
|
961
|
+
return this.data;
|
|
962
|
+
}
|
|
963
|
+
if (this.data instanceof Blob) {
|
|
964
|
+
if (this.data.type)
|
|
965
|
+
this.setContentType(this.data.type);
|
|
966
|
+
return this.data;
|
|
967
|
+
}
|
|
968
|
+
if (this.data instanceof FormData) {
|
|
969
|
+
this.setContentType("multipart/form-data");
|
|
970
|
+
return this.data;
|
|
500
971
|
}
|
|
501
|
-
if (this.
|
|
502
|
-
|
|
972
|
+
if (this.data instanceof URLSearchParams) {
|
|
973
|
+
this.setContentType("application/x-www-form-urlencoded");
|
|
974
|
+
return this.data;
|
|
503
975
|
}
|
|
504
|
-
if (this.
|
|
976
|
+
if (this.data instanceof ReadableStream) {
|
|
977
|
+
return this.data;
|
|
978
|
+
}
|
|
979
|
+
if (this.data instanceof Date) {
|
|
505
980
|
this.setContentType("text/plain");
|
|
506
|
-
return this.
|
|
981
|
+
return this.data.toISOString();
|
|
507
982
|
}
|
|
508
|
-
if (Array.isArray(this.
|
|
983
|
+
if (Array.isArray(this.data) || isPlainObject(this.data)) {
|
|
509
984
|
this.setContentType("application/json");
|
|
510
|
-
return JSON.stringify(this.
|
|
985
|
+
return JSON.stringify(this.data);
|
|
511
986
|
}
|
|
512
987
|
this.setContentType("text/plain");
|
|
513
|
-
return String(this.
|
|
988
|
+
return String(this.data);
|
|
514
989
|
}
|
|
515
|
-
getDefaultStatusText() {
|
|
516
|
-
const key =
|
|
990
|
+
static getDefaultStatusText(status) {
|
|
991
|
+
const key = status;
|
|
517
992
|
return DefaultStatusTexts[key] ?? "Unknown";
|
|
518
993
|
}
|
|
519
|
-
static redirect(url, init) {
|
|
520
|
-
const res = new HttpResponse(undefined, {
|
|
521
|
-
...init,
|
|
522
|
-
status: init?.status ?? Status.FOUND,
|
|
523
|
-
statusText: init?.statusText ?? DefaultStatusTexts[Status.FOUND]
|
|
524
|
-
});
|
|
525
|
-
const urlString = url instanceof URL ? url.toString() : url;
|
|
526
|
-
res.headers.set(CommonHeaders.Location, urlString);
|
|
527
|
-
return res;
|
|
528
|
-
}
|
|
529
|
-
static permanentRedirect(url, init) {
|
|
530
|
-
return this.redirect(url, {
|
|
531
|
-
...init,
|
|
532
|
-
status: Status.MOVED_PERMANENTLY
|
|
533
|
-
});
|
|
534
|
-
}
|
|
535
|
-
static temporaryRedirect(url, init) {
|
|
536
|
-
return this.redirect(url, { ...init, status: Status.TEMPORARY_REDIRECT });
|
|
537
|
-
}
|
|
538
|
-
static seeOther(url, init) {
|
|
539
|
-
return this.redirect(url, { ...init, status: Status.SEE_OTHER });
|
|
540
|
-
}
|
|
541
994
|
}
|
|
995
|
+
var init_CResponse = __esm(() => {
|
|
996
|
+
init_DefaultStatusTexts();
|
|
997
|
+
init_Status();
|
|
998
|
+
init_CommonHeaders();
|
|
999
|
+
init_Cookies();
|
|
1000
|
+
init_CHeaders();
|
|
1001
|
+
init_CError();
|
|
1002
|
+
init_XFile();
|
|
1003
|
+
});
|
|
542
1004
|
|
|
543
|
-
// src/
|
|
544
|
-
var Method
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
message;
|
|
559
|
-
status;
|
|
560
|
-
data;
|
|
561
|
-
constructor(message, status, data) {
|
|
562
|
-
super(message);
|
|
563
|
-
this.message = message;
|
|
564
|
-
this.status = status;
|
|
565
|
-
this.data = data;
|
|
566
|
-
}
|
|
567
|
-
toResponse() {
|
|
568
|
-
return new HttpResponse(this.data ? { error: this.data, message: this.message } : { error: true, message: this.message }, { status: this.status });
|
|
569
|
-
}
|
|
570
|
-
isStatusOf(status) {
|
|
571
|
-
return this.status === status;
|
|
572
|
-
}
|
|
573
|
-
static internalServerError(msg) {
|
|
574
|
-
const status = Status.INTERNAL_SERVER_ERROR;
|
|
575
|
-
return new this(msg ?? status.toString(), status);
|
|
576
|
-
}
|
|
577
|
-
static badRequest(msg) {
|
|
578
|
-
const status = Status.BAD_REQUEST;
|
|
579
|
-
return new this(msg ?? status.toString(), status);
|
|
580
|
-
}
|
|
581
|
-
static notFound(msg) {
|
|
582
|
-
const status = Status.NOT_FOUND;
|
|
583
|
-
return new this(msg ?? status.toString(), status);
|
|
584
|
-
}
|
|
585
|
-
static methodNotAllowed(msg) {
|
|
586
|
-
const status = Status.METHOD_NOT_ALLOWED;
|
|
587
|
-
return new this(msg ?? status.toString(), status);
|
|
588
|
-
}
|
|
589
|
-
static unprocessableEntity(msg) {
|
|
590
|
-
const status = Status.UNPROCESSABLE_ENTITY;
|
|
591
|
-
return new this(msg ?? status.toString(), status);
|
|
592
|
-
}
|
|
593
|
-
}
|
|
1005
|
+
// src/CRequest/enums/Method.ts
|
|
1006
|
+
var Method;
|
|
1007
|
+
var init_Method = __esm(() => {
|
|
1008
|
+
Method = {
|
|
1009
|
+
GET: "GET",
|
|
1010
|
+
POST: "POST",
|
|
1011
|
+
PUT: "PUT",
|
|
1012
|
+
PATCH: "PATCH",
|
|
1013
|
+
DELETE: "DELETE",
|
|
1014
|
+
HEAD: "HEAD",
|
|
1015
|
+
OPTIONS: "OPTIONS",
|
|
1016
|
+
CONNECT: "CONNECT",
|
|
1017
|
+
TRACE: "TRACE"
|
|
1018
|
+
};
|
|
1019
|
+
});
|
|
594
1020
|
|
|
595
1021
|
// src/utils/arrIncludes.ts
|
|
596
1022
|
function arrIncludes(input, array) {
|
|
@@ -612,15 +1038,15 @@ function objAppendEntry(data, key, value) {
|
|
|
612
1038
|
}
|
|
613
1039
|
}
|
|
614
1040
|
|
|
615
|
-
// src/Model/
|
|
616
|
-
class
|
|
1041
|
+
// src/Model/XParser.ts
|
|
1042
|
+
class XParser {
|
|
617
1043
|
static async parse(data, validate) {
|
|
618
1044
|
if (!validate)
|
|
619
1045
|
return data;
|
|
620
1046
|
const result = await validate(data);
|
|
621
1047
|
if (result.issues !== undefined) {
|
|
622
1048
|
const msg = this.issuesToErrorMessage(result.issues);
|
|
623
|
-
throw
|
|
1049
|
+
throw new CError(msg, Status.UNPROCESSABLE_ENTITY, data);
|
|
624
1050
|
}
|
|
625
1051
|
return result.value;
|
|
626
1052
|
}
|
|
@@ -636,19 +1062,19 @@ class Parser {
|
|
|
636
1062
|
}).join(`
|
|
637
1063
|
`);
|
|
638
1064
|
}
|
|
639
|
-
static async
|
|
1065
|
+
static async parseUrlData(params, validate) {
|
|
640
1066
|
const data = {};
|
|
641
|
-
for (const [key, value] of
|
|
642
|
-
data[key] =
|
|
1067
|
+
for (const [key, value] of Object.entries(params)) {
|
|
1068
|
+
data[key] = decodeURIComponent(value);
|
|
643
1069
|
}
|
|
644
1070
|
return await this.parse(data, validate);
|
|
645
1071
|
}
|
|
646
|
-
static async
|
|
1072
|
+
static async parseBody(r, validate) {
|
|
647
1073
|
let data;
|
|
648
1074
|
const empty = {};
|
|
649
1075
|
const input = r instanceof Request ? r : r instanceof Response ? r : r.response;
|
|
650
1076
|
try {
|
|
651
|
-
switch (
|
|
1077
|
+
switch (XParser.getNormalizedContentType(input)) {
|
|
652
1078
|
case "json":
|
|
653
1079
|
data = await this.getJsonBody(input);
|
|
654
1080
|
break;
|
|
@@ -670,7 +1096,7 @@ class Parser {
|
|
|
670
1096
|
case "image":
|
|
671
1097
|
case "audio":
|
|
672
1098
|
case "video":
|
|
673
|
-
throw new
|
|
1099
|
+
throw new CError("unprocessable.contentType", Status.UNPROCESSABLE_ENTITY);
|
|
674
1100
|
case "no-body-allowed":
|
|
675
1101
|
default:
|
|
676
1102
|
return empty;
|
|
@@ -682,23 +1108,6 @@ class Parser {
|
|
|
682
1108
|
throw err;
|
|
683
1109
|
}
|
|
684
1110
|
}
|
|
685
|
-
static async getParams(endpoint, url, validate) {
|
|
686
|
-
const data = {};
|
|
687
|
-
if (!endpoint.includes(":")) {
|
|
688
|
-
return data;
|
|
689
|
-
}
|
|
690
|
-
const defParts = endpoint.split("/");
|
|
691
|
-
const reqParts = url.pathname.split("/");
|
|
692
|
-
for (const [i, defPart] of defParts.entries()) {
|
|
693
|
-
const reqPart = reqParts[i];
|
|
694
|
-
if (defPart.startsWith(":") && reqPart !== undefined) {
|
|
695
|
-
const key = defPart.slice(1);
|
|
696
|
-
const value = this.processString(decodeURIComponent(reqPart));
|
|
697
|
-
data[key] = value;
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
return await this.parse(data, validate);
|
|
701
|
-
}
|
|
702
1111
|
static async getUnknownBody(input, validate) {
|
|
703
1112
|
if (!validate) {
|
|
704
1113
|
return await this.getTextBody(input);
|
|
@@ -720,7 +1129,7 @@ class Parser {
|
|
|
720
1129
|
const params = new URLSearchParams(text);
|
|
721
1130
|
const body = {};
|
|
722
1131
|
for (const [key, value] of params.entries()) {
|
|
723
|
-
objAppendEntry(body, key,
|
|
1132
|
+
objAppendEntry(body, key, value);
|
|
724
1133
|
}
|
|
725
1134
|
return body;
|
|
726
1135
|
}
|
|
@@ -732,7 +1141,7 @@ class Parser {
|
|
|
732
1141
|
if (value instanceof File) {
|
|
733
1142
|
body[key] = value;
|
|
734
1143
|
} else {
|
|
735
|
-
objAppendEntry(body, key,
|
|
1144
|
+
objAppendEntry(body, key, value);
|
|
736
1145
|
}
|
|
737
1146
|
}
|
|
738
1147
|
return body;
|
|
@@ -741,16 +1150,14 @@ class Parser {
|
|
|
741
1150
|
const contentLength = input.headers.get(CommonHeaders.ContentLength);
|
|
742
1151
|
const length = contentLength ? parseInt(contentLength) : 0;
|
|
743
1152
|
if (length > 0 && length < 1024 * 1024) {
|
|
744
|
-
|
|
745
|
-
return this.processString(text2);
|
|
1153
|
+
return await input.text();
|
|
746
1154
|
}
|
|
747
1155
|
const buffer = await input.arrayBuffer();
|
|
748
1156
|
const contentType = input.headers.get(CommonHeaders.ContentType) || "";
|
|
749
1157
|
const match = contentType.match(/charset=([^;]+)/i);
|
|
750
1158
|
const charset = match?.[1] ? match[1].trim() : null;
|
|
751
1159
|
const decoder = new TextDecoder(charset || "utf-8");
|
|
752
|
-
|
|
753
|
-
return this.processString(text);
|
|
1160
|
+
return decoder.decode(buffer);
|
|
754
1161
|
}
|
|
755
1162
|
static getNormalizedContentType(input) {
|
|
756
1163
|
const contentTypeHeader = input.headers.get(CommonHeaders.ContentType) || "";
|
|
@@ -787,18 +1194,13 @@ class Parser {
|
|
|
787
1194
|
}
|
|
788
1195
|
return "unknown";
|
|
789
1196
|
}
|
|
790
|
-
static processString(value) {
|
|
791
|
-
let processedValue = value;
|
|
792
|
-
if (!strIsDefined(value))
|
|
793
|
-
return "";
|
|
794
|
-
if (/^-?\d+(\.\d+)?$/.test(value)) {
|
|
795
|
-
processedValue = Number(value);
|
|
796
|
-
} else if (value.toLowerCase() === "true" || value.toLowerCase() === "false") {
|
|
797
|
-
processedValue = value.toLowerCase() === "true";
|
|
798
|
-
}
|
|
799
|
-
return processedValue;
|
|
800
|
-
}
|
|
801
1197
|
}
|
|
1198
|
+
var init_XParser = __esm(() => {
|
|
1199
|
+
init_Status();
|
|
1200
|
+
init_Method();
|
|
1201
|
+
init_CommonHeaders();
|
|
1202
|
+
init_CError();
|
|
1203
|
+
});
|
|
802
1204
|
|
|
803
1205
|
// src/Context/Context.ts
|
|
804
1206
|
class Context {
|
|
@@ -810,7 +1212,7 @@ class Context {
|
|
|
810
1212
|
this.body = body;
|
|
811
1213
|
this.search = search;
|
|
812
1214
|
this.params = params;
|
|
813
|
-
this.res = res ?? new
|
|
1215
|
+
this.res = res ?? new CResponse;
|
|
814
1216
|
}
|
|
815
1217
|
req;
|
|
816
1218
|
url;
|
|
@@ -824,67 +1226,25 @@ class Context {
|
|
|
824
1226
|
static makeFromRequest(req) {
|
|
825
1227
|
return new Context(req, {}, {}, {});
|
|
826
1228
|
}
|
|
827
|
-
static async appendParsedData(ctx, req,
|
|
828
|
-
ctx.body = await
|
|
829
|
-
ctx.
|
|
830
|
-
ctx.
|
|
1229
|
+
static async appendParsedData(ctx, req, params, search, model) {
|
|
1230
|
+
ctx.body = await XParser.parseBody(req, model?.body);
|
|
1231
|
+
ctx.params = await XParser.parseUrlData(params, model?.params);
|
|
1232
|
+
ctx.search = await XParser.parseUrlData(search, model?.search);
|
|
831
1233
|
}
|
|
832
1234
|
}
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
};
|
|
838
|
-
|
|
839
|
-
// src/utils/joinPathSegments.ts
|
|
840
|
-
function joinPathSegments(...segments) {
|
|
841
|
-
const joined = segments.map((segment) => typeof segment === "number" ? segment.toString() : segment).filter((segment) => segment !== undefined && segment !== null && segment.trim() !== "").map((segment) => segment.replace(/^\/+|\/+$/g, "")).filter((segment) => segment.length > 0).join("/");
|
|
842
|
-
return `/${joined}`;
|
|
843
|
-
}
|
|
1235
|
+
var init_Context = __esm(() => {
|
|
1236
|
+
init_CResponse();
|
|
1237
|
+
init_XParser();
|
|
1238
|
+
});
|
|
844
1239
|
|
|
845
1240
|
// src/Route/RouteAbstract.ts
|
|
846
1241
|
class RouteAbstract {
|
|
847
|
-
resolveEndpoint(definition, variant) {
|
|
848
|
-
const endpoint = typeof definition === "string" ? definition : definition.path;
|
|
849
|
-
if (variant === RouteVariant.dynamic) {
|
|
850
|
-
return joinPathSegments(_globalPrefix.get(), endpoint);
|
|
851
|
-
}
|
|
852
|
-
return endpoint;
|
|
853
|
-
}
|
|
854
|
-
resolveMethod(definition) {
|
|
855
|
-
return typeof definition === "string" ? Method.GET : definition.method;
|
|
856
|
-
}
|
|
857
1242
|
resolvePattern(endpoint) {
|
|
858
|
-
return
|
|
1243
|
+
return RouteAbstract.makeRoutePattern(endpoint);
|
|
859
1244
|
}
|
|
860
1245
|
resolveId(method, endpoint) {
|
|
861
|
-
return
|
|
1246
|
+
return RouteAbstract.makeRouteId(method, endpoint);
|
|
862
1247
|
}
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
// src/Route/Route.ts
|
|
866
|
-
class Route extends RouteAbstract {
|
|
867
|
-
constructor(definition, handler, model) {
|
|
868
|
-
super();
|
|
869
|
-
this.variant = RouteVariant.dynamic;
|
|
870
|
-
this.endpoint = this.resolveEndpoint(definition, this.variant);
|
|
871
|
-
this.method = this.resolveMethod(definition);
|
|
872
|
-
this.pattern = this.resolvePattern(this.endpoint);
|
|
873
|
-
this.id = this.resolveId(this.method, this.endpoint);
|
|
874
|
-
this.model = model;
|
|
875
|
-
this.handler = handler;
|
|
876
|
-
_router.get().addRoute(this);
|
|
877
|
-
if (model) {
|
|
878
|
-
_router.get().addModel(this.id, model);
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
variant;
|
|
882
|
-
endpoint;
|
|
883
|
-
method;
|
|
884
|
-
pattern;
|
|
885
|
-
id;
|
|
886
|
-
handler;
|
|
887
|
-
model;
|
|
888
1248
|
static makeRouteId(method, endpoint) {
|
|
889
1249
|
return `${method.toUpperCase()} ${endpoint}`;
|
|
890
1250
|
}
|
|
@@ -894,113 +1254,134 @@ class Route extends RouteAbstract {
|
|
|
894
1254
|
}
|
|
895
1255
|
}
|
|
896
1256
|
|
|
897
|
-
// src/
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
const file = await this.find(address);
|
|
902
|
-
if (!file)
|
|
903
|
-
return null;
|
|
904
|
-
return await file.text();
|
|
905
|
-
} catch {
|
|
906
|
-
return null;
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
static async exists(address) {
|
|
910
|
-
return await this.find(address) !== null;
|
|
911
|
-
}
|
|
912
|
-
static getExtension(address) {
|
|
913
|
-
return address.split(".").pop() ?? "txt";
|
|
914
|
-
}
|
|
915
|
-
static async find(address) {
|
|
916
|
-
const file = Bun.file(address);
|
|
917
|
-
const exists = await file.exists();
|
|
918
|
-
if (exists) {
|
|
919
|
-
return { text: () => file.text() };
|
|
920
|
-
}
|
|
921
|
-
return null;
|
|
922
|
-
}
|
|
1257
|
+
// src/utils/joinPathSegments.ts
|
|
1258
|
+
function joinPathSegments(...segments) {
|
|
1259
|
+
const joined = segments.map((segment) => typeof segment === "number" ? segment.toString() : segment).filter((segment) => segment !== undefined && segment !== null && segment.trim() !== "").map((segment) => segment.replace(/^\/+|\/+$/g, "")).filter((segment) => segment.length > 0).join("/");
|
|
1260
|
+
return `/${joined}`;
|
|
923
1261
|
}
|
|
924
1262
|
|
|
925
|
-
// src/
|
|
926
|
-
|
|
927
|
-
|
|
1263
|
+
// src/Route/enums/RouteVariant.ts
|
|
1264
|
+
var RouteVariant;
|
|
1265
|
+
var init_RouteVariant = __esm(() => {
|
|
1266
|
+
RouteVariant = {
|
|
1267
|
+
static: "static",
|
|
1268
|
+
dynamic: "dynamic",
|
|
1269
|
+
websocket: "websocket"
|
|
1270
|
+
};
|
|
1271
|
+
});
|
|
928
1272
|
|
|
929
|
-
// src/
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
const content = await this.defaultHandler(c);
|
|
944
|
-
return handler(c, content);
|
|
945
|
-
};
|
|
946
|
-
} else {
|
|
947
|
-
this.handler = this.defaultHandler;
|
|
948
|
-
}
|
|
949
|
-
_router.get().addRoute(this);
|
|
950
|
-
}
|
|
951
|
-
id;
|
|
952
|
-
variant;
|
|
953
|
-
method;
|
|
954
|
-
endpoint;
|
|
955
|
-
pattern;
|
|
956
|
-
model;
|
|
957
|
-
handler;
|
|
958
|
-
defaultHandler = async (c) => {
|
|
959
|
-
const content = await this.getContent();
|
|
960
|
-
c.res.headers.set(CommonHeaders.ContentType, this.mimeTypes[this.extension] || "application/octet-stream");
|
|
961
|
-
c.res.headers.set(CommonHeaders.ContentLength, content.length.toString());
|
|
962
|
-
return content;
|
|
1273
|
+
// src/DynamicRoute/DynamicRouteAbstract.ts
|
|
1274
|
+
var DynamicRouteAbstract;
|
|
1275
|
+
var init_DynamicRouteAbstract = __esm(() => {
|
|
1276
|
+
init_Method();
|
|
1277
|
+
init_src();
|
|
1278
|
+
init_RouteVariant();
|
|
1279
|
+
DynamicRouteAbstract = class DynamicRouteAbstract extends RouteAbstract {
|
|
1280
|
+
variant = RouteVariant.dynamic;
|
|
1281
|
+
resolveEndpoint(definition) {
|
|
1282
|
+
return joinPathSegments($prefixStore.get(), typeof definition === "string" ? definition : definition.path);
|
|
1283
|
+
}
|
|
1284
|
+
resolveMethod(definition) {
|
|
1285
|
+
return typeof definition === "string" ? Method.GET : definition.method;
|
|
1286
|
+
}
|
|
963
1287
|
};
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
ico: "image/x-icon",
|
|
989
|
-
txt: "text/plain",
|
|
990
|
-
xml: "application/xml",
|
|
991
|
-
pdf: "application/pdf",
|
|
992
|
-
zip: "application/zip",
|
|
993
|
-
mp3: "audio/mpeg",
|
|
994
|
-
mp4: "video/mp4",
|
|
995
|
-
webm: "video/webm",
|
|
996
|
-
woff: "font/woff",
|
|
997
|
-
woff2: "font/woff2",
|
|
998
|
-
ttf: "font/ttf"
|
|
1288
|
+
});
|
|
1289
|
+
|
|
1290
|
+
// src/DynamicRoute/DynamicRoute.ts
|
|
1291
|
+
var DynamicRoute;
|
|
1292
|
+
var init_DynamicRoute = __esm(() => {
|
|
1293
|
+
init_src();
|
|
1294
|
+
init_DynamicRouteAbstract();
|
|
1295
|
+
DynamicRoute = class DynamicRoute extends DynamicRouteAbstract {
|
|
1296
|
+
constructor(definition, handler, model) {
|
|
1297
|
+
super();
|
|
1298
|
+
this.endpoint = this.resolveEndpoint(definition);
|
|
1299
|
+
this.method = this.resolveMethod(definition);
|
|
1300
|
+
this.pattern = this.resolvePattern(this.endpoint);
|
|
1301
|
+
this.id = this.resolveId(this.method, this.endpoint);
|
|
1302
|
+
this.model = model;
|
|
1303
|
+
this.handler = handler;
|
|
1304
|
+
$routerStore.get().addRoute(this);
|
|
1305
|
+
}
|
|
1306
|
+
id;
|
|
1307
|
+
method;
|
|
1308
|
+
endpoint;
|
|
1309
|
+
pattern;
|
|
1310
|
+
handler;
|
|
1311
|
+
model;
|
|
999
1312
|
};
|
|
1000
|
-
}
|
|
1313
|
+
});
|
|
1314
|
+
|
|
1315
|
+
// src/StaticRoute/StaticRouteAbstract.ts
|
|
1316
|
+
var StaticRouteAbstract;
|
|
1317
|
+
var init_StaticRouteAbstract = __esm(() => {
|
|
1318
|
+
init_CError();
|
|
1319
|
+
init_CommonHeaders();
|
|
1320
|
+
init_CResponse();
|
|
1321
|
+
init_Status();
|
|
1322
|
+
init_RouteVariant();
|
|
1323
|
+
init_internalLogger();
|
|
1324
|
+
init_XFile();
|
|
1325
|
+
StaticRouteAbstract = class StaticRouteAbstract extends RouteAbstract {
|
|
1326
|
+
variant = RouteVariant.static;
|
|
1327
|
+
resolveFilePath(definition) {
|
|
1328
|
+
return typeof definition === "string" ? definition : definition.filePath;
|
|
1329
|
+
}
|
|
1330
|
+
resolveHandler(definition, customHandler) {
|
|
1331
|
+
if (customHandler !== undefined) {
|
|
1332
|
+
return async (c) => {
|
|
1333
|
+
const file = new XFile(this.filePath);
|
|
1334
|
+
const exists = await file.exists();
|
|
1335
|
+
if (!exists) {
|
|
1336
|
+
log.error("File not found at:", this.filePath);
|
|
1337
|
+
throw new CError(Status.NOT_FOUND.toString(), Status.NOT_FOUND);
|
|
1338
|
+
}
|
|
1339
|
+
const content = await file.text();
|
|
1340
|
+
c.res.headers.setMany({
|
|
1341
|
+
[CommonHeaders.ContentType]: file.mimeType,
|
|
1342
|
+
[CommonHeaders.ContentLength]: content.length.toString()
|
|
1343
|
+
});
|
|
1344
|
+
return customHandler(c, content);
|
|
1345
|
+
};
|
|
1346
|
+
} else if (typeof definition === "string") {
|
|
1347
|
+
return async () => await CResponse.file(this.filePath);
|
|
1348
|
+
} else {
|
|
1349
|
+
return async () => await CResponse.streamFile(this.filePath);
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
};
|
|
1353
|
+
});
|
|
1354
|
+
|
|
1355
|
+
// src/StaticRoute/StaticRoute.ts
|
|
1356
|
+
var StaticRoute;
|
|
1357
|
+
var init_StaticRoute = __esm(() => {
|
|
1358
|
+
init_Method();
|
|
1359
|
+
init_src();
|
|
1360
|
+
init_StaticRouteAbstract();
|
|
1361
|
+
StaticRoute = class StaticRoute extends StaticRouteAbstract {
|
|
1362
|
+
constructor(path2, definition, handler, model) {
|
|
1363
|
+
super();
|
|
1364
|
+
this.endpoint = path2;
|
|
1365
|
+
this.method = Method.GET;
|
|
1366
|
+
this.pattern = this.resolvePattern(this.endpoint);
|
|
1367
|
+
this.id = this.resolveId(this.method, this.endpoint);
|
|
1368
|
+
this.model = model;
|
|
1369
|
+
this.filePath = this.resolveFilePath(definition);
|
|
1370
|
+
this.handler = this.resolveHandler(definition, handler);
|
|
1371
|
+
$routerStore.get().addRoute(this);
|
|
1372
|
+
}
|
|
1373
|
+
id;
|
|
1374
|
+
method;
|
|
1375
|
+
endpoint;
|
|
1376
|
+
pattern;
|
|
1377
|
+
handler;
|
|
1378
|
+
model;
|
|
1379
|
+
filePath;
|
|
1380
|
+
};
|
|
1381
|
+
});
|
|
1001
1382
|
|
|
1002
|
-
// src/Controller/
|
|
1003
|
-
class
|
|
1383
|
+
// src/Controller/Controller.ts
|
|
1384
|
+
class Controller {
|
|
1004
1385
|
constructor(opts) {
|
|
1005
1386
|
this.prefix = opts?.prefix;
|
|
1006
1387
|
this.beforeEach = opts?.beforeEach;
|
|
@@ -1010,7 +1391,7 @@ class ControllerAbstract {
|
|
|
1010
1391
|
beforeEach;
|
|
1011
1392
|
route(...args) {
|
|
1012
1393
|
const [definition, handler, model] = args;
|
|
1013
|
-
const route = new
|
|
1394
|
+
const route = new DynamicRoute(this.resolveRouteDefinition(definition), async (ctx) => {
|
|
1014
1395
|
await this.beforeEach?.(ctx);
|
|
1015
1396
|
return handler(ctx);
|
|
1016
1397
|
}, model);
|
|
@@ -1033,157 +1414,142 @@ class ControllerAbstract {
|
|
|
1033
1414
|
};
|
|
1034
1415
|
}
|
|
1035
1416
|
}
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
this.handler = opts.handler;
|
|
1041
|
-
_router.get().addMiddleware(opts);
|
|
1042
|
-
}
|
|
1043
|
-
useOn;
|
|
1044
|
-
handler;
|
|
1045
|
-
}
|
|
1046
|
-
// src/Repository/RepositoryAbstract.ts
|
|
1047
|
-
class RepositoryAbstract {
|
|
1048
|
-
db;
|
|
1049
|
-
constructor(db) {
|
|
1050
|
-
this.db = db;
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
// src/utils/assert.ts
|
|
1054
|
-
function assert(condition, message) {
|
|
1055
|
-
const conditionName = String(condition);
|
|
1056
|
-
if (!condition) {
|
|
1057
|
-
if (!message) {
|
|
1058
|
-
message = `Assertion failed for ${conditionName}`;
|
|
1059
|
-
} else {
|
|
1060
|
-
message = `${conditionName}: ${message}`;
|
|
1061
|
-
}
|
|
1062
|
-
throw new Error(message);
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1417
|
+
var init_Controller = __esm(() => {
|
|
1418
|
+
init_DynamicRoute();
|
|
1419
|
+
init_StaticRoute();
|
|
1420
|
+
});
|
|
1065
1421
|
|
|
1066
|
-
// src/
|
|
1067
|
-
|
|
1068
|
-
const parts = input.split(mark).map((part) => part.trim()).filter(Boolean);
|
|
1069
|
-
if (minLength) {
|
|
1070
|
-
assert(parts.length >= minLength);
|
|
1071
|
-
return parts;
|
|
1072
|
-
}
|
|
1073
|
-
return parts;
|
|
1422
|
+
// src/Middleware/MiddlewareAbstract.ts
|
|
1423
|
+
class MiddlewareAbstract {
|
|
1074
1424
|
}
|
|
1075
1425
|
|
|
1076
|
-
// src/
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1426
|
+
// src/Middleware/Middleware.ts
|
|
1427
|
+
var Middleware;
|
|
1428
|
+
var init_Middleware = __esm(() => {
|
|
1429
|
+
init_src();
|
|
1430
|
+
Middleware = class Middleware extends MiddlewareAbstract {
|
|
1431
|
+
constructor(opts) {
|
|
1432
|
+
super();
|
|
1433
|
+
this.useOn = opts.useOn;
|
|
1434
|
+
this.handler = opts.handler;
|
|
1435
|
+
$routerStore.get().addMiddleware(this);
|
|
1436
|
+
}
|
|
1437
|
+
useOn;
|
|
1438
|
+
handler;
|
|
1439
|
+
};
|
|
1440
|
+
});
|
|
1441
|
+
|
|
1442
|
+
// src/CRequest/CRequest.ts
|
|
1443
|
+
var CRequest;
|
|
1444
|
+
var init_CRequest = __esm(() => {
|
|
1445
|
+
init_Method();
|
|
1446
|
+
init_CommonHeaders();
|
|
1447
|
+
init_Cookies();
|
|
1448
|
+
init_CHeaders();
|
|
1449
|
+
init_strSplit();
|
|
1450
|
+
CRequest = class CRequest extends Request {
|
|
1451
|
+
info;
|
|
1452
|
+
init;
|
|
1453
|
+
constructor(info, init) {
|
|
1454
|
+
super(info, init);
|
|
1455
|
+
this.info = info;
|
|
1456
|
+
this.init = init;
|
|
1457
|
+
this.urlObject = this.resolveUrlObject();
|
|
1458
|
+
this.headers = this.resolveHeaders();
|
|
1459
|
+
this.cookies = this.resolveCookies();
|
|
1460
|
+
this.isPreflight = this.resolveIsPreflight();
|
|
1461
|
+
this.isWebsocket = this.resolveIsWebsocketUpgrade();
|
|
1462
|
+
}
|
|
1463
|
+
urlObject;
|
|
1464
|
+
isPreflight;
|
|
1465
|
+
isWebsocket;
|
|
1466
|
+
cookies;
|
|
1467
|
+
headers;
|
|
1468
|
+
resolveUrlObject() {
|
|
1469
|
+
let urlObject;
|
|
1470
|
+
switch (true) {
|
|
1471
|
+
case this.info instanceof URL:
|
|
1472
|
+
urlObject = this.info;
|
|
1473
|
+
break;
|
|
1474
|
+
case this.info instanceof CRequest:
|
|
1475
|
+
urlObject = this.info.urlObject;
|
|
1476
|
+
break;
|
|
1477
|
+
case this.info instanceof Request:
|
|
1478
|
+
urlObject = new URL(this.info.url);
|
|
1479
|
+
break;
|
|
1480
|
+
default:
|
|
1481
|
+
urlObject = new URL(this.info);
|
|
1482
|
+
break;
|
|
1133
1483
|
}
|
|
1484
|
+
if (!urlObject.pathname) {
|
|
1485
|
+
urlObject.pathname += "/";
|
|
1486
|
+
}
|
|
1487
|
+
return urlObject;
|
|
1134
1488
|
}
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
}
|
|
1158
|
-
originKey = "Access-Control-Allow-Origin";
|
|
1159
|
-
methodsKey = "Access-Control-Allow-Methods";
|
|
1160
|
-
headersKey = "Access-Control-Allow-Headers";
|
|
1161
|
-
credentialsKey = "Access-Control-Allow-Credentials";
|
|
1162
|
-
getCorsHeaders(req, res) {
|
|
1163
|
-
const reqOrigin = req.headers.get("origin") ?? "";
|
|
1164
|
-
const { allowedOrigins, allowedMethods, allowedHeaders, credentials } = this.opts;
|
|
1165
|
-
if (isSomeArray(allowedOrigins) && allowedOrigins.includes(reqOrigin)) {
|
|
1166
|
-
res.headers.set(this.originKey, reqOrigin);
|
|
1489
|
+
resolveHeaders() {
|
|
1490
|
+
if (this.init?.headers !== undefined) {
|
|
1491
|
+
return new CHeaders(this.init.headers);
|
|
1492
|
+
}
|
|
1493
|
+
if (this.info instanceof Request || this.info instanceof CRequest) {
|
|
1494
|
+
return new CHeaders(this.info.headers);
|
|
1495
|
+
}
|
|
1496
|
+
return new CHeaders;
|
|
1497
|
+
}
|
|
1498
|
+
resolveCookies() {
|
|
1499
|
+
const jar = new Cookies;
|
|
1500
|
+
const cookieHeader = this.headers.get(CommonHeaders.Cookie);
|
|
1501
|
+
if (cookieHeader) {
|
|
1502
|
+
const pairs = strSplit(";", cookieHeader);
|
|
1503
|
+
for (const pair of pairs) {
|
|
1504
|
+
const [name, value] = strSplit("=", pair);
|
|
1505
|
+
if (!name || !value)
|
|
1506
|
+
continue;
|
|
1507
|
+
jar.set({ name, value });
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
return jar;
|
|
1167
1511
|
}
|
|
1168
|
-
|
|
1169
|
-
|
|
1512
|
+
resolveIsPreflight() {
|
|
1513
|
+
return this.method === Method.OPTIONS && this.headers.has(CommonHeaders.AccessControlRequestMethod);
|
|
1170
1514
|
}
|
|
1171
|
-
|
|
1172
|
-
|
|
1515
|
+
resolveIsWebsocketUpgrade() {
|
|
1516
|
+
const isUpgrade = this.headers.get(CommonHeaders.Connection)?.toLowerCase() === "upgrade";
|
|
1517
|
+
const isWebsocket = this.headers.get(CommonHeaders.Upgrade)?.toLowerCase() === "websocket";
|
|
1518
|
+
return isUpgrade && isWebsocket;
|
|
1173
1519
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
}
|
|
1177
|
-
apply(req, res) {
|
|
1178
|
-
const headers = this.getCorsHeaders(req, res);
|
|
1179
|
-
res.headers.innerCombine(headers);
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1520
|
+
};
|
|
1521
|
+
});
|
|
1182
1522
|
|
|
1183
|
-
// src/
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1523
|
+
// src/WebSocketRoute/WebSocketRoute.ts
|
|
1524
|
+
var WebSocketRoute;
|
|
1525
|
+
var init_WebSocketRoute = __esm(() => {
|
|
1526
|
+
init_src();
|
|
1527
|
+
init_Method();
|
|
1528
|
+
init_RouteVariant();
|
|
1529
|
+
WebSocketRoute = class WebSocketRoute extends RouteAbstract {
|
|
1530
|
+
constructor(path2, handlers) {
|
|
1531
|
+
super();
|
|
1532
|
+
this.endpoint = path2;
|
|
1533
|
+
this.method = Method.GET;
|
|
1534
|
+
this.pattern = this.resolvePattern(this.endpoint);
|
|
1535
|
+
this.id = this.resolveId(this.method, this.endpoint);
|
|
1536
|
+
this.onOpen = handlers.onOpen;
|
|
1537
|
+
this.onClose = handlers.onClose;
|
|
1538
|
+
this.onMessage = handlers.onMessage;
|
|
1539
|
+
$routerStore.get().addRoute(this);
|
|
1540
|
+
}
|
|
1541
|
+
id;
|
|
1542
|
+
method;
|
|
1543
|
+
endpoint;
|
|
1544
|
+
pattern;
|
|
1545
|
+
model;
|
|
1546
|
+
handler = () => this;
|
|
1547
|
+
variant = RouteVariant.websocket;
|
|
1548
|
+
onOpen;
|
|
1549
|
+
onClose;
|
|
1550
|
+
onMessage;
|
|
1551
|
+
};
|
|
1552
|
+
});
|
|
1187
1553
|
|
|
1188
1554
|
// src/utils/isRegexMatch.ts
|
|
1189
1555
|
function isRegexMatch(source, pattern) {
|
|
@@ -1210,39 +1576,44 @@ class CorpusAdapter {
|
|
|
1210
1576
|
this.checkPossibleCollision(data);
|
|
1211
1577
|
this.routes.set(data.id, data);
|
|
1212
1578
|
}
|
|
1213
|
-
find(
|
|
1579
|
+
find(req) {
|
|
1580
|
+
const method = req.method;
|
|
1581
|
+
const pathname = req.urlObject.pathname;
|
|
1582
|
+
const searchParams = req.urlObject.searchParams;
|
|
1214
1583
|
let route = null;
|
|
1215
1584
|
for (const data of this.routes.values()) {
|
|
1216
|
-
|
|
1217
|
-
|
|
1585
|
+
if (method !== data.method)
|
|
1586
|
+
continue;
|
|
1587
|
+
if (this.hasAnyParam(data.endpoint) && isRegexMatch(pathname, data.pattern)) {
|
|
1218
1588
|
route = data;
|
|
1219
1589
|
break;
|
|
1220
1590
|
}
|
|
1221
|
-
if (this.hasLastPartParam(endpoint) && strIsEqual(this.removeLastParam(endpoint),
|
|
1591
|
+
if (this.hasLastPartParam(data.endpoint) && strIsEqual(this.removeLastParam(data.endpoint), pathname, "lower")) {
|
|
1222
1592
|
route = data;
|
|
1223
1593
|
break;
|
|
1224
1594
|
}
|
|
1225
|
-
if (strIsEqual(endpoint,
|
|
1595
|
+
if (strIsEqual(data.endpoint, pathname)) {
|
|
1226
1596
|
route = data;
|
|
1227
1597
|
break;
|
|
1228
1598
|
}
|
|
1229
1599
|
}
|
|
1230
1600
|
if (route === null) {
|
|
1231
|
-
|
|
1232
|
-
}
|
|
1233
|
-
if (!strIsEqual(method, route.method, "upper")) {
|
|
1234
|
-
throw HttpError.methodNotAllowed();
|
|
1601
|
+
return null;
|
|
1235
1602
|
}
|
|
1236
|
-
return {
|
|
1603
|
+
return {
|
|
1604
|
+
route,
|
|
1605
|
+
params: this.extractParams(pathname, route.endpoint),
|
|
1606
|
+
search: Object.fromEntries(searchParams)
|
|
1607
|
+
};
|
|
1237
1608
|
}
|
|
1238
1609
|
list() {
|
|
1239
1610
|
return Array.from(this.routes.values());
|
|
1240
1611
|
}
|
|
1241
1612
|
checkPossibleCollision(n) {
|
|
1242
|
-
const dupeMsg = (nId) =>
|
|
1243
|
-
const dynamicPatternMsg = (nId, oId) =>
|
|
1244
|
-
const baseDupeMsg = (nId, oId) =>
|
|
1245
|
-
const shadowMsg = (nId, oId) =>
|
|
1613
|
+
const dupeMsg = (nId) => log.error(`Duplicate route detected. ${nId} has already been registered.`);
|
|
1614
|
+
const dynamicPatternMsg = (nId, oId) => log.error(`Ambiguous dynamic routes. ${nId} and ${oId} match the same URL patterns.`);
|
|
1615
|
+
const baseDupeMsg = (nId, oId) => log.error(`Dynamic route overlaps existing route. ${nId} \u2014 dropping the last param segment matches ${oId}.`);
|
|
1616
|
+
const shadowMsg = (nId, oId) => log.error(`Route shadowed by existing dynamic route. ${nId} will be unreachable \u2014 ${oId} captures the same URL space.`);
|
|
1246
1617
|
const existing = this.routes.get(n.id);
|
|
1247
1618
|
if (existing) {
|
|
1248
1619
|
dupeMsg(n.id);
|
|
@@ -1267,7 +1638,7 @@ class CorpusAdapter {
|
|
|
1267
1638
|
}
|
|
1268
1639
|
const oHasLastPartParam = this.hasLastPartParam(o.endpoint);
|
|
1269
1640
|
if (oHasLastPartParam) {
|
|
1270
|
-
if (isRegexMatch(n.endpoint,
|
|
1641
|
+
if (isRegexMatch(n.endpoint, DynamicRoute.makeRoutePattern(this.removeLastParam(o.endpoint)))) {
|
|
1271
1642
|
shadowMsg(n.id, o.id);
|
|
1272
1643
|
return true;
|
|
1273
1644
|
}
|
|
@@ -1275,6 +1646,20 @@ class CorpusAdapter {
|
|
|
1275
1646
|
}
|
|
1276
1647
|
return false;
|
|
1277
1648
|
}
|
|
1649
|
+
extractParams(pathname, endpoint) {
|
|
1650
|
+
const data = {};
|
|
1651
|
+
if (!this.hasAnyParam(endpoint))
|
|
1652
|
+
return data;
|
|
1653
|
+
const defParts = endpoint.split("/");
|
|
1654
|
+
const reqParts = pathname.split("/");
|
|
1655
|
+
for (const [i, defPart] of defParts.entries()) {
|
|
1656
|
+
const reqPart = reqParts[i];
|
|
1657
|
+
if (defPart.startsWith(":") && reqPart !== undefined) {
|
|
1658
|
+
data[defPart.slice(1)] = decodeURIComponent(reqPart);
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
return data;
|
|
1662
|
+
}
|
|
1278
1663
|
hasLastPartParam(endpoint) {
|
|
1279
1664
|
if (!this.hasAnyParam(endpoint))
|
|
1280
1665
|
return false;
|
|
@@ -1292,196 +1677,258 @@ class CorpusAdapter {
|
|
|
1292
1677
|
return endpoint.split("/").some((p) => p.startsWith(":"));
|
|
1293
1678
|
}
|
|
1294
1679
|
}
|
|
1680
|
+
var init_CorpusAdapter = __esm(() => {
|
|
1681
|
+
init_DynamicRoute();
|
|
1682
|
+
init_internalLogger();
|
|
1683
|
+
});
|
|
1295
1684
|
|
|
1296
|
-
// src/
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1685
|
+
// src/utils/LazyMap.ts
|
|
1686
|
+
var LazyMap;
|
|
1687
|
+
var init_LazyMap = __esm(() => {
|
|
1688
|
+
LazyMap = class LazyMap {
|
|
1689
|
+
constructor() {
|
|
1690
|
+
return new Proxy(this, {
|
|
1691
|
+
get(target, prop) {
|
|
1692
|
+
const val = Reflect.get(target.map, prop);
|
|
1693
|
+
return typeof val === "function" ? val.bind(target.map) : val;
|
|
1694
|
+
}
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
_map;
|
|
1698
|
+
get map() {
|
|
1699
|
+
if (!this._map) {
|
|
1700
|
+
this._map = new Map;
|
|
1303
1701
|
}
|
|
1304
|
-
|
|
1305
|
-
}
|
|
1306
|
-
_map;
|
|
1307
|
-
get map() {
|
|
1308
|
-
if (!this._map) {
|
|
1309
|
-
this._map = new Map;
|
|
1702
|
+
return this._map;
|
|
1310
1703
|
}
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1704
|
+
get [Symbol.toStringTag]() {
|
|
1705
|
+
return "LazyMap";
|
|
1706
|
+
}
|
|
1707
|
+
};
|
|
1708
|
+
});
|
|
1709
|
+
|
|
1710
|
+
// src/utils/strRemoveWhitespace.ts
|
|
1711
|
+
function strRemoveWhitespace(str) {
|
|
1712
|
+
return str.trim().replace(/\s+/g, "");
|
|
1316
1713
|
}
|
|
1317
1714
|
|
|
1318
|
-
// src/Router/
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1715
|
+
// src/Router/registries/ModelRegistry.ts
|
|
1716
|
+
var ModelRegistry;
|
|
1717
|
+
var init_ModelRegistry = __esm(() => {
|
|
1718
|
+
init_LazyMap();
|
|
1719
|
+
ModelRegistry = class ModelRegistry {
|
|
1720
|
+
map = new LazyMap;
|
|
1721
|
+
add(routeId, model) {
|
|
1722
|
+
const entry = ModelRegistry.toRouterModelData(model);
|
|
1723
|
+
this.map.set(routeId, entry);
|
|
1724
|
+
}
|
|
1725
|
+
find(routeId) {
|
|
1726
|
+
return this.map.get(routeId);
|
|
1727
|
+
}
|
|
1728
|
+
static internFuncMap = new LazyMap;
|
|
1729
|
+
static toRouterModelData(model) {
|
|
1730
|
+
const entry = {};
|
|
1731
|
+
for (const k of Object.keys(model)) {
|
|
1732
|
+
const key = k;
|
|
1733
|
+
const schema = model[key];
|
|
1734
|
+
if (!schema)
|
|
1735
|
+
continue;
|
|
1736
|
+
const handler = schema["~standard"].validate;
|
|
1737
|
+
entry[key] = this.intern(handler, "model", strRemoveWhitespace(JSON.stringify(schema)));
|
|
1738
|
+
}
|
|
1739
|
+
return entry;
|
|
1331
1740
|
}
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1741
|
+
static intern(value, ...namespace) {
|
|
1742
|
+
const key = namespace.join("::");
|
|
1743
|
+
const existing = this.internFuncMap.get(key);
|
|
1744
|
+
if (existing)
|
|
1745
|
+
return existing;
|
|
1746
|
+
this.internFuncMap.set(key, value);
|
|
1747
|
+
return value;
|
|
1748
|
+
}
|
|
1749
|
+
};
|
|
1750
|
+
});
|
|
1751
|
+
|
|
1752
|
+
// src/utils/compile.ts
|
|
1753
|
+
function compile(fns) {
|
|
1754
|
+
return async (...args) => {
|
|
1755
|
+
for (const fn of fns) {
|
|
1756
|
+
if (!fn)
|
|
1340
1757
|
continue;
|
|
1341
|
-
|
|
1342
|
-
entry[key] = this.intern(handler, "model", strRemoveWhitespace(JSON.stringify(schema)));
|
|
1758
|
+
await fn(...args);
|
|
1343
1759
|
}
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
const
|
|
1352
|
-
if (
|
|
1760
|
+
};
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
// src/Router/registries/MiddlewareRegistry.ts
|
|
1764
|
+
class MiddlewareRegistry {
|
|
1765
|
+
middlewares = new LazyMap;
|
|
1766
|
+
add(middleware) {
|
|
1767
|
+
const resolved = MiddlewareRegistry.resolveRouteIds(middleware);
|
|
1768
|
+
if (resolved.isGlobal) {
|
|
1353
1769
|
const existing = this.middlewares.get("*") ?? [];
|
|
1354
|
-
this.middlewares.set("*", [...existing, handler]);
|
|
1770
|
+
this.middlewares.set("*", [...existing, middleware.handler]);
|
|
1355
1771
|
return;
|
|
1356
1772
|
}
|
|
1357
|
-
for (const
|
|
1358
|
-
const
|
|
1359
|
-
|
|
1360
|
-
const existing = this.middlewares.get(routeId) ?? [];
|
|
1361
|
-
this.middlewares.set(routeId, [...existing, handler]);
|
|
1362
|
-
}
|
|
1773
|
+
for (const routeId of resolved.routeIds) {
|
|
1774
|
+
const existing = this.middlewares.get(routeId) ?? [];
|
|
1775
|
+
this.middlewares.set(routeId, [...existing, middleware.handler]);
|
|
1363
1776
|
}
|
|
1364
1777
|
}
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
const locals = this.middlewares.get(routeId) ?? [];
|
|
1368
|
-
return this.compile([...globals, ...locals]);
|
|
1778
|
+
find(routeId) {
|
|
1779
|
+
return compile(this.middlewares.get(routeId) ?? []);
|
|
1369
1780
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1781
|
+
static resolveRouteIds(m) {
|
|
1782
|
+
if (m.useOn === "*")
|
|
1783
|
+
return { isGlobal: true };
|
|
1784
|
+
const targets = Array.isArray(m.useOn) ? m.useOn : [m.useOn];
|
|
1785
|
+
const routeIds = [];
|
|
1786
|
+
for (const target of targets) {
|
|
1787
|
+
if (target instanceof DynamicRoute) {
|
|
1788
|
+
routeIds.push(target.id);
|
|
1789
|
+
} else if (target instanceof Controller) {
|
|
1790
|
+
routeIds.push(...target.routeIds);
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
return { isGlobal: false, routeIds };
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
var init_MiddlewareRegistry = __esm(() => {
|
|
1797
|
+
init_Controller();
|
|
1798
|
+
init_DynamicRoute();
|
|
1799
|
+
init_LazyMap();
|
|
1800
|
+
});
|
|
1801
|
+
|
|
1802
|
+
// src/Router/Router.ts
|
|
1803
|
+
class Router {
|
|
1804
|
+
adapter;
|
|
1805
|
+
constructor(adapter = new CorpusAdapter) {
|
|
1806
|
+
this.adapter = adapter;
|
|
1807
|
+
}
|
|
1808
|
+
modelRegistry = new ModelRegistry;
|
|
1809
|
+
middlewareRegistry = new MiddlewareRegistry;
|
|
1810
|
+
cache = new WeakMap;
|
|
1811
|
+
addMiddleware(middleware) {
|
|
1812
|
+
this.middlewareRegistry.add(middleware);
|
|
1813
|
+
}
|
|
1814
|
+
findMiddleware(id) {
|
|
1815
|
+
return this.middlewareRegistry.find(id);
|
|
1816
|
+
}
|
|
1817
|
+
addRoute(route) {
|
|
1818
|
+
this.adapter.add({
|
|
1819
|
+
id: route.id,
|
|
1820
|
+
endpoint: route.endpoint,
|
|
1821
|
+
method: route.method,
|
|
1822
|
+
handler: route.handler,
|
|
1823
|
+
pattern: route.pattern,
|
|
1824
|
+
variant: route.variant
|
|
1377
1825
|
});
|
|
1826
|
+
if (route.model) {
|
|
1827
|
+
this.modelRegistry.add(route.id, route.model);
|
|
1828
|
+
}
|
|
1378
1829
|
}
|
|
1379
1830
|
findRouteHandler(req) {
|
|
1380
|
-
const
|
|
1381
|
-
if (cached)
|
|
1382
|
-
return cached;
|
|
1383
|
-
const match = this._adapter.find(req.method, req.urlObject.pathname);
|
|
1831
|
+
const match = this.cache.get(req) ?? this.adapter.find(req);
|
|
1384
1832
|
if (!match)
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
const
|
|
1388
|
-
const
|
|
1389
|
-
|
|
1390
|
-
await
|
|
1391
|
-
await Context.appendParsedData(ctx, req, match.
|
|
1392
|
-
const
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
});
|
|
1399
|
-
};
|
|
1400
|
-
this.cache.set(req, handler);
|
|
1401
|
-
return handler;
|
|
1402
|
-
}
|
|
1403
|
-
getRouteList() {
|
|
1404
|
-
return this._adapter.list().map((v) => [v.method, v.endpoint]);
|
|
1405
|
-
}
|
|
1406
|
-
compile(fns) {
|
|
1407
|
-
return async (...args) => {
|
|
1408
|
-
for (const fn of fns) {
|
|
1409
|
-
if (!fn)
|
|
1410
|
-
continue;
|
|
1411
|
-
await fn(...args);
|
|
1833
|
+
return null;
|
|
1834
|
+
this.cache.set(req, match);
|
|
1835
|
+
const model = this.modelRegistry.find(match.route.id);
|
|
1836
|
+
const middleware = this.middlewareRegistry.find(match.route.id);
|
|
1837
|
+
return async (ctx) => {
|
|
1838
|
+
await middleware(ctx);
|
|
1839
|
+
await Context.appendParsedData(ctx, req, match.params, match.search, model);
|
|
1840
|
+
const result = await match.route.handler(ctx);
|
|
1841
|
+
if (result instanceof WebSocketRoute) {
|
|
1842
|
+
return result;
|
|
1843
|
+
}
|
|
1844
|
+
if (result instanceof CResponse) {
|
|
1845
|
+
return result;
|
|
1412
1846
|
}
|
|
1847
|
+
return new CResponse(result, ctx.res);
|
|
1413
1848
|
};
|
|
1414
1849
|
}
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
const existing = this.internFuncMap.get(key);
|
|
1418
|
-
if (existing)
|
|
1419
|
-
return existing;
|
|
1420
|
-
this.internFuncMap.set(key, value);
|
|
1421
|
-
return value;
|
|
1850
|
+
getRouteList() {
|
|
1851
|
+
return this.adapter.list().map((v) => [v.method, v.endpoint]);
|
|
1422
1852
|
}
|
|
1423
1853
|
}
|
|
1854
|
+
var init_Router = __esm(() => {
|
|
1855
|
+
init_Context();
|
|
1856
|
+
init_CResponse();
|
|
1857
|
+
init_CorpusAdapter();
|
|
1858
|
+
init_ModelRegistry();
|
|
1859
|
+
init_MiddlewareRegistry();
|
|
1860
|
+
init_WebSocketRoute();
|
|
1861
|
+
});
|
|
1424
1862
|
|
|
1425
1863
|
// src/Server/ServerAbstract.ts
|
|
1426
1864
|
class ServerAbstract {
|
|
1865
|
+
opts;
|
|
1427
1866
|
constructor(opts) {
|
|
1428
|
-
|
|
1867
|
+
this.opts = opts;
|
|
1868
|
+
$routerStore.set(new Router(opts?.adapter));
|
|
1429
1869
|
}
|
|
1430
1870
|
get routes() {
|
|
1431
|
-
return
|
|
1871
|
+
return $routerStore.get().getRouteList();
|
|
1432
1872
|
}
|
|
1433
1873
|
setGlobalPrefix(value) {
|
|
1434
|
-
|
|
1874
|
+
$prefixStore.set(value);
|
|
1435
1875
|
}
|
|
1436
1876
|
async listen(port, hostname = "0.0.0.0") {
|
|
1437
1877
|
try {
|
|
1438
1878
|
process.on("SIGINT", () => this.close());
|
|
1439
1879
|
process.on("SIGTERM", () => this.close());
|
|
1440
|
-
|
|
1880
|
+
log.log(`Listening on ${hostname}:${port}`);
|
|
1441
1881
|
await this.handleBeforeListen?.();
|
|
1442
1882
|
this.serve({
|
|
1443
1883
|
port,
|
|
1444
|
-
hostname
|
|
1445
|
-
fetch: (r) => this.handle(r)
|
|
1884
|
+
hostname
|
|
1446
1885
|
});
|
|
1447
1886
|
} catch (err) {
|
|
1448
|
-
|
|
1887
|
+
log.error("Server unable to start:", err);
|
|
1449
1888
|
await this.close();
|
|
1450
1889
|
}
|
|
1451
1890
|
}
|
|
1452
1891
|
async handle(request) {
|
|
1453
|
-
const req = new
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
res = await this.handleAfterResponse(res);
|
|
1892
|
+
const req = new CRequest(request);
|
|
1893
|
+
const handled = await this.handleRequest(req, () => {
|
|
1894
|
+
return;
|
|
1895
|
+
});
|
|
1896
|
+
if (!handled) {
|
|
1897
|
+
logFatal("WebSocket requests cannot be handled with this method.");
|
|
1460
1898
|
}
|
|
1461
|
-
return
|
|
1899
|
+
return handled;
|
|
1462
1900
|
}
|
|
1463
|
-
async
|
|
1901
|
+
async handleRequest(req, onUpgrade) {
|
|
1902
|
+
let res;
|
|
1464
1903
|
try {
|
|
1465
1904
|
if (req.isPreflight) {
|
|
1466
|
-
|
|
1467
|
-
}
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1905
|
+
res = await this.handlePreflight(req);
|
|
1906
|
+
} else {
|
|
1907
|
+
const router = $routerStore.get();
|
|
1908
|
+
const handleFound = router.findRouteHandler(req);
|
|
1909
|
+
const ctx = Context.makeFromRequest(req);
|
|
1910
|
+
const handleGlobalMiddleware = router.findMiddleware("*");
|
|
1911
|
+
await handleGlobalMiddleware(ctx);
|
|
1912
|
+
const result = await handleFound?.(ctx);
|
|
1913
|
+
if (result instanceof WebSocketRoute && req.isWebsocket) {
|
|
1914
|
+
return onUpgrade(result);
|
|
1915
|
+
} else if (result instanceof CResponse) {
|
|
1916
|
+
res = result;
|
|
1917
|
+
} else {
|
|
1918
|
+
res = await this.handleNotFound(req);
|
|
1477
1919
|
}
|
|
1478
1920
|
}
|
|
1479
|
-
|
|
1921
|
+
} catch (err) {
|
|
1922
|
+
res = await this.handleError(err);
|
|
1480
1923
|
}
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1924
|
+
const cors = $corsStore.get();
|
|
1925
|
+
if (cors !== null) {
|
|
1926
|
+
cors.apply(req, res);
|
|
1927
|
+
}
|
|
1928
|
+
if (this.handleAfterResponse) {
|
|
1929
|
+
res = await this.handleAfterResponse(res);
|
|
1930
|
+
}
|
|
1931
|
+
return res.response;
|
|
1485
1932
|
}
|
|
1486
1933
|
handleBeforeListen;
|
|
1487
1934
|
setOnBeforeListen(handler) {
|
|
@@ -1503,206 +1950,496 @@ class ServerAbstract {
|
|
|
1503
1950
|
this.handleError = handler;
|
|
1504
1951
|
}
|
|
1505
1952
|
defaultErrorHandler = (err) => {
|
|
1506
|
-
if (
|
|
1507
|
-
return new HttpResponse({ error: err, message: "Unknown" }, { status: Status.INTERNAL_SERVER_ERROR });
|
|
1508
|
-
}
|
|
1509
|
-
if (err instanceof HttpError) {
|
|
1953
|
+
if (err instanceof CError) {
|
|
1510
1954
|
return err.toResponse();
|
|
1511
1955
|
}
|
|
1512
|
-
return new
|
|
1956
|
+
return new CResponse({ error: err, message: "message" in err ? err.message : "Unknown" }, { status: Status.INTERNAL_SERVER_ERROR });
|
|
1513
1957
|
};
|
|
1514
1958
|
handleNotFound = (req) => this.defaultNotFoundHandler(req);
|
|
1515
1959
|
setOnNotFound(handler) {
|
|
1516
1960
|
this.handleNotFound = handler;
|
|
1517
1961
|
}
|
|
1518
1962
|
defaultNotFoundHandler = (req) => {
|
|
1519
|
-
return new
|
|
1963
|
+
return new CResponse({ error: true, message: `${req.method} on ${req.url} does not exist.` }, { status: Status.NOT_FOUND });
|
|
1520
1964
|
};
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1965
|
+
handlePreflight = (req) => this.defaultPreflightHandler(req);
|
|
1966
|
+
setOnPreflight(handler) {
|
|
1967
|
+
this.handlePreflight = handler;
|
|
1968
|
+
}
|
|
1969
|
+
defaultPreflightHandler = () => {
|
|
1970
|
+
return new CResponse("Departed");
|
|
1524
1971
|
};
|
|
1525
1972
|
}
|
|
1973
|
+
var init_ServerAbstract = __esm(() => {
|
|
1974
|
+
init_Context();
|
|
1975
|
+
init_Status();
|
|
1976
|
+
init_src();
|
|
1977
|
+
init_CError();
|
|
1978
|
+
init_CRequest();
|
|
1979
|
+
init_CResponse();
|
|
1980
|
+
init_Router();
|
|
1981
|
+
init_internalLogger();
|
|
1982
|
+
init_WebSocketRoute();
|
|
1983
|
+
});
|
|
1526
1984
|
|
|
1527
|
-
// src/
|
|
1528
|
-
class
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
this.
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1985
|
+
// src/CWebSocket/CWebSocket.bun.ts
|
|
1986
|
+
class CWebSocketBun {
|
|
1987
|
+
constructor(ws) {
|
|
1988
|
+
this.ws = ws;
|
|
1989
|
+
this.subscriptions = this.ws.subscriptions;
|
|
1990
|
+
this.remoteAddress = this.ws.remoteAddress;
|
|
1991
|
+
this.readyState = this.ws.readyState;
|
|
1992
|
+
}
|
|
1993
|
+
subscriptions;
|
|
1994
|
+
remoteAddress;
|
|
1995
|
+
readyState;
|
|
1996
|
+
ws;
|
|
1997
|
+
send(data) {
|
|
1998
|
+
return this.ws.send(data);
|
|
1999
|
+
}
|
|
2000
|
+
publish(topic, data) {
|
|
2001
|
+
return this.ws.publish(topic, data);
|
|
2002
|
+
}
|
|
2003
|
+
cork(callback) {
|
|
2004
|
+
return this.ws.cork(callback);
|
|
2005
|
+
}
|
|
2006
|
+
close(code, reason) {
|
|
2007
|
+
return this.ws.close(code, reason);
|
|
2008
|
+
}
|
|
2009
|
+
terminate() {
|
|
2010
|
+
return this.ws.terminate();
|
|
2011
|
+
}
|
|
2012
|
+
subscribe(topic) {
|
|
2013
|
+
return this.ws.subscribe(topic);
|
|
2014
|
+
}
|
|
2015
|
+
unsubscribe(topic) {
|
|
2016
|
+
return this.ws.unsubscribe(topic);
|
|
2017
|
+
}
|
|
2018
|
+
isSubscribed(topic) {
|
|
2019
|
+
return this.ws.isSubscribed(topic);
|
|
1547
2020
|
}
|
|
1548
2021
|
}
|
|
1549
2022
|
|
|
1550
|
-
// src/Server/Server.ts
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
this.config.onParam = [this.config.onParam];
|
|
1575
|
-
}
|
|
1576
|
-
static regex = { static: /:.+?(?=\/|$)/, params: /:.+?(?=\/|$)/g, optionalParams: /(\/:\w+\?)/g };
|
|
1577
|
-
lazyFind = (v, b) => {
|
|
1578
|
-
if (!this.config.lazy)
|
|
1579
|
-
return this.find;
|
|
1580
|
-
return this.build(), this.find(v, b);
|
|
1581
|
-
};
|
|
1582
|
-
build() {
|
|
1583
|
-
if (!this.config.lazy)
|
|
1584
|
-
return;
|
|
1585
|
-
for (let [v, b, A] of this.deferred)
|
|
1586
|
-
this.add(v, b, A, { lazy: false, ignoreHistory: true });
|
|
1587
|
-
this.deferred = [], this.find = (v, b) => {
|
|
1588
|
-
let A = this.root[v];
|
|
1589
|
-
if (!A)
|
|
1590
|
-
return null;
|
|
1591
|
-
return $(b, b.length, A, 0, this.config.onParam);
|
|
1592
|
-
};
|
|
1593
|
-
}
|
|
1594
|
-
add(v, b, A, { ignoreError: Q = false, ignoreHistory: O = false, lazy: V = this.config.lazy } = {}) {
|
|
1595
|
-
if (V)
|
|
1596
|
-
return this.find = this.lazyFind, this.deferred.push([v, b, A]), A;
|
|
1597
|
-
if (typeof b !== "string")
|
|
1598
|
-
throw new TypeError("Route path must be a string");
|
|
1599
|
-
if (b === "")
|
|
1600
|
-
b = "/";
|
|
1601
|
-
else if (b[0] !== "/")
|
|
1602
|
-
b = `/${b}`;
|
|
1603
|
-
let X = b[b.length - 1] === "*", J = b.match(_.regex.optionalParams);
|
|
1604
|
-
if (J) {
|
|
1605
|
-
let F = b.replaceAll("?", "");
|
|
1606
|
-
this.add(v, F, A, { ignoreError: Q, ignoreHistory: O, lazy: V });
|
|
1607
|
-
for (let B = 0;B < J.length; B++) {
|
|
1608
|
-
let D = b.replace(J[B], "");
|
|
1609
|
-
this.add(v, D, A, { ignoreError: true, ignoreHistory: O, lazy: V });
|
|
2023
|
+
// src/Server/Server.bun.ts
|
|
2024
|
+
var exports_Server_bun = {};
|
|
2025
|
+
__export(exports_Server_bun, {
|
|
2026
|
+
default: () => ServerUsingBun
|
|
2027
|
+
});
|
|
2028
|
+
var ServerUsingBun;
|
|
2029
|
+
var init_Server_bun = __esm(() => {
|
|
2030
|
+
init_Config();
|
|
2031
|
+
init_CRequest();
|
|
2032
|
+
init_Status();
|
|
2033
|
+
init_ServerAbstract();
|
|
2034
|
+
init_internalLogger();
|
|
2035
|
+
init_CError();
|
|
2036
|
+
ServerUsingBun = class ServerUsingBun extends ServerAbstract {
|
|
2037
|
+
app;
|
|
2038
|
+
serve(args) {
|
|
2039
|
+
this.app = this.createApp(args);
|
|
2040
|
+
}
|
|
2041
|
+
async close() {
|
|
2042
|
+
await this.handleBeforeClose?.();
|
|
2043
|
+
log.log("Closing...");
|
|
2044
|
+
await this.app?.stop(true);
|
|
2045
|
+
if (Config.nodeEnv !== "test") {
|
|
2046
|
+
process.exit(0);
|
|
1610
2047
|
}
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
q = this.root[v];
|
|
1629
|
-
let U = 0;
|
|
1630
|
-
for (let F = 0;F < K.length; ++F) {
|
|
1631
|
-
let B = K[F];
|
|
1632
|
-
if (F > 0) {
|
|
1633
|
-
let D = G[U++].slice(1);
|
|
1634
|
-
if (q.params === null)
|
|
1635
|
-
q.params = T(D);
|
|
1636
|
-
else if (q.params.name !== D)
|
|
1637
|
-
if (Q)
|
|
1638
|
-
return A;
|
|
1639
|
-
else
|
|
1640
|
-
throw new Error(`Cannot create route "${b}" with parameter "${D}" because a route already exists with a different parameter name ("${q.params.name}") in the same location`);
|
|
1641
|
-
let S = q.params;
|
|
1642
|
-
if (S.inert === null) {
|
|
1643
|
-
q = S.inert = Y(B);
|
|
1644
|
-
continue;
|
|
2048
|
+
}
|
|
2049
|
+
createApp(options) {
|
|
2050
|
+
return Bun.serve({
|
|
2051
|
+
port: options.port,
|
|
2052
|
+
hostname: options.hostname,
|
|
2053
|
+
idleTimeout: this.opts?.idleTimeout,
|
|
2054
|
+
tls: this.opts?.tls,
|
|
2055
|
+
fetch: (r, s) => this.fetch(r, s),
|
|
2056
|
+
websocket: this.websocket
|
|
2057
|
+
});
|
|
2058
|
+
}
|
|
2059
|
+
async fetch(request, server) {
|
|
2060
|
+
const req = new CRequest(request);
|
|
2061
|
+
return await this.handleRequest(req, (wsRoute) => {
|
|
2062
|
+
const upgraded = server.upgrade(request, { data: wsRoute });
|
|
2063
|
+
if (!upgraded) {
|
|
2064
|
+
throw new CError("Upgrade failed", Status.UPGRADE_REQUIRED);
|
|
1645
2065
|
}
|
|
1646
|
-
|
|
2066
|
+
return;
|
|
2067
|
+
});
|
|
2068
|
+
}
|
|
2069
|
+
websocket = {
|
|
2070
|
+
async open(ws) {
|
|
2071
|
+
await ws.data.onOpen?.(new CWebSocketBun(ws));
|
|
2072
|
+
},
|
|
2073
|
+
async message(ws, message) {
|
|
2074
|
+
await ws.data.onMessage(new CWebSocketBun(ws), message);
|
|
2075
|
+
},
|
|
2076
|
+
async close(ws, code, reason) {
|
|
2077
|
+
await ws.data.onClose?.(new CWebSocketBun(ws), code, reason);
|
|
1647
2078
|
}
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
2079
|
+
};
|
|
2080
|
+
};
|
|
2081
|
+
});
|
|
2082
|
+
|
|
2083
|
+
// src/CWebSocket/CWebSocket.node.ts
|
|
2084
|
+
class CWebSocketNode {
|
|
2085
|
+
remoteAddress;
|
|
2086
|
+
readyState;
|
|
2087
|
+
subscriptions = [];
|
|
2088
|
+
ws;
|
|
2089
|
+
registry;
|
|
2090
|
+
constructor(ws, registry, remoteAddress) {
|
|
2091
|
+
this.ws = ws;
|
|
2092
|
+
this.registry = registry;
|
|
2093
|
+
this.remoteAddress = remoteAddress;
|
|
2094
|
+
this.readyState = ws.readyState;
|
|
2095
|
+
}
|
|
2096
|
+
send(data) {
|
|
2097
|
+
this.ws.send(data);
|
|
2098
|
+
return 0;
|
|
2099
|
+
}
|
|
2100
|
+
publish(topic, data) {
|
|
2101
|
+
const subscribers = this.registry.get(topic);
|
|
2102
|
+
if (!subscribers)
|
|
2103
|
+
return 0;
|
|
2104
|
+
let count = 0;
|
|
2105
|
+
for (const sub of subscribers) {
|
|
2106
|
+
if (sub !== this && sub.readyState === 1) {
|
|
2107
|
+
sub.send(data);
|
|
2108
|
+
count++;
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
return count;
|
|
2112
|
+
}
|
|
2113
|
+
cork(callback) {
|
|
2114
|
+
return callback(this);
|
|
2115
|
+
}
|
|
2116
|
+
close(code, reason) {
|
|
2117
|
+
this.ws.close(code, reason);
|
|
2118
|
+
}
|
|
2119
|
+
terminate() {
|
|
2120
|
+
this.ws.terminate();
|
|
2121
|
+
}
|
|
2122
|
+
subscribe(topic) {
|
|
2123
|
+
if (this.isSubscribed(topic))
|
|
2124
|
+
return;
|
|
2125
|
+
this.subscriptions.push(topic);
|
|
2126
|
+
const set = this.registry.get(topic) ?? new Set;
|
|
2127
|
+
set.add(this);
|
|
2128
|
+
this.registry.set(topic, set);
|
|
2129
|
+
}
|
|
2130
|
+
unsubscribe(topic) {
|
|
2131
|
+
const idx = this.subscriptions.indexOf(topic);
|
|
2132
|
+
if (idx === -1)
|
|
2133
|
+
return;
|
|
2134
|
+
this.subscriptions.splice(idx, 1);
|
|
2135
|
+
this.registry.get(topic)?.delete(this);
|
|
2136
|
+
}
|
|
2137
|
+
isSubscribed(topic) {
|
|
2138
|
+
return this.subscriptions.includes(topic);
|
|
2139
|
+
}
|
|
2140
|
+
cleanup() {
|
|
2141
|
+
for (const topic of this.subscriptions) {
|
|
2142
|
+
this.unsubscribe(topic);
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
// src/Server/Server.node.ts
|
|
2148
|
+
var exports_Server_node = {};
|
|
2149
|
+
__export(exports_Server_node, {
|
|
2150
|
+
default: () => ServerUsingNode
|
|
2151
|
+
});
|
|
2152
|
+
var import_node_http, import_node_https, import_ws, ServerUsingNode;
|
|
2153
|
+
var init_Server_node = __esm(() => {
|
|
2154
|
+
init_Config();
|
|
2155
|
+
init_CRequest();
|
|
2156
|
+
init_Method();
|
|
2157
|
+
init_ServerAbstract();
|
|
2158
|
+
init_internalLogger();
|
|
2159
|
+
import_node_http = __toESM(require("http"));
|
|
2160
|
+
import_node_https = __toESM(require("https"));
|
|
2161
|
+
import_ws = require("ws");
|
|
2162
|
+
ServerUsingNode = class ServerUsingNode extends ServerAbstract {
|
|
2163
|
+
app;
|
|
2164
|
+
wss;
|
|
2165
|
+
registry = new Map;
|
|
2166
|
+
serve(args) {
|
|
2167
|
+
const app = this.createApp();
|
|
2168
|
+
const wss = this.createWss();
|
|
2169
|
+
app.addListener("request", async (incomingMessage, serverResponse) => {
|
|
2170
|
+
const body = await this.getBody(incomingMessage);
|
|
2171
|
+
const url = this.getUrl(incomingMessage);
|
|
2172
|
+
const method = this.getMethod(incomingMessage);
|
|
2173
|
+
const headers = this.getHeaders(incomingMessage);
|
|
2174
|
+
const request = this.getRequest(url, method, headers, body);
|
|
2175
|
+
const req = new CRequest(request);
|
|
2176
|
+
const response = await this.handleRequest(req, () => {
|
|
2177
|
+
return;
|
|
2178
|
+
});
|
|
2179
|
+
if (!response) {
|
|
2180
|
+
return;
|
|
1655
2181
|
}
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
2182
|
+
const data = await this.getData(response);
|
|
2183
|
+
serverResponse.statusCode = response.status;
|
|
2184
|
+
serverResponse.setHeaders(response.headers);
|
|
2185
|
+
serverResponse.end(Buffer.from(data));
|
|
2186
|
+
});
|
|
2187
|
+
app.addListener("upgrade", async (incomingMessage, socket, head) => {
|
|
2188
|
+
const body = undefined;
|
|
2189
|
+
const url = this.getUrl(incomingMessage);
|
|
2190
|
+
const method = this.getMethod(incomingMessage);
|
|
2191
|
+
const headers = this.getHeaders(incomingMessage);
|
|
2192
|
+
const request = this.getRequest(url, method, headers, body);
|
|
2193
|
+
const req = new CRequest(request);
|
|
2194
|
+
await this.handleRequest(req, (wsRoute) => {
|
|
2195
|
+
if (!wsRoute) {
|
|
2196
|
+
socket.destroy();
|
|
2197
|
+
return;
|
|
1663
2198
|
}
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
2199
|
+
wss.handleUpgrade(incomingMessage, socket, head, async (ws) => {
|
|
2200
|
+
const remoteAddress = incomingMessage.socket.remoteAddress ?? "";
|
|
2201
|
+
const cws = new CWebSocketNode(ws, this.registry, remoteAddress);
|
|
2202
|
+
wss.emit("connection", ws, incomingMessage);
|
|
2203
|
+
await wsRoute.onOpen?.(cws);
|
|
2204
|
+
ws.on("message", async (message) => {
|
|
2205
|
+
const msg = Buffer.isBuffer(message) ? message : Buffer.from(message);
|
|
2206
|
+
await wsRoute.onMessage(cws, msg);
|
|
2207
|
+
});
|
|
2208
|
+
ws.on("close", async (code, reason) => {
|
|
2209
|
+
cws.cleanup();
|
|
2210
|
+
await wsRoute.onClose?.(cws, code, reason.toString());
|
|
2211
|
+
});
|
|
2212
|
+
});
|
|
2213
|
+
return;
|
|
2214
|
+
});
|
|
2215
|
+
});
|
|
2216
|
+
console.log(app.eventNames());
|
|
2217
|
+
this.app = app;
|
|
2218
|
+
this.wss = wss;
|
|
2219
|
+
app.listen(args.port, args.hostname);
|
|
2220
|
+
}
|
|
2221
|
+
async close() {
|
|
2222
|
+
await this.handleBeforeClose?.();
|
|
2223
|
+
log.log("Closing...");
|
|
2224
|
+
this.wss?.close();
|
|
2225
|
+
this.app?.close();
|
|
2226
|
+
this.app?.closeAllConnections();
|
|
2227
|
+
this.app?.closeIdleConnections();
|
|
2228
|
+
if (Config.nodeEnv !== "test") {
|
|
2229
|
+
process.exit(0);
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
createWss() {
|
|
2233
|
+
return new import_ws.WebSocketServer({ noServer: true });
|
|
2234
|
+
}
|
|
2235
|
+
createApp() {
|
|
2236
|
+
return this.opts?.tls ? import_node_https.default.createServer({
|
|
2237
|
+
keepAliveTimeout: this.opts.idleTimeout,
|
|
2238
|
+
...this.opts.tls
|
|
2239
|
+
}) : import_node_http.default.createServer({ keepAliveTimeout: this.opts?.idleTimeout });
|
|
2240
|
+
}
|
|
2241
|
+
async getBody(incomingMessage) {
|
|
2242
|
+
let body = undefined;
|
|
2243
|
+
const chunks = [];
|
|
2244
|
+
for await (const chunk of incomingMessage) {
|
|
2245
|
+
chunks.push(chunk);
|
|
2246
|
+
}
|
|
2247
|
+
if (chunks.length > 0) {
|
|
2248
|
+
body = Buffer.concat(chunks);
|
|
2249
|
+
}
|
|
2250
|
+
return body;
|
|
2251
|
+
}
|
|
2252
|
+
getUrl(incomingMessage) {
|
|
2253
|
+
const forwardedProtocol = incomingMessage.headers["x-forwarded-proto"];
|
|
2254
|
+
const protocolFromForwarded = Array.isArray(forwardedProtocol) ? forwardedProtocol[0] : forwardedProtocol;
|
|
2255
|
+
const socket = incomingMessage.socket;
|
|
2256
|
+
const isEncrypted = socket.encrypted;
|
|
2257
|
+
let protocol;
|
|
2258
|
+
if (protocolFromForwarded) {
|
|
2259
|
+
protocol = `${protocolFromForwarded}://`;
|
|
2260
|
+
} else if (isEncrypted) {
|
|
2261
|
+
protocol = "https://";
|
|
2262
|
+
} else {
|
|
2263
|
+
protocol = "http://";
|
|
2264
|
+
}
|
|
2265
|
+
return `${protocol}${incomingMessage.headers.host}${incomingMessage.url}`;
|
|
2266
|
+
}
|
|
2267
|
+
getMethod(incomingMessage) {
|
|
2268
|
+
return incomingMessage.method?.toUpperCase() ?? Method.GET;
|
|
2269
|
+
}
|
|
2270
|
+
getHeaders(incomingMessage) {
|
|
2271
|
+
const headers = new Headers;
|
|
2272
|
+
for (const [key, value] of Object.entries(incomingMessage.headers)) {
|
|
2273
|
+
if (Array.isArray(value)) {
|
|
2274
|
+
for (const v of value)
|
|
2275
|
+
headers.append(key, v);
|
|
2276
|
+
} else if (value != null && typeof value === "string") {
|
|
2277
|
+
headers.append(key, value);
|
|
1672
2278
|
}
|
|
1673
|
-
++D;
|
|
1674
2279
|
}
|
|
2280
|
+
return headers;
|
|
1675
2281
|
}
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
2282
|
+
getRequest(url, method, headers, body) {
|
|
2283
|
+
if (method !== Method.GET) {
|
|
2284
|
+
return new Request(url, { method, headers, body });
|
|
2285
|
+
} else {
|
|
2286
|
+
return new Request(url, { method, headers });
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
async getData(response) {
|
|
2290
|
+
return await response.arrayBuffer();
|
|
2291
|
+
}
|
|
2292
|
+
};
|
|
2293
|
+
});
|
|
2294
|
+
|
|
2295
|
+
// src/Server/Server.ts
|
|
2296
|
+
var Adapted3, Server;
|
|
2297
|
+
var init_Server = __esm(() => {
|
|
2298
|
+
Adapted3 = (typeof Bun !== "undefined" ? (init_Server_bun(), __toCommonJS(exports_Server_bun)) : (init_Server_node(), __toCommonJS(exports_Server_node))).default;
|
|
2299
|
+
Server = class Server extends Adapted3 {
|
|
2300
|
+
};
|
|
2301
|
+
});
|
|
2302
|
+
|
|
2303
|
+
// src/C.ts
|
|
2304
|
+
var exports_C = {};
|
|
2305
|
+
__export(exports_C, {
|
|
2306
|
+
WebSocketRoute: () => WebSocketRoute,
|
|
2307
|
+
Status: () => Status,
|
|
2308
|
+
StaticRouteAbstract: () => StaticRouteAbstract,
|
|
2309
|
+
StaticRoute: () => StaticRoute,
|
|
2310
|
+
Server: () => Server,
|
|
2311
|
+
Route: () => DynamicRoute,
|
|
2312
|
+
Response: () => CResponse,
|
|
2313
|
+
Request: () => CRequest,
|
|
2314
|
+
MiddlewareAbstract: () => MiddlewareAbstract,
|
|
2315
|
+
Middleware: () => Middleware,
|
|
2316
|
+
Method: () => Method,
|
|
2317
|
+
Headers: () => CHeaders,
|
|
2318
|
+
Error: () => CError,
|
|
2319
|
+
DynamicRouteAbstract: () => DynamicRouteAbstract,
|
|
2320
|
+
Cookies: () => Cookies,
|
|
2321
|
+
Controller: () => Controller,
|
|
2322
|
+
Context: () => Context,
|
|
2323
|
+
Config: () => Config,
|
|
2324
|
+
CommonHeaders: () => CommonHeaders
|
|
2325
|
+
});
|
|
2326
|
+
var init_C = __esm(() => {
|
|
2327
|
+
init_Config();
|
|
2328
|
+
init_Context();
|
|
2329
|
+
init_Controller();
|
|
2330
|
+
init_Cookies();
|
|
2331
|
+
init_CError();
|
|
2332
|
+
init_CHeaders();
|
|
2333
|
+
init_Middleware();
|
|
2334
|
+
init_CRequest();
|
|
2335
|
+
init_CResponse();
|
|
2336
|
+
init_DynamicRouteAbstract();
|
|
2337
|
+
init_DynamicRoute();
|
|
2338
|
+
init_StaticRouteAbstract();
|
|
2339
|
+
init_StaticRoute();
|
|
2340
|
+
init_WebSocketRoute();
|
|
2341
|
+
init_Server();
|
|
2342
|
+
init_CommonHeaders();
|
|
2343
|
+
init_Method();
|
|
2344
|
+
init_Status();
|
|
2345
|
+
});
|
|
2346
|
+
|
|
2347
|
+
// src/utils/boolToString.ts
|
|
2348
|
+
function boolToString(arg) {
|
|
2349
|
+
return arg ? "true" : "false";
|
|
2350
|
+
}
|
|
2351
|
+
|
|
2352
|
+
// src/utils/isSomeArray.ts
|
|
2353
|
+
function isSomeArray(arg) {
|
|
2354
|
+
return arg !== undefined && Array.isArray(arg) && arg.length > 0 && arg.every((a) => a !== null && a !== undefined);
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
// src/utils/arrMerge.ts
|
|
2358
|
+
function arrMerge(base = [], override = []) {
|
|
2359
|
+
if (base.length === 0 && override.length === 0)
|
|
2360
|
+
return;
|
|
2361
|
+
const seen = new Set(base);
|
|
2362
|
+
for (const item of override)
|
|
2363
|
+
seen.add(item);
|
|
2364
|
+
return [...seen];
|
|
2365
|
+
}
|
|
2366
|
+
|
|
2367
|
+
// src/XCors/XCors.ts
|
|
2368
|
+
class XCors {
|
|
2369
|
+
opts;
|
|
2370
|
+
constructor(opts) {
|
|
2371
|
+
this.opts = opts;
|
|
2372
|
+
if (opts === undefined) {
|
|
2373
|
+
$corsStore.set(null);
|
|
2374
|
+
} else {
|
|
2375
|
+
$corsStore.set(this);
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
originKey = "Access-Control-Allow-Origin";
|
|
2379
|
+
methodsKey = "Access-Control-Allow-Methods";
|
|
2380
|
+
headersKey = "Access-Control-Allow-Headers";
|
|
2381
|
+
credentialsKey = "Access-Control-Allow-Credentials";
|
|
2382
|
+
exposedHeadersKey = "Access-Control-Expose-Headers";
|
|
2383
|
+
getCorsHeaders(req, res) {
|
|
2384
|
+
const reqOrigin = req.headers.get("origin") ?? "";
|
|
2385
|
+
const {
|
|
2386
|
+
allowedOrigins,
|
|
2387
|
+
allowedMethods,
|
|
2388
|
+
allowedHeaders,
|
|
2389
|
+
exposedHeaders,
|
|
2390
|
+
credentials
|
|
2391
|
+
} = this.opts ?? {};
|
|
2392
|
+
if (isSomeArray(allowedOrigins) && allowedOrigins.includes(reqOrigin)) {
|
|
2393
|
+
res.headers.set(this.originKey, reqOrigin);
|
|
2394
|
+
}
|
|
2395
|
+
if (isSomeArray(allowedMethods)) {
|
|
2396
|
+
res.headers.set(this.methodsKey, allowedMethods.join(", "));
|
|
2397
|
+
}
|
|
2398
|
+
if (isSomeArray(allowedHeaders)) {
|
|
2399
|
+
res.headers.set(this.headersKey, allowedHeaders.join(", "));
|
|
2400
|
+
}
|
|
2401
|
+
if (isSomeArray(exposedHeaders)) {
|
|
2402
|
+
res.headers.set(this.exposedHeadersKey, exposedHeaders.join(", "));
|
|
2403
|
+
}
|
|
2404
|
+
res.headers.set(this.credentialsKey, boolToString(credentials));
|
|
2405
|
+
return res.headers;
|
|
2406
|
+
}
|
|
2407
|
+
apply(req, res) {
|
|
2408
|
+
const headers = this.getCorsHeaders(req, res);
|
|
2409
|
+
res.headers.innerCombine(headers);
|
|
2410
|
+
}
|
|
2411
|
+
updateOptions(newOpts) {
|
|
2412
|
+
this.opts = {
|
|
2413
|
+
...this.opts,
|
|
2414
|
+
...newOpts,
|
|
2415
|
+
allowedHeaders: arrMerge(this.opts?.allowedHeaders, newOpts.allowedHeaders),
|
|
2416
|
+
allowedMethods: arrMerge(this.opts?.allowedMethods, newOpts.allowedMethods),
|
|
2417
|
+
allowedOrigins: arrMerge(this.opts?.allowedOrigins, newOpts.allowedOrigins),
|
|
2418
|
+
exposedHeaders: arrMerge(this.opts?.exposedHeaders, newOpts.exposedHeaders)
|
|
2419
|
+
};
|
|
2420
|
+
$corsStore.set(this);
|
|
1703
2421
|
}
|
|
1704
2422
|
}
|
|
1705
|
-
var
|
|
2423
|
+
var init_XCors = __esm(() => {
|
|
2424
|
+
init_src();
|
|
2425
|
+
});
|
|
2426
|
+
|
|
2427
|
+
// src/XRepository/XRepository.ts
|
|
2428
|
+
class XRepository {
|
|
2429
|
+
db;
|
|
2430
|
+
constructor(db) {
|
|
2431
|
+
this.db = db;
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
|
|
2435
|
+
// node_modules/memoirist/dist/bun/index.js
|
|
2436
|
+
var Y = (v, b) => {
|
|
2437
|
+
let A = b?.length ? {} : null;
|
|
2438
|
+
if (A)
|
|
2439
|
+
for (let Q of b)
|
|
2440
|
+
A[Q.part.charCodeAt(0)] = Q;
|
|
2441
|
+
return { part: v, store: null, inert: A, params: null, wildcardStore: null };
|
|
2442
|
+
}, k = (v, b) => ({ ...v, part: b }), T = (v) => ({ name: v, store: null, inert: null }), _, $ = (v, b, A, Q, O) => {
|
|
1706
2443
|
let V = A.part, X = V.length, J = Q + X;
|
|
1707
2444
|
if (X > 1) {
|
|
1708
2445
|
if (J > b)
|
|
@@ -1760,28 +2497,590 @@ var $ = (v, b, A, Q, O) => {
|
|
|
1760
2497
|
if (A.wildcardStore !== null)
|
|
1761
2498
|
return { store: A.wildcardStore, params: { "*": v.substring(J, b) } };
|
|
1762
2499
|
return null;
|
|
1763
|
-
};
|
|
1764
|
-
var
|
|
2500
|
+
}, w;
|
|
2501
|
+
var init_bun = __esm(() => {
|
|
2502
|
+
_ = class _ {
|
|
2503
|
+
config;
|
|
2504
|
+
root = {};
|
|
2505
|
+
history = [];
|
|
2506
|
+
deferred = [];
|
|
2507
|
+
constructor(v = {}) {
|
|
2508
|
+
this.config = v;
|
|
2509
|
+
if (v.lazy)
|
|
2510
|
+
this.find = this.lazyFind;
|
|
2511
|
+
if (v.onParam && !Array.isArray(v.onParam))
|
|
2512
|
+
this.config.onParam = [this.config.onParam];
|
|
2513
|
+
}
|
|
2514
|
+
static regex = { static: /:.+?(?=\/|$)/, params: /:.+?(?=\/|$)/g, optionalParams: /(\/:\w+\?)/g };
|
|
2515
|
+
lazyFind = (v, b) => {
|
|
2516
|
+
if (!this.config.lazy)
|
|
2517
|
+
return this.find;
|
|
2518
|
+
return this.build(), this.find(v, b);
|
|
2519
|
+
};
|
|
2520
|
+
build() {
|
|
2521
|
+
if (!this.config.lazy)
|
|
2522
|
+
return;
|
|
2523
|
+
for (let [v, b, A] of this.deferred)
|
|
2524
|
+
this.add(v, b, A, { lazy: false, ignoreHistory: true });
|
|
2525
|
+
this.deferred = [], this.find = (v, b) => {
|
|
2526
|
+
let A = this.root[v];
|
|
2527
|
+
if (!A)
|
|
2528
|
+
return null;
|
|
2529
|
+
return $(b, b.length, A, 0, this.config.onParam);
|
|
2530
|
+
};
|
|
2531
|
+
}
|
|
2532
|
+
add(v, b, A, { ignoreError: Q = false, ignoreHistory: O = false, lazy: V = this.config.lazy } = {}) {
|
|
2533
|
+
if (V)
|
|
2534
|
+
return this.find = this.lazyFind, this.deferred.push([v, b, A]), A;
|
|
2535
|
+
if (typeof b !== "string")
|
|
2536
|
+
throw new TypeError("Route path must be a string");
|
|
2537
|
+
if (b === "")
|
|
2538
|
+
b = "/";
|
|
2539
|
+
else if (b[0] !== "/")
|
|
2540
|
+
b = `/${b}`;
|
|
2541
|
+
let X = b[b.length - 1] === "*", J = b.match(_.regex.optionalParams);
|
|
2542
|
+
if (J) {
|
|
2543
|
+
let F = b.replaceAll("?", "");
|
|
2544
|
+
this.add(v, F, A, { ignoreError: Q, ignoreHistory: O, lazy: V });
|
|
2545
|
+
for (let B = 0;B < J.length; B++) {
|
|
2546
|
+
let D = b.replace(J[B], "");
|
|
2547
|
+
this.add(v, D, A, { ignoreError: true, ignoreHistory: O, lazy: V });
|
|
2548
|
+
}
|
|
2549
|
+
return A;
|
|
2550
|
+
}
|
|
2551
|
+
if (J)
|
|
2552
|
+
b = b.replaceAll("?", "");
|
|
2553
|
+
if (this.history.find(([F, B, D]) => F === v && B === b))
|
|
2554
|
+
return A;
|
|
2555
|
+
if (X || J && b.charCodeAt(b.length - 1) === 63)
|
|
2556
|
+
b = b.slice(0, -1);
|
|
2557
|
+
if (!O)
|
|
2558
|
+
this.history.push([v, b, A]);
|
|
2559
|
+
let K = b.split(_.regex.static), G = b.match(_.regex.params) || [];
|
|
2560
|
+
if (K[K.length - 1] === "")
|
|
2561
|
+
K.pop();
|
|
2562
|
+
let q;
|
|
2563
|
+
if (!this.root[v])
|
|
2564
|
+
q = this.root[v] = Y("/");
|
|
2565
|
+
else
|
|
2566
|
+
q = this.root[v];
|
|
2567
|
+
let U = 0;
|
|
2568
|
+
for (let F = 0;F < K.length; ++F) {
|
|
2569
|
+
let B = K[F];
|
|
2570
|
+
if (F > 0) {
|
|
2571
|
+
let D = G[U++].slice(1);
|
|
2572
|
+
if (q.params === null)
|
|
2573
|
+
q.params = T(D);
|
|
2574
|
+
else if (q.params.name !== D)
|
|
2575
|
+
if (Q)
|
|
2576
|
+
return A;
|
|
2577
|
+
else
|
|
2578
|
+
throw new Error(`Cannot create route "${b}" with parameter "${D}" because a route already exists with a different parameter name ("${q.params.name}") in the same location`);
|
|
2579
|
+
let S = q.params;
|
|
2580
|
+
if (S.inert === null) {
|
|
2581
|
+
q = S.inert = Y(B);
|
|
2582
|
+
continue;
|
|
2583
|
+
}
|
|
2584
|
+
q = S.inert;
|
|
2585
|
+
}
|
|
2586
|
+
for (let D = 0;; ) {
|
|
2587
|
+
if (D === B.length) {
|
|
2588
|
+
if (D < q.part.length) {
|
|
2589
|
+
let S = k(q, q.part.slice(D));
|
|
2590
|
+
Object.assign(q, Y(B, [S]));
|
|
2591
|
+
}
|
|
2592
|
+
break;
|
|
2593
|
+
}
|
|
2594
|
+
if (D === q.part.length) {
|
|
2595
|
+
if (q.inert === null)
|
|
2596
|
+
q.inert = {};
|
|
2597
|
+
let S = q.inert[B.charCodeAt(D)];
|
|
2598
|
+
if (S) {
|
|
2599
|
+
q = S, B = B.slice(D), D = 0;
|
|
2600
|
+
continue;
|
|
2601
|
+
}
|
|
2602
|
+
let Z = Y(B.slice(D));
|
|
2603
|
+
q.inert[B.charCodeAt(D)] = Z, q = Z;
|
|
2604
|
+
break;
|
|
2605
|
+
}
|
|
2606
|
+
if (B[D] !== q.part[D]) {
|
|
2607
|
+
let S = k(q, q.part.slice(D)), Z = Y(B.slice(D));
|
|
2608
|
+
Object.assign(q, Y(q.part.slice(0, D), [S, Z])), q = Z;
|
|
2609
|
+
break;
|
|
2610
|
+
}
|
|
2611
|
+
++D;
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
if (U < G.length) {
|
|
2615
|
+
let B = G[U].slice(1);
|
|
2616
|
+
if (q.params === null)
|
|
2617
|
+
q.params = T(B);
|
|
2618
|
+
else if (q.params.name !== B)
|
|
2619
|
+
if (Q)
|
|
2620
|
+
return A;
|
|
2621
|
+
else
|
|
2622
|
+
throw new Error(`Cannot create route "${b}" with parameter "${B}" because a route already exists with a different parameter name ("${q.params.name}") in the same location`);
|
|
2623
|
+
if (q.params.store === null)
|
|
2624
|
+
q.params.store = A;
|
|
2625
|
+
return q.params.store;
|
|
2626
|
+
}
|
|
2627
|
+
if (X) {
|
|
2628
|
+
if (q.wildcardStore === null)
|
|
2629
|
+
q.wildcardStore = A;
|
|
2630
|
+
return q.wildcardStore;
|
|
2631
|
+
}
|
|
2632
|
+
if (q.store === null)
|
|
2633
|
+
q.store = A;
|
|
2634
|
+
return q.store;
|
|
2635
|
+
}
|
|
2636
|
+
find(v, b) {
|
|
2637
|
+
let A = this.root[v];
|
|
2638
|
+
if (!A)
|
|
2639
|
+
return null;
|
|
2640
|
+
return $(b, b.length, A, 0, this.config.onParam);
|
|
2641
|
+
}
|
|
2642
|
+
};
|
|
2643
|
+
w = _;
|
|
2644
|
+
});
|
|
1765
2645
|
|
|
1766
2646
|
// src/Router/adapters/MemoiristAdapter.ts
|
|
1767
2647
|
class MemoiristAdapter {
|
|
1768
2648
|
router = new w;
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
const result = this.router.find(method,
|
|
2649
|
+
find(req) {
|
|
2650
|
+
const method = req.method;
|
|
2651
|
+
const pathname = req.urlObject.pathname;
|
|
2652
|
+
const searchParams = req.urlObject.searchParams;
|
|
2653
|
+
const result = this.router.find(method, pathname);
|
|
1774
2654
|
if (!result)
|
|
1775
2655
|
return null;
|
|
1776
|
-
return {
|
|
2656
|
+
return {
|
|
2657
|
+
route: result.store,
|
|
2658
|
+
params: result.params,
|
|
2659
|
+
search: Object.fromEntries(searchParams)
|
|
2660
|
+
};
|
|
1777
2661
|
}
|
|
1778
2662
|
list() {
|
|
1779
2663
|
return this.router.history.map((v) => v[2]);
|
|
1780
2664
|
}
|
|
2665
|
+
add(data) {
|
|
2666
|
+
this.router.add(data.method, data.endpoint, data);
|
|
2667
|
+
}
|
|
1781
2668
|
}
|
|
2669
|
+
var init_MemoiristAdapter = __esm(() => {
|
|
2670
|
+
init_bun();
|
|
2671
|
+
});
|
|
2672
|
+
|
|
2673
|
+
// src/XRateLimiter/stores/RateLimiterFileStore.ts
|
|
2674
|
+
class RateLimiterFileStore {
|
|
2675
|
+
storeDir;
|
|
2676
|
+
locks = new Map;
|
|
2677
|
+
constructor(storeDir) {
|
|
2678
|
+
this.storeDir = storeDir || path2.join(os.tmpdir(), "rate-limit-store");
|
|
2679
|
+
this.ensureStoreDir();
|
|
2680
|
+
}
|
|
2681
|
+
ensureStoreDir() {
|
|
2682
|
+
import_promises.default.mkdir(this.storeDir, { recursive: true }).catch((err) => {
|
|
2683
|
+
log.error("Rate Limit File Store Directory could not be created:", err);
|
|
2684
|
+
});
|
|
2685
|
+
}
|
|
2686
|
+
getFilePath(id) {
|
|
2687
|
+
const safeId = import_crypto.default.hash("sha256", id).slice(0, 32);
|
|
2688
|
+
return path2.join(this.storeDir, `${safeId}.json`);
|
|
2689
|
+
}
|
|
2690
|
+
async get(id) {
|
|
2691
|
+
try {
|
|
2692
|
+
const data = await import_promises.default.readFile(this.getFilePath(id), "utf-8");
|
|
2693
|
+
return JSON.parse(data);
|
|
2694
|
+
} catch {
|
|
2695
|
+
return;
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
async set(id, entry) {
|
|
2699
|
+
while (this.locks.has(id)) {
|
|
2700
|
+
await this.locks.get(id);
|
|
2701
|
+
}
|
|
2702
|
+
let resolveLock;
|
|
2703
|
+
this.locks.set(id, new Promise((resolve) => {
|
|
2704
|
+
resolveLock = resolve;
|
|
2705
|
+
}));
|
|
2706
|
+
try {
|
|
2707
|
+
await import_promises.default.writeFile(this.getFilePath(id), JSON.stringify(entry), "utf-8");
|
|
2708
|
+
} finally {
|
|
2709
|
+
this.locks.delete(id);
|
|
2710
|
+
resolveLock();
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
async delete(id) {
|
|
2714
|
+
try {
|
|
2715
|
+
await import_promises.default.unlink(this.getFilePath(id));
|
|
2716
|
+
} catch {}
|
|
2717
|
+
}
|
|
2718
|
+
async cleanup(now) {
|
|
2719
|
+
const files = await import_promises.default.readdir(this.storeDir);
|
|
2720
|
+
for (const file of files) {
|
|
2721
|
+
if (!file.endsWith(".json"))
|
|
2722
|
+
continue;
|
|
2723
|
+
try {
|
|
2724
|
+
const data = await import_promises.default.readFile(path2.join(this.storeDir, file), "utf-8");
|
|
2725
|
+
const entry = JSON.parse(data);
|
|
2726
|
+
if (entry.resetAt <= now) {
|
|
2727
|
+
await import_promises.default.unlink(path2.join(this.storeDir, file));
|
|
2728
|
+
}
|
|
2729
|
+
} catch {}
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
async clear() {
|
|
2733
|
+
const files = await import_promises.default.readdir(this.storeDir);
|
|
2734
|
+
for (const file of files) {
|
|
2735
|
+
if (file.endsWith(".json")) {
|
|
2736
|
+
await import_promises.default.unlink(path2.join(this.storeDir, file));
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
async size() {
|
|
2741
|
+
const files = await import_promises.default.readdir(this.storeDir);
|
|
2742
|
+
return files.filter((f) => f.endsWith(".json")).length;
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2745
|
+
var import_crypto, import_promises, path2, os;
|
|
2746
|
+
var init_RateLimiterFileStore = __esm(() => {
|
|
2747
|
+
init_internalLogger();
|
|
2748
|
+
import_crypto = __toESM(require("crypto"));
|
|
2749
|
+
import_promises = __toESM(require("fs/promises"));
|
|
2750
|
+
path2 = __toESM(require("path"));
|
|
2751
|
+
os = __toESM(require("os"));
|
|
2752
|
+
});
|
|
2753
|
+
|
|
2754
|
+
// src/XRateLimiter/stores/RateLimiterRedisStore.ts
|
|
2755
|
+
class RateLimiterRedisStore {
|
|
2756
|
+
redis;
|
|
2757
|
+
prefix;
|
|
2758
|
+
constructor(redis, prefix = "rl:") {
|
|
2759
|
+
this.redis = redis;
|
|
2760
|
+
this.prefix = prefix;
|
|
2761
|
+
}
|
|
2762
|
+
async get(id) {
|
|
2763
|
+
const data = await this.redis.get(this.prefix + id);
|
|
2764
|
+
return data ? JSON.parse(data) : undefined;
|
|
2765
|
+
}
|
|
2766
|
+
async set(id, entry) {
|
|
2767
|
+
await this.redis.set(this.prefix + id, JSON.stringify(entry), "PX", Math.max(0, entry.resetAt - Date.now()));
|
|
2768
|
+
}
|
|
2769
|
+
async delete(id) {
|
|
2770
|
+
await this.redis.del(this.prefix + id);
|
|
2771
|
+
}
|
|
2772
|
+
async cleanup(_now) {}
|
|
2773
|
+
async clear() {
|
|
2774
|
+
const keys = await this.redis.keys(this.prefix + "*");
|
|
2775
|
+
if (keys.length > 0) {
|
|
2776
|
+
await this.redis.del(...keys);
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2779
|
+
async size() {
|
|
2780
|
+
const keys = await this.redis.keys(this.prefix + "*");
|
|
2781
|
+
return keys.length;
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
|
|
2785
|
+
// src/XRateLimiter/stores/RateLimiterMemoryStore.ts
|
|
2786
|
+
class RateLimiterMemoryStore {
|
|
2787
|
+
store = new Map;
|
|
2788
|
+
locks = new Map;
|
|
2789
|
+
async get(id) {
|
|
2790
|
+
return this.store.get(id);
|
|
2791
|
+
}
|
|
2792
|
+
async set(id, entry) {
|
|
2793
|
+
while (this.locks.has(id)) {
|
|
2794
|
+
await this.locks.get(id);
|
|
2795
|
+
}
|
|
2796
|
+
let resolveLock;
|
|
2797
|
+
this.locks.set(id, new Promise((resolve) => {
|
|
2798
|
+
resolveLock = resolve;
|
|
2799
|
+
}));
|
|
2800
|
+
try {
|
|
2801
|
+
this.store.set(id, entry);
|
|
2802
|
+
} finally {
|
|
2803
|
+
this.locks.delete(id);
|
|
2804
|
+
resolveLock();
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
async delete(id) {
|
|
2808
|
+
this.store.delete(id);
|
|
2809
|
+
}
|
|
2810
|
+
async cleanup(now) {
|
|
2811
|
+
for (const [id, entry] of this.store) {
|
|
2812
|
+
if (entry.resetAt <= now) {
|
|
2813
|
+
await this.delete(id);
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
async clear() {
|
|
2818
|
+
this.store.clear();
|
|
2819
|
+
}
|
|
2820
|
+
async size() {
|
|
2821
|
+
return this.store.size;
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
|
|
2825
|
+
// src/XRateLimiter/XRateLimiter.ts
|
|
2826
|
+
class XRateLimiter {
|
|
2827
|
+
constructor(config = {}) {
|
|
2828
|
+
this.config = { ...this.defaultConfig, ...config };
|
|
2829
|
+
this.store = this.resolveStore();
|
|
2830
|
+
this.storedSalt = this.getRandomBytes();
|
|
2831
|
+
this.saltRotatesAt = Date.now() + this.config.saltRotateMs;
|
|
2832
|
+
this.registerMiddleware();
|
|
2833
|
+
}
|
|
2834
|
+
config;
|
|
2835
|
+
store;
|
|
2836
|
+
storedSalt;
|
|
2837
|
+
saltRotatesAt;
|
|
2838
|
+
async getResult(headers) {
|
|
2839
|
+
await this.maybeCleanStore();
|
|
2840
|
+
const id = this.getId(headers);
|
|
2841
|
+
const now = Date.now();
|
|
2842
|
+
let entry = await this.store.get(id);
|
|
2843
|
+
if (entry && entry.resetAt > now) {
|
|
2844
|
+
entry.hits++;
|
|
2845
|
+
} else {
|
|
2846
|
+
entry = { hits: 1, resetAt: now + this.config.windowMs };
|
|
2847
|
+
}
|
|
2848
|
+
await this.store.set(id, entry);
|
|
2849
|
+
const max = this.getMax(id);
|
|
2850
|
+
const allowed = entry.hits <= max;
|
|
2851
|
+
const remaining = Math.max(0, max - entry.hits);
|
|
2852
|
+
const resetUnix = Math.ceil(entry.resetAt / 1000);
|
|
2853
|
+
const keys = this.config.headerNames;
|
|
2854
|
+
const responseHeaders = new CHeaders;
|
|
2855
|
+
responseHeaders.setMany({
|
|
2856
|
+
[keys.limit]: max.toString(),
|
|
2857
|
+
[keys.remaining]: remaining.toString(),
|
|
2858
|
+
[keys.reset]: resetUnix.toString()
|
|
2859
|
+
});
|
|
2860
|
+
if (!allowed) {
|
|
2861
|
+
const retryAfter = Math.ceil((entry.resetAt - now) / 1000);
|
|
2862
|
+
responseHeaders.set(keys.retryAfter, retryAfter.toString());
|
|
2863
|
+
}
|
|
2864
|
+
if (allowed) {
|
|
2865
|
+
return { headers: responseHeaders, success: true };
|
|
2866
|
+
}
|
|
2867
|
+
return { headers: responseHeaders, success: false };
|
|
2868
|
+
}
|
|
2869
|
+
getId(headers) {
|
|
2870
|
+
const authHeader = headers.get(CommonHeaders.Authorization);
|
|
2871
|
+
const token = authHeader?.split(" ")[1];
|
|
2872
|
+
if (strIsDefined(token) && token.length >= 20 && token.length <= 2048) {
|
|
2873
|
+
return `u:${this.hash(token, 16)}`;
|
|
2874
|
+
}
|
|
2875
|
+
const ip = this.extractIp(headers);
|
|
2876
|
+
if (ip !== null) {
|
|
2877
|
+
return `i:${this.hash(ip + this.salt(), 16)}`;
|
|
2878
|
+
}
|
|
2879
|
+
const parts = [
|
|
2880
|
+
headers.get("user-agent") ?? "no-ua",
|
|
2881
|
+
headers.get("accept-language") ?? "no-lang",
|
|
2882
|
+
headers.get("accept-encoding") ?? "no-enc"
|
|
2883
|
+
];
|
|
2884
|
+
return `f:${this.hash(parts.join("|") + this.salt(), 16)}`;
|
|
2885
|
+
}
|
|
2886
|
+
getMax(id) {
|
|
2887
|
+
const prefix = id.charAt(0);
|
|
2888
|
+
return this.config.limits[prefix] ?? this.config.limits.f;
|
|
2889
|
+
}
|
|
2890
|
+
extractIp(headers) {
|
|
2891
|
+
const raw = headers.get("cf-connecting-ip") || headers.get("x-real-ip") || headers.get("x-forwarded-for")?.split(",")[0]?.trim();
|
|
2892
|
+
return this.isValidIp(raw) ? raw : null;
|
|
2893
|
+
}
|
|
2894
|
+
isValidIp(ip) {
|
|
2895
|
+
if (!strIsDefined(ip) || ip.length === 0)
|
|
2896
|
+
return false;
|
|
2897
|
+
if (ip.includes(".")) {
|
|
2898
|
+
const parts = ip.split(".");
|
|
2899
|
+
if (parts.length !== 4)
|
|
2900
|
+
return false;
|
|
2901
|
+
return parts.every((p) => {
|
|
2902
|
+
if (!/^\d+$/.test(p))
|
|
2903
|
+
return false;
|
|
2904
|
+
const n = Number(p);
|
|
2905
|
+
return n >= 0 && n <= 255 && p === String(n);
|
|
2906
|
+
});
|
|
2907
|
+
}
|
|
2908
|
+
if (ip.includes(":")) {
|
|
2909
|
+
try {
|
|
2910
|
+
new URL(`http://[${ip}]`);
|
|
2911
|
+
return true;
|
|
2912
|
+
} catch {
|
|
2913
|
+
return false;
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
return false;
|
|
2917
|
+
}
|
|
2918
|
+
salt() {
|
|
2919
|
+
if (Date.now() > this.saltRotatesAt) {
|
|
2920
|
+
this.storedSalt = this.getRandomBytes();
|
|
2921
|
+
this.saltRotatesAt = Date.now() + this.config.saltRotateMs;
|
|
2922
|
+
}
|
|
2923
|
+
return this.storedSalt;
|
|
2924
|
+
}
|
|
2925
|
+
async maybeCleanStore() {
|
|
2926
|
+
const currentSize = await this.store.size();
|
|
2927
|
+
const shouldClean = Math.random() < this.config.cleanProbability || currentSize > this.config.maxStoreSize;
|
|
2928
|
+
if (shouldClean)
|
|
2929
|
+
await this.cleanStore();
|
|
2930
|
+
}
|
|
2931
|
+
async cleanStore() {
|
|
2932
|
+
const now = Date.now();
|
|
2933
|
+
await this.store.cleanup(now);
|
|
2934
|
+
return await this.store.size();
|
|
2935
|
+
}
|
|
2936
|
+
hash(data, len) {
|
|
2937
|
+
return import_crypto2.default.hash("sha256", data).slice(0, len);
|
|
2938
|
+
}
|
|
2939
|
+
getRandomBytes() {
|
|
2940
|
+
return import_crypto2.default.randomBytes(16).toString("hex");
|
|
2941
|
+
}
|
|
2942
|
+
async clearStore() {
|
|
2943
|
+
await this.store.clear();
|
|
2944
|
+
}
|
|
2945
|
+
async getStoreSize() {
|
|
2946
|
+
return await this.store.size();
|
|
2947
|
+
}
|
|
2948
|
+
defaultConfig = {
|
|
2949
|
+
windowMs: 60000,
|
|
2950
|
+
saltRotateMs: 24 * 3600 * 1000,
|
|
2951
|
+
cleanProbability: 0.005,
|
|
2952
|
+
maxStoreSize: 50000,
|
|
2953
|
+
storeType: "memory",
|
|
2954
|
+
limits: { u: 120, i: 60, f: 20 },
|
|
2955
|
+
headerNames: {
|
|
2956
|
+
limit: "RateLimit-Limit",
|
|
2957
|
+
remaining: "RateLimit-Remaining",
|
|
2958
|
+
reset: "RateLimit-Reset",
|
|
2959
|
+
retryAfter: "Retry-After"
|
|
2960
|
+
}
|
|
2961
|
+
};
|
|
2962
|
+
resolveStore() {
|
|
2963
|
+
switch (this.config.storeType) {
|
|
2964
|
+
case "file":
|
|
2965
|
+
return new RateLimiterFileStore(this.config.storeDir);
|
|
2966
|
+
case "redis":
|
|
2967
|
+
if (!this.config.redisClient) {
|
|
2968
|
+
logFatal("Redis client required for redis store type");
|
|
2969
|
+
}
|
|
2970
|
+
return new RateLimiterRedisStore(this.config.redisClient);
|
|
2971
|
+
case "memory":
|
|
2972
|
+
default:
|
|
2973
|
+
return new RateLimiterMemoryStore;
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
registerMiddleware() {
|
|
2977
|
+
const exposedHeaders = Object.values(this.config.headerNames);
|
|
2978
|
+
const cors = $corsStore.get();
|
|
2979
|
+
if (cors) {
|
|
2980
|
+
cors.updateOptions({ exposedHeaders });
|
|
2981
|
+
} else {
|
|
2982
|
+
new XCors({ exposedHeaders });
|
|
2983
|
+
}
|
|
2984
|
+
new Middleware({
|
|
2985
|
+
useOn: "*",
|
|
2986
|
+
handler: async (c) => {
|
|
2987
|
+
const result = await this.getResult(c.headers);
|
|
2988
|
+
c.res.headers.innerCombine(result.headers);
|
|
2989
|
+
if (!result.success) {
|
|
2990
|
+
throw new CError("Too many requests", Status.TOO_MANY_REQUESTS, c.res);
|
|
2991
|
+
}
|
|
2992
|
+
}
|
|
2993
|
+
});
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
var import_crypto2;
|
|
2997
|
+
var init_XRateLimiter = __esm(() => {
|
|
2998
|
+
init_CHeaders();
|
|
2999
|
+
init_CError();
|
|
3000
|
+
init_RateLimiterFileStore();
|
|
3001
|
+
init_Status();
|
|
3002
|
+
init_CommonHeaders();
|
|
3003
|
+
init_Middleware();
|
|
3004
|
+
init_XCors();
|
|
3005
|
+
init_src();
|
|
3006
|
+
init_internalLogger();
|
|
3007
|
+
import_crypto2 = __toESM(require("crypto"));
|
|
3008
|
+
});
|
|
3009
|
+
|
|
3010
|
+
// src/X.ts
|
|
3011
|
+
var exports_X = {};
|
|
3012
|
+
__export(exports_X, {
|
|
3013
|
+
Repository: () => XRepository,
|
|
3014
|
+
RateLimiterRedisStore: () => RateLimiterRedisStore,
|
|
3015
|
+
RateLimiterMemoryStore: () => RateLimiterMemoryStore,
|
|
3016
|
+
RateLimiterFileStore: () => RateLimiterFileStore,
|
|
3017
|
+
RateLimiter: () => XRateLimiter,
|
|
3018
|
+
Parser: () => XParser,
|
|
3019
|
+
MemoiristAdapter: () => MemoiristAdapter,
|
|
3020
|
+
File: () => XFile,
|
|
3021
|
+
Cors: () => XCors
|
|
3022
|
+
});
|
|
3023
|
+
var init_X = __esm(() => {
|
|
3024
|
+
init_XCors();
|
|
3025
|
+
init_XFile();
|
|
3026
|
+
init_MemoiristAdapter();
|
|
3027
|
+
init_XRateLimiter();
|
|
3028
|
+
init_RateLimiterFileStore();
|
|
3029
|
+
init_XParser();
|
|
3030
|
+
});
|
|
1782
3031
|
|
|
1783
3032
|
// src/index.ts
|
|
1784
|
-
var
|
|
1785
|
-
|
|
1786
|
-
|
|
3033
|
+
var exports_src = {};
|
|
3034
|
+
__export(exports_src, {
|
|
3035
|
+
default: () => exports_C,
|
|
3036
|
+
X: () => exports_X,
|
|
3037
|
+
WebSocketRoute: () => WebSocketRoute,
|
|
3038
|
+
Status: () => Status,
|
|
3039
|
+
StaticRouteAbstract: () => StaticRouteAbstract,
|
|
3040
|
+
StaticRoute: () => StaticRoute,
|
|
3041
|
+
Server: () => Server,
|
|
3042
|
+
Route: () => DynamicRoute,
|
|
3043
|
+
Response: () => CResponse,
|
|
3044
|
+
Request: () => CRequest,
|
|
3045
|
+
Repository: () => XRepository,
|
|
3046
|
+
RateLimiterRedisStore: () => RateLimiterRedisStore,
|
|
3047
|
+
RateLimiterMemoryStore: () => RateLimiterMemoryStore,
|
|
3048
|
+
RateLimiterFileStore: () => RateLimiterFileStore,
|
|
3049
|
+
RateLimiter: () => XRateLimiter,
|
|
3050
|
+
Parser: () => XParser,
|
|
3051
|
+
MiddlewareAbstract: () => MiddlewareAbstract,
|
|
3052
|
+
Middleware: () => Middleware,
|
|
3053
|
+
Method: () => Method,
|
|
3054
|
+
MemoiristAdapter: () => MemoiristAdapter,
|
|
3055
|
+
Headers: () => CHeaders,
|
|
3056
|
+
File: () => XFile,
|
|
3057
|
+
Extra: () => exports_X,
|
|
3058
|
+
Error: () => CError,
|
|
3059
|
+
DynamicRouteAbstract: () => DynamicRouteAbstract,
|
|
3060
|
+
Cors: () => XCors,
|
|
3061
|
+
Cookies: () => Cookies,
|
|
3062
|
+
Controller: () => Controller,
|
|
3063
|
+
Context: () => Context,
|
|
3064
|
+
Config: () => Config,
|
|
3065
|
+
CommonHeaders: () => CommonHeaders,
|
|
3066
|
+
C: () => exports_C,
|
|
3067
|
+
$routerStore: () => $routerStore,
|
|
3068
|
+
$prefixStore: () => $prefixStore,
|
|
3069
|
+
$corsStore: () => $corsStore
|
|
3070
|
+
});
|
|
3071
|
+
module.exports = __toCommonJS(exports_src);
|
|
3072
|
+
var $prefixStore, $routerStore, $corsStore;
|
|
3073
|
+
var init_src = __esm(() => {
|
|
3074
|
+
init_GlobalPrefixStore();
|
|
3075
|
+
init_GlobalRouterStore();
|
|
3076
|
+
init_GlobalCorsStore();
|
|
3077
|
+
init_C();
|
|
3078
|
+
init_X();
|
|
3079
|
+
init_C();
|
|
3080
|
+
init_X();
|
|
3081
|
+
$prefixStore = new GlobalPrefixStore;
|
|
3082
|
+
$routerStore = new GlobalRouterStore;
|
|
3083
|
+
$corsStore = new GlobalCorsStore;
|
|
3084
|
+
});
|
|
3085
|
+
init_src();
|
|
1787
3086
|
})
|