@ozanarslan/corpus 0.1.6 → 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/dist/index.cjs +2051 -979
- package/dist/index.d.ts +385 -152
- package/dist/index.js +2043 -945
- package/package.json +6 -2
package/dist/index.cjs
CHANGED
|
@@ -60,41 +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: () => exports_C,
|
|
68
|
-
_routerStore: () => _routerStore,
|
|
69
|
-
_prefixStore: () => _prefixStore,
|
|
70
|
-
_corsStore: () => _corsStore,
|
|
71
|
-
X: () => exports_X,
|
|
72
|
-
Status: () => Status,
|
|
73
|
-
StaticRoute: () => StaticRoute,
|
|
74
|
-
Server: () => Server,
|
|
75
|
-
Route: () => Route,
|
|
76
|
-
Response: () => CResponse,
|
|
77
|
-
Request: () => CRequest,
|
|
78
|
-
Repository: () => RepositoryAbstract,
|
|
79
|
-
Parser: () => Parser,
|
|
80
|
-
Middleware: () => Middleware,
|
|
81
|
-
Method: () => Method,
|
|
82
|
-
MemoiristAdapter: () => MemoiristAdapter,
|
|
83
|
-
Headers: () => CHeaders,
|
|
84
|
-
File: () => XFile,
|
|
85
|
-
Extra: () => exports_X,
|
|
86
|
-
Error: () => CError,
|
|
87
|
-
Cors: () => Cors,
|
|
88
|
-
Cookies: () => Cookies,
|
|
89
|
-
Controller: () => ControllerAbstract,
|
|
90
|
-
Context: () => Context,
|
|
91
|
-
Config: () => Config,
|
|
92
|
-
CommonHeaders: () => CommonHeaders,
|
|
93
|
-
C: () => exports_C
|
|
94
|
-
});
|
|
95
|
-
module.exports = __toCommonJS(exports_src);
|
|
96
|
-
|
|
97
|
-
// src/Store/StoreAbstract.ts
|
|
65
|
+
// src/store/StoreAbstract.ts
|
|
98
66
|
class StoreAbstract {
|
|
99
67
|
set(value) {
|
|
100
68
|
this.value = value;
|
|
@@ -104,53 +72,55 @@ class StoreAbstract {
|
|
|
104
72
|
}
|
|
105
73
|
}
|
|
106
74
|
|
|
107
|
-
// src/
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
75
|
+
// src/store/GlobalPrefixStore.ts
|
|
76
|
+
var GlobalPrefixStore;
|
|
77
|
+
var init_GlobalPrefixStore = __esm(() => {
|
|
78
|
+
GlobalPrefixStore = class GlobalPrefixStore extends StoreAbstract {
|
|
79
|
+
value = "";
|
|
80
|
+
};
|
|
81
|
+
});
|
|
111
82
|
|
|
112
|
-
// src/
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (!this.value) {
|
|
117
|
-
console.error("Router instance is not set. Please instantiate your Server before your routes.");
|
|
118
|
-
process.exit(1);
|
|
119
|
-
}
|
|
120
|
-
return this.value;
|
|
121
|
-
}
|
|
83
|
+
// src/utils/internalLogger.ts
|
|
84
|
+
function logFatal(...args) {
|
|
85
|
+
console.error(...args);
|
|
86
|
+
process.exit(1);
|
|
122
87
|
}
|
|
88
|
+
var log;
|
|
89
|
+
var init_internalLogger = __esm(() => {
|
|
90
|
+
log = console;
|
|
91
|
+
});
|
|
123
92
|
|
|
124
|
-
// src/
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
});
|
|
128
107
|
|
|
129
|
-
// src/
|
|
130
|
-
var
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
Route: () => Route,
|
|
136
|
-
Response: () => CResponse,
|
|
137
|
-
Request: () => CRequest,
|
|
138
|
-
Middleware: () => Middleware,
|
|
139
|
-
Method: () => Method,
|
|
140
|
-
Headers: () => CHeaders,
|
|
141
|
-
Error: () => CError,
|
|
142
|
-
Cookies: () => Cookies,
|
|
143
|
-
Controller: () => ControllerAbstract,
|
|
144
|
-
Context: () => Context,
|
|
145
|
-
Config: () => Config,
|
|
146
|
-
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
|
+
};
|
|
147
114
|
});
|
|
148
115
|
|
|
149
116
|
// src/Config/enums/RuntimeOptions.ts
|
|
150
|
-
var RuntimeOptions
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
117
|
+
var RuntimeOptions;
|
|
118
|
+
var init_RuntimeOptions = __esm(() => {
|
|
119
|
+
RuntimeOptions = {
|
|
120
|
+
bun: "bun",
|
|
121
|
+
node: "node"
|
|
122
|
+
};
|
|
123
|
+
});
|
|
154
124
|
|
|
155
125
|
// src/utils/strIsDefined.ts
|
|
156
126
|
function strIsDefined(input) {
|
|
@@ -158,8 +128,6 @@ function strIsDefined(input) {
|
|
|
158
128
|
}
|
|
159
129
|
|
|
160
130
|
// src/Config/Config.ts
|
|
161
|
-
var import_path = __toESM(require("path"));
|
|
162
|
-
|
|
163
131
|
class Config {
|
|
164
132
|
static get runtime() {
|
|
165
133
|
if (typeof Bun !== "undefined") {
|
|
@@ -168,7 +136,7 @@ class Config {
|
|
|
168
136
|
if (typeof process !== "undefined" && process?.env) {
|
|
169
137
|
return RuntimeOptions.node;
|
|
170
138
|
}
|
|
171
|
-
|
|
139
|
+
log.warn("\u26A0\uFE0F Runtime isn't Bun or NodeJS. Features may not be available. App might not start.");
|
|
172
140
|
return "unknown";
|
|
173
141
|
}
|
|
174
142
|
static get nodeEnv() {
|
|
@@ -181,7 +149,7 @@ class Config {
|
|
|
181
149
|
case RuntimeOptions.node:
|
|
182
150
|
return process.env;
|
|
183
151
|
default:
|
|
184
|
-
|
|
152
|
+
log.warn("\u26A0\uFE0F process.env wasn't available. Your environment variables are in memory.");
|
|
185
153
|
return {};
|
|
186
154
|
}
|
|
187
155
|
}
|
|
@@ -199,7 +167,7 @@ class Config {
|
|
|
199
167
|
if (opts?.fallback !== undefined) {
|
|
200
168
|
return opts?.fallback;
|
|
201
169
|
}
|
|
202
|
-
|
|
170
|
+
log.warn(`${key} doesn't exist in env`);
|
|
203
171
|
return;
|
|
204
172
|
}
|
|
205
173
|
static set(key, value) {
|
|
@@ -214,121 +182,140 @@ class Config {
|
|
|
214
182
|
this.env[key] = value;
|
|
215
183
|
}
|
|
216
184
|
}
|
|
185
|
+
var import_path;
|
|
186
|
+
var init_Config = __esm(() => {
|
|
187
|
+
init_RuntimeOptions();
|
|
188
|
+
init_internalLogger();
|
|
189
|
+
import_path = __toESM(require("path"));
|
|
190
|
+
});
|
|
191
|
+
|
|
217
192
|
// src/CResponse/enums/Status.ts
|
|
218
|
-
var Status
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
+
});
|
|
282
260
|
|
|
283
261
|
// src/CResponse/enums/DefaultStatusTexts.ts
|
|
284
|
-
var DefaultStatusTexts
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
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
|
+
});
|
|
299
281
|
|
|
300
282
|
// src/CHeaders/enums/CommonHeaders.ts
|
|
301
|
-
var CommonHeaders
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
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
|
+
});
|
|
329
315
|
|
|
330
316
|
// src/Cookies/CookiesAbstract.ts
|
|
331
317
|
class CookiesAbstract {
|
|
318
|
+
constructor(_) {}
|
|
332
319
|
applyInit(init) {
|
|
333
320
|
if (!init)
|
|
334
321
|
return;
|
|
@@ -347,102 +334,297 @@ class CookiesAbstract {
|
|
|
347
334
|
}
|
|
348
335
|
}
|
|
349
336
|
|
|
350
|
-
// src/Cookies/
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
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
|
+
}
|
|
366
360
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
}
|
|
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);
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
-
// src/
|
|
392
|
-
|
|
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);
|
|
393
395
|
}
|
|
394
396
|
|
|
395
|
-
// src/
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
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);
|
|
411
412
|
}
|
|
412
|
-
|
|
413
|
-
|
|
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;
|
|
414
421
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
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}`;
|
|
419
534
|
} else {
|
|
420
|
-
|
|
535
|
+
result += `; Path=/`;
|
|
421
536
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
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;
|
|
434
562
|
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
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);
|
|
443
580
|
}
|
|
444
|
-
|
|
445
|
-
|
|
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
|
+
});
|
|
446
628
|
|
|
447
629
|
// src/utils/isNil.ts
|
|
448
630
|
function isNil(input) {
|
|
@@ -460,43 +642,31 @@ function isPlainObject(input) {
|
|
|
460
642
|
}
|
|
461
643
|
|
|
462
644
|
// src/CError/CError.ts
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
const status = Status.NOT_FOUND;
|
|
489
|
-
return new this(msg ?? status.toString(), status);
|
|
490
|
-
}
|
|
491
|
-
static methodNotAllowed(msg) {
|
|
492
|
-
const status = Status.METHOD_NOT_ALLOWED;
|
|
493
|
-
return new this(msg ?? status.toString(), status);
|
|
494
|
-
}
|
|
495
|
-
static unprocessableEntity(msg) {
|
|
496
|
-
const status = Status.UNPROCESSABLE_ENTITY;
|
|
497
|
-
return new this(msg ?? status.toString(), status);
|
|
498
|
-
}
|
|
499
|
-
}
|
|
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;
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
});
|
|
500
670
|
|
|
501
671
|
// src/XFile/XFileAbstract.ts
|
|
502
672
|
class XFileAbstract {
|
|
@@ -542,27 +712,73 @@ class XFileAbstract {
|
|
|
542
712
|
}
|
|
543
713
|
}
|
|
544
714
|
|
|
545
|
-
// src/XFile/
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
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
|
+
});
|
|
562
773
|
|
|
563
774
|
// src/XFile/XFile.ts
|
|
564
|
-
|
|
565
|
-
|
|
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
|
+
|
|
566
782
|
// src/CResponse/CResponse.ts
|
|
567
783
|
class CResponse {
|
|
568
784
|
data;
|
|
@@ -574,7 +790,7 @@ class CResponse {
|
|
|
574
790
|
this.headers = this.resolveHeaders();
|
|
575
791
|
this.body = this.resolveBody();
|
|
576
792
|
this.status = this.resolveStatus();
|
|
577
|
-
this.statusText =
|
|
793
|
+
this.statusText = CResponse.getDefaultStatusText(this.status);
|
|
578
794
|
}
|
|
579
795
|
body;
|
|
580
796
|
headers;
|
|
@@ -679,8 +895,9 @@ class CResponse {
|
|
|
679
895
|
}
|
|
680
896
|
static async streamFile(filePath, disposition = "attachment", init) {
|
|
681
897
|
const file = new XFile(filePath);
|
|
682
|
-
|
|
683
|
-
|
|
898
|
+
const exists = await file.exists();
|
|
899
|
+
if (!exists) {
|
|
900
|
+
throw new CError(Status.NOT_FOUND.toString(), Status.NOT_FOUND, new CResponse({ filePath }, init));
|
|
684
901
|
}
|
|
685
902
|
const stream = file.stream();
|
|
686
903
|
const res = new CResponse(stream, { ...init, status: Status.OK });
|
|
@@ -692,8 +909,9 @@ class CResponse {
|
|
|
692
909
|
}
|
|
693
910
|
static async file(filePath, init) {
|
|
694
911
|
const file = new XFile(filePath);
|
|
695
|
-
|
|
696
|
-
|
|
912
|
+
const exists = await file.exists();
|
|
913
|
+
if (!exists) {
|
|
914
|
+
throw new CError(Status.NOT_FOUND.toString(), Status.NOT_FOUND, new CResponse({ filePath }, init));
|
|
697
915
|
}
|
|
698
916
|
const content = await file.text();
|
|
699
917
|
const res = new CResponse(content, init);
|
|
@@ -704,7 +922,7 @@ class CResponse {
|
|
|
704
922
|
return res;
|
|
705
923
|
}
|
|
706
924
|
resolveCookies() {
|
|
707
|
-
return new Cookies(this.init?.cookies);
|
|
925
|
+
return this.init?.cookies instanceof Cookies ? this.init.cookies : new Cookies(this.init?.cookies);
|
|
708
926
|
}
|
|
709
927
|
resolveHeaders() {
|
|
710
928
|
const headers = new CHeaders(this.init?.headers);
|
|
@@ -769,24 +987,36 @@ class CResponse {
|
|
|
769
987
|
this.setContentType("text/plain");
|
|
770
988
|
return String(this.data);
|
|
771
989
|
}
|
|
772
|
-
getDefaultStatusText() {
|
|
773
|
-
const key =
|
|
990
|
+
static getDefaultStatusText(status) {
|
|
991
|
+
const key = status;
|
|
774
992
|
return DefaultStatusTexts[key] ?? "Unknown";
|
|
775
993
|
}
|
|
776
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
|
+
});
|
|
777
1004
|
|
|
778
1005
|
// src/CRequest/enums/Method.ts
|
|
779
|
-
var Method
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
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
|
+
});
|
|
790
1020
|
|
|
791
1021
|
// src/utils/arrIncludes.ts
|
|
792
1022
|
function arrIncludes(input, array) {
|
|
@@ -808,15 +1038,15 @@ function objAppendEntry(data, key, value) {
|
|
|
808
1038
|
}
|
|
809
1039
|
}
|
|
810
1040
|
|
|
811
|
-
// src/Model/
|
|
812
|
-
class
|
|
1041
|
+
// src/Model/XParser.ts
|
|
1042
|
+
class XParser {
|
|
813
1043
|
static async parse(data, validate) {
|
|
814
1044
|
if (!validate)
|
|
815
1045
|
return data;
|
|
816
1046
|
const result = await validate(data);
|
|
817
1047
|
if (result.issues !== undefined) {
|
|
818
1048
|
const msg = this.issuesToErrorMessage(result.issues);
|
|
819
|
-
throw CError
|
|
1049
|
+
throw new CError(msg, Status.UNPROCESSABLE_ENTITY, data);
|
|
820
1050
|
}
|
|
821
1051
|
return result.value;
|
|
822
1052
|
}
|
|
@@ -844,7 +1074,7 @@ class Parser {
|
|
|
844
1074
|
const empty = {};
|
|
845
1075
|
const input = r instanceof Request ? r : r instanceof Response ? r : r.response;
|
|
846
1076
|
try {
|
|
847
|
-
switch (
|
|
1077
|
+
switch (XParser.getNormalizedContentType(input)) {
|
|
848
1078
|
case "json":
|
|
849
1079
|
data = await this.getJsonBody(input);
|
|
850
1080
|
break;
|
|
@@ -965,6 +1195,12 @@ class Parser {
|
|
|
965
1195
|
return "unknown";
|
|
966
1196
|
}
|
|
967
1197
|
}
|
|
1198
|
+
var init_XParser = __esm(() => {
|
|
1199
|
+
init_Status();
|
|
1200
|
+
init_Method();
|
|
1201
|
+
init_CommonHeaders();
|
|
1202
|
+
init_CError();
|
|
1203
|
+
});
|
|
968
1204
|
|
|
969
1205
|
// src/Context/Context.ts
|
|
970
1206
|
class Context {
|
|
@@ -991,66 +1227,24 @@ class Context {
|
|
|
991
1227
|
return new Context(req, {}, {}, {});
|
|
992
1228
|
}
|
|
993
1229
|
static async appendParsedData(ctx, req, params, search, model) {
|
|
994
|
-
ctx.body = await
|
|
995
|
-
ctx.params = await
|
|
996
|
-
ctx.search = await
|
|
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);
|
|
997
1233
|
}
|
|
998
1234
|
}
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
};
|
|
1004
|
-
|
|
1005
|
-
// src/utils/joinPathSegments.ts
|
|
1006
|
-
function joinPathSegments(...segments) {
|
|
1007
|
-
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("/");
|
|
1008
|
-
return `/${joined}`;
|
|
1009
|
-
}
|
|
1235
|
+
var init_Context = __esm(() => {
|
|
1236
|
+
init_CResponse();
|
|
1237
|
+
init_XParser();
|
|
1238
|
+
});
|
|
1010
1239
|
|
|
1011
1240
|
// src/Route/RouteAbstract.ts
|
|
1012
1241
|
class RouteAbstract {
|
|
1013
|
-
resolveEndpoint(definition, variant) {
|
|
1014
|
-
const endpoint = typeof definition === "string" ? definition : definition.path;
|
|
1015
|
-
if (variant === RouteVariant.dynamic) {
|
|
1016
|
-
return joinPathSegments(_prefixStore.get(), endpoint);
|
|
1017
|
-
}
|
|
1018
|
-
return endpoint;
|
|
1019
|
-
}
|
|
1020
|
-
resolveMethod(definition) {
|
|
1021
|
-
return typeof definition === "string" ? Method.GET : definition.method;
|
|
1022
|
-
}
|
|
1023
1242
|
resolvePattern(endpoint) {
|
|
1024
|
-
return
|
|
1243
|
+
return RouteAbstract.makeRoutePattern(endpoint);
|
|
1025
1244
|
}
|
|
1026
1245
|
resolveId(method, endpoint) {
|
|
1027
|
-
return
|
|
1246
|
+
return RouteAbstract.makeRouteId(method, endpoint);
|
|
1028
1247
|
}
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
// src/Route/Route.ts
|
|
1032
|
-
class Route extends RouteAbstract {
|
|
1033
|
-
constructor(definition, handler, model) {
|
|
1034
|
-
super();
|
|
1035
|
-
this.variant = RouteVariant.dynamic;
|
|
1036
|
-
this.endpoint = this.resolveEndpoint(definition, this.variant);
|
|
1037
|
-
this.method = this.resolveMethod(definition);
|
|
1038
|
-
this.pattern = this.resolvePattern(this.endpoint);
|
|
1039
|
-
this.id = this.resolveId(this.method, this.endpoint);
|
|
1040
|
-
this.model = model;
|
|
1041
|
-
this.handler = handler;
|
|
1042
|
-
_routerStore.get().addRoute(this);
|
|
1043
|
-
if (model) {
|
|
1044
|
-
_routerStore.get().addModel(this, model);
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
variant;
|
|
1048
|
-
endpoint;
|
|
1049
|
-
method;
|
|
1050
|
-
pattern;
|
|
1051
|
-
id;
|
|
1052
|
-
handler;
|
|
1053
|
-
model;
|
|
1054
1248
|
static makeRouteId(method, endpoint) {
|
|
1055
1249
|
return `${method.toUpperCase()} ${endpoint}`;
|
|
1056
1250
|
}
|
|
@@ -1060,66 +1254,144 @@ class Route extends RouteAbstract {
|
|
|
1060
1254
|
}
|
|
1061
1255
|
}
|
|
1062
1256
|
|
|
1063
|
-
// src/
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
this.variant = RouteVariant.static;
|
|
1068
|
-
this.endpoint = this.resolveEndpoint(path2, this.variant);
|
|
1069
|
-
this.method = Method.GET;
|
|
1070
|
-
this.pattern = this.resolvePattern(this.endpoint);
|
|
1071
|
-
this.id = this.resolveId(this.method, this.endpoint);
|
|
1072
|
-
this.model = model;
|
|
1073
|
-
this.filePath = this.resolveFilePath(definition);
|
|
1074
|
-
this.handler = this.resolveHandler(definition, handler);
|
|
1075
|
-
_routerStore.get().addRoute(this);
|
|
1076
|
-
}
|
|
1077
|
-
id;
|
|
1078
|
-
variant;
|
|
1079
|
-
method;
|
|
1080
|
-
endpoint;
|
|
1081
|
-
pattern;
|
|
1082
|
-
model;
|
|
1083
|
-
handler;
|
|
1084
|
-
filePath;
|
|
1085
|
-
resolveFilePath(definition) {
|
|
1086
|
-
return typeof definition === "string" ? definition : definition.filePath;
|
|
1087
|
-
}
|
|
1088
|
-
resolveHandler(definition, customHandler) {
|
|
1089
|
-
if (customHandler !== undefined) {
|
|
1090
|
-
return async (c) => {
|
|
1091
|
-
const file = new XFile(this.filePath);
|
|
1092
|
-
if (!file) {
|
|
1093
|
-
console.error("File not found at:", this.filePath);
|
|
1094
|
-
throw CError.notFound();
|
|
1095
|
-
}
|
|
1096
|
-
const content = await file.text();
|
|
1097
|
-
c.res.headers.setMany({
|
|
1098
|
-
[CommonHeaders.ContentType]: file.mimeType,
|
|
1099
|
-
[CommonHeaders.ContentLength]: content.length.toString()
|
|
1100
|
-
});
|
|
1101
|
-
return customHandler(c, content);
|
|
1102
|
-
};
|
|
1103
|
-
} else if (typeof definition === "string") {
|
|
1104
|
-
return async () => await CResponse.file(this.filePath);
|
|
1105
|
-
} else {
|
|
1106
|
-
return async () => await CResponse.streamFile(this.filePath);
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
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}`;
|
|
1109
1261
|
}
|
|
1110
1262
|
|
|
1111
|
-
// src/
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
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
|
+
});
|
|
1272
|
+
|
|
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
|
+
}
|
|
1287
|
+
};
|
|
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;
|
|
1312
|
+
};
|
|
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
|
+
});
|
|
1382
|
+
|
|
1383
|
+
// src/Controller/Controller.ts
|
|
1384
|
+
class Controller {
|
|
1385
|
+
constructor(opts) {
|
|
1386
|
+
this.prefix = opts?.prefix;
|
|
1387
|
+
this.beforeEach = opts?.beforeEach;
|
|
1388
|
+
}
|
|
1389
|
+
routeIds = new Set;
|
|
1390
|
+
prefix;
|
|
1391
|
+
beforeEach;
|
|
1392
|
+
route(...args) {
|
|
1121
1393
|
const [definition, handler, model] = args;
|
|
1122
|
-
const route = new
|
|
1394
|
+
const route = new DynamicRoute(this.resolveRouteDefinition(definition), async (ctx) => {
|
|
1123
1395
|
await this.beforeEach?.(ctx);
|
|
1124
1396
|
return handler(ctx);
|
|
1125
1397
|
}, model);
|
|
@@ -1142,105 +1414,143 @@ class ControllerAbstract {
|
|
|
1142
1414
|
};
|
|
1143
1415
|
}
|
|
1144
1416
|
}
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
this.handler = opts.handler;
|
|
1150
|
-
_routerStore.get().addMiddleware(opts);
|
|
1151
|
-
}
|
|
1152
|
-
useOn;
|
|
1153
|
-
handler;
|
|
1154
|
-
}
|
|
1155
|
-
// src/utils/assert.ts
|
|
1156
|
-
function assert(condition, message) {
|
|
1157
|
-
const conditionName = String(condition);
|
|
1158
|
-
if (!condition) {
|
|
1159
|
-
if (!message) {
|
|
1160
|
-
message = `Assertion failed for ${conditionName}`;
|
|
1161
|
-
} else {
|
|
1162
|
-
message = `${conditionName}: ${message}`;
|
|
1163
|
-
}
|
|
1164
|
-
throw new Error(message);
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1417
|
+
var init_Controller = __esm(() => {
|
|
1418
|
+
init_DynamicRoute();
|
|
1419
|
+
init_StaticRoute();
|
|
1420
|
+
});
|
|
1167
1421
|
|
|
1168
|
-
// src/
|
|
1169
|
-
|
|
1170
|
-
const parts = input.split(mark).map((part) => part.trim()).filter(Boolean);
|
|
1171
|
-
if (minLength) {
|
|
1172
|
-
assert(parts.length >= minLength);
|
|
1173
|
-
return parts;
|
|
1174
|
-
}
|
|
1175
|
-
return parts;
|
|
1422
|
+
// src/Middleware/MiddlewareAbstract.ts
|
|
1423
|
+
class MiddlewareAbstract {
|
|
1176
1424
|
}
|
|
1177
1425
|
|
|
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
|
+
|
|
1178
1442
|
// src/CRequest/CRequest.ts
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
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;
|
|
1483
|
+
}
|
|
1484
|
+
if (!urlObject.pathname) {
|
|
1485
|
+
urlObject.pathname += "/";
|
|
1486
|
+
}
|
|
1487
|
+
return urlObject;
|
|
1213
1488
|
}
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
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;
|
|
1219
1511
|
}
|
|
1220
|
-
|
|
1221
|
-
return
|
|
1512
|
+
resolveIsPreflight() {
|
|
1513
|
+
return this.method === Method.OPTIONS && this.headers.has(CommonHeaders.AccessControlRequestMethod);
|
|
1222
1514
|
}
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
const cookieHeader = this.headers.get(CommonHeaders.Cookie);
|
|
1228
|
-
if (cookieHeader) {
|
|
1229
|
-
const pairs = strSplit(";", cookieHeader);
|
|
1230
|
-
for (const pair of pairs) {
|
|
1231
|
-
const [name, value] = strSplit("=", pair);
|
|
1232
|
-
if (!name || !value)
|
|
1233
|
-
continue;
|
|
1234
|
-
jar.set({ name, value });
|
|
1235
|
-
}
|
|
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;
|
|
1236
1519
|
}
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1520
|
+
};
|
|
1521
|
+
});
|
|
1522
|
+
|
|
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
|
+
});
|
|
1553
|
+
|
|
1244
1554
|
// src/utils/isRegexMatch.ts
|
|
1245
1555
|
function isRegexMatch(source, pattern) {
|
|
1246
1556
|
return pattern.test(source);
|
|
@@ -1259,134 +1569,21 @@ function strIsEqual(source, target, modifier) {
|
|
|
1259
1569
|
return source === target;
|
|
1260
1570
|
}
|
|
1261
1571
|
|
|
1262
|
-
// src/Store/LazyMap.ts
|
|
1263
|
-
class LazyMap {
|
|
1264
|
-
constructor() {
|
|
1265
|
-
return new Proxy(this, {
|
|
1266
|
-
get(target, prop) {
|
|
1267
|
-
const val = Reflect.get(target.map, prop);
|
|
1268
|
-
return typeof val === "function" ? val.bind(target.map) : val;
|
|
1269
|
-
}
|
|
1270
|
-
});
|
|
1271
|
-
}
|
|
1272
|
-
_map;
|
|
1273
|
-
get map() {
|
|
1274
|
-
if (!this._map) {
|
|
1275
|
-
this._map = new Map;
|
|
1276
|
-
}
|
|
1277
|
-
return this._map;
|
|
1278
|
-
}
|
|
1279
|
-
get [Symbol.toStringTag]() {
|
|
1280
|
-
return "LazyMap";
|
|
1281
|
-
}
|
|
1282
|
-
}
|
|
1283
|
-
|
|
1284
|
-
// src/utils/strRemoveWhitespace.ts
|
|
1285
|
-
function strRemoveWhitespace(str) {
|
|
1286
|
-
return str.trim().replace(/\s+/g, "");
|
|
1287
|
-
}
|
|
1288
|
-
|
|
1289
|
-
// src/Router/registries/ModelRegistry.ts
|
|
1290
|
-
class ModelRegistry {
|
|
1291
|
-
map = new LazyMap;
|
|
1292
|
-
add(method, endpoint, model) {
|
|
1293
|
-
const entry = ModelRegistry.toRouterModelData(model);
|
|
1294
|
-
this.map.set(Route.makeRouteId(method, endpoint), entry);
|
|
1295
|
-
}
|
|
1296
|
-
find(routeId) {
|
|
1297
|
-
return this.map.get(routeId);
|
|
1298
|
-
}
|
|
1299
|
-
static internFuncMap = new LazyMap;
|
|
1300
|
-
static toRouterModelData(model) {
|
|
1301
|
-
const entry = {};
|
|
1302
|
-
for (const k of Object.keys(model)) {
|
|
1303
|
-
const key = k;
|
|
1304
|
-
const schema = model[key];
|
|
1305
|
-
if (!schema)
|
|
1306
|
-
continue;
|
|
1307
|
-
const handler = schema["~standard"].validate;
|
|
1308
|
-
entry[key] = this.intern(handler, "model", strRemoveWhitespace(JSON.stringify(schema)));
|
|
1309
|
-
}
|
|
1310
|
-
return entry;
|
|
1311
|
-
}
|
|
1312
|
-
static intern(value, ...namespace) {
|
|
1313
|
-
const key = namespace.join("::");
|
|
1314
|
-
const existing = this.internFuncMap.get(key);
|
|
1315
|
-
if (existing)
|
|
1316
|
-
return existing;
|
|
1317
|
-
this.internFuncMap.set(key, value);
|
|
1318
|
-
return value;
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
|
-
// src/utils/compile.ts
|
|
1323
|
-
function compile(fns) {
|
|
1324
|
-
return async (...args) => {
|
|
1325
|
-
for (const fn of fns) {
|
|
1326
|
-
if (!fn)
|
|
1327
|
-
continue;
|
|
1328
|
-
await fn(...args);
|
|
1329
|
-
}
|
|
1330
|
-
};
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
// src/Router/registries/MiddlewareRegistry.ts
|
|
1334
|
-
class MiddlewareRegistry {
|
|
1335
|
-
middlewares = new LazyMap;
|
|
1336
|
-
add(m) {
|
|
1337
|
-
const resolved = MiddlewareRegistry.resolveRouteIds(m);
|
|
1338
|
-
if (resolved.isGlobal) {
|
|
1339
|
-
const existing = this.middlewares.get("*") ?? [];
|
|
1340
|
-
this.middlewares.set("*", [...existing, m.handler]);
|
|
1341
|
-
return;
|
|
1342
|
-
}
|
|
1343
|
-
for (const routeId of resolved.routeIds) {
|
|
1344
|
-
const existing = this.middlewares.get(routeId) ?? [];
|
|
1345
|
-
this.middlewares.set(routeId, [...existing, m.handler]);
|
|
1346
|
-
}
|
|
1347
|
-
}
|
|
1348
|
-
find(routeId) {
|
|
1349
|
-
const globals = this.middlewares.get("*") ?? [];
|
|
1350
|
-
const locals = this.middlewares.get(routeId) ?? [];
|
|
1351
|
-
return compile([...globals, ...locals]);
|
|
1352
|
-
}
|
|
1353
|
-
static resolveRouteIds(m) {
|
|
1354
|
-
if (m.useOn === "*")
|
|
1355
|
-
return { isGlobal: true };
|
|
1356
|
-
const targets = Array.isArray(m.useOn) ? m.useOn : [m.useOn];
|
|
1357
|
-
const routeIds = [];
|
|
1358
|
-
for (const target of targets) {
|
|
1359
|
-
if (target instanceof Route) {
|
|
1360
|
-
routeIds.push(target.id);
|
|
1361
|
-
} else if (target instanceof ControllerAbstract) {
|
|
1362
|
-
routeIds.push(...target.routeIds);
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
return { isGlobal: false, routeIds };
|
|
1366
|
-
}
|
|
1367
|
-
}
|
|
1368
|
-
|
|
1369
1572
|
// src/Router/adapters/CorpusAdapter.ts
|
|
1370
1573
|
class CorpusAdapter {
|
|
1371
1574
|
routes = new Map;
|
|
1372
|
-
|
|
1373
|
-
middlewareRegistry = new MiddlewareRegistry;
|
|
1374
|
-
addRoute(data) {
|
|
1575
|
+
add(data) {
|
|
1375
1576
|
this.checkPossibleCollision(data);
|
|
1376
1577
|
this.routes.set(data.id, data);
|
|
1377
1578
|
}
|
|
1378
|
-
addModel(route, model) {
|
|
1379
|
-
this.modelRegistry.add(route.method, route.endpoint, model);
|
|
1380
|
-
}
|
|
1381
|
-
addMiddleware(middleware) {
|
|
1382
|
-
this.middlewareRegistry.add(middleware);
|
|
1383
|
-
}
|
|
1384
1579
|
find(req) {
|
|
1385
1580
|
const method = req.method;
|
|
1386
1581
|
const pathname = req.urlObject.pathname;
|
|
1387
1582
|
const searchParams = req.urlObject.searchParams;
|
|
1388
1583
|
let route = null;
|
|
1389
1584
|
for (const data of this.routes.values()) {
|
|
1585
|
+
if (method !== data.method)
|
|
1586
|
+
continue;
|
|
1390
1587
|
if (this.hasAnyParam(data.endpoint) && isRegexMatch(pathname, data.pattern)) {
|
|
1391
1588
|
route = data;
|
|
1392
1589
|
break;
|
|
@@ -1401,15 +1598,10 @@ class CorpusAdapter {
|
|
|
1401
1598
|
}
|
|
1402
1599
|
}
|
|
1403
1600
|
if (route === null) {
|
|
1404
|
-
|
|
1405
|
-
}
|
|
1406
|
-
if (!strIsEqual(method, route.method, "upper")) {
|
|
1407
|
-
throw CError.methodNotAllowed();
|
|
1601
|
+
return null;
|
|
1408
1602
|
}
|
|
1409
1603
|
return {
|
|
1410
1604
|
route,
|
|
1411
|
-
model: this.modelRegistry.find(route.id),
|
|
1412
|
-
middleware: this.middlewareRegistry.find(route.id),
|
|
1413
1605
|
params: this.extractParams(pathname, route.endpoint),
|
|
1414
1606
|
search: Object.fromEntries(searchParams)
|
|
1415
1607
|
};
|
|
@@ -1418,10 +1610,10 @@ class CorpusAdapter {
|
|
|
1418
1610
|
return Array.from(this.routes.values());
|
|
1419
1611
|
}
|
|
1420
1612
|
checkPossibleCollision(n) {
|
|
1421
|
-
const dupeMsg = (nId) =>
|
|
1422
|
-
const dynamicPatternMsg = (nId, oId) =>
|
|
1423
|
-
const baseDupeMsg = (nId, oId) =>
|
|
1424
|
-
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.`);
|
|
1425
1617
|
const existing = this.routes.get(n.id);
|
|
1426
1618
|
if (existing) {
|
|
1427
1619
|
dupeMsg(n.id);
|
|
@@ -1446,7 +1638,7 @@ class CorpusAdapter {
|
|
|
1446
1638
|
}
|
|
1447
1639
|
const oHasLastPartParam = this.hasLastPartParam(o.endpoint);
|
|
1448
1640
|
if (oHasLastPartParam) {
|
|
1449
|
-
if (isRegexMatch(n.endpoint,
|
|
1641
|
+
if (isRegexMatch(n.endpoint, DynamicRoute.makeRoutePattern(this.removeLastParam(o.endpoint)))) {
|
|
1450
1642
|
shadowMsg(n.id, o.id);
|
|
1451
1643
|
return true;
|
|
1452
1644
|
}
|
|
@@ -1485,123 +1677,258 @@ class CorpusAdapter {
|
|
|
1485
1677
|
return endpoint.split("/").some((p) => p.startsWith(":"));
|
|
1486
1678
|
}
|
|
1487
1679
|
}
|
|
1680
|
+
var init_CorpusAdapter = __esm(() => {
|
|
1681
|
+
init_DynamicRoute();
|
|
1682
|
+
init_internalLogger();
|
|
1683
|
+
});
|
|
1488
1684
|
|
|
1489
|
-
// src/
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
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;
|
|
1701
|
+
}
|
|
1702
|
+
return this._map;
|
|
1703
|
+
}
|
|
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, "");
|
|
1713
|
+
}
|
|
1714
|
+
|
|
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;
|
|
1740
|
+
}
|
|
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)
|
|
1757
|
+
continue;
|
|
1758
|
+
await fn(...args);
|
|
1759
|
+
}
|
|
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) {
|
|
1769
|
+
const existing = this.middlewares.get("*") ?? [];
|
|
1770
|
+
this.middlewares.set("*", [...existing, middleware.handler]);
|
|
1771
|
+
return;
|
|
1772
|
+
}
|
|
1773
|
+
for (const routeId of resolved.routeIds) {
|
|
1774
|
+
const existing = this.middlewares.get(routeId) ?? [];
|
|
1775
|
+
this.middlewares.set(routeId, [...existing, middleware.handler]);
|
|
1776
|
+
}
|
|
1493
1777
|
}
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
if (
|
|
1499
|
-
return
|
|
1778
|
+
find(routeId) {
|
|
1779
|
+
return compile(this.middlewares.get(routeId) ?? []);
|
|
1780
|
+
}
|
|
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
|
+
}
|
|
1500
1792
|
}
|
|
1501
|
-
return false;
|
|
1793
|
+
return { isGlobal: false, routeIds };
|
|
1502
1794
|
}
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
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;
|
|
1506
1807
|
}
|
|
1808
|
+
modelRegistry = new ModelRegistry;
|
|
1809
|
+
middlewareRegistry = new MiddlewareRegistry;
|
|
1810
|
+
cache = new WeakMap;
|
|
1507
1811
|
addMiddleware(middleware) {
|
|
1508
|
-
this.
|
|
1509
|
-
}
|
|
1510
|
-
|
|
1511
|
-
this.
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
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
|
|
1517
1825
|
});
|
|
1826
|
+
if (route.model) {
|
|
1827
|
+
this.modelRegistry.add(route.id, route.model);
|
|
1828
|
+
}
|
|
1518
1829
|
}
|
|
1519
1830
|
findRouteHandler(req) {
|
|
1520
|
-
const
|
|
1521
|
-
if (cached)
|
|
1522
|
-
return cached;
|
|
1523
|
-
const match = this._adapter.find(req);
|
|
1831
|
+
const match = this.cache.get(req) ?? this.adapter.find(req);
|
|
1524
1832
|
if (!match)
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
const
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
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;
|
|
1846
|
+
}
|
|
1847
|
+
return new CResponse(result, ctx.res);
|
|
1537
1848
|
};
|
|
1538
|
-
this.cache.set(req, handler);
|
|
1539
|
-
return handler;
|
|
1540
1849
|
}
|
|
1541
1850
|
getRouteList() {
|
|
1542
|
-
return this.
|
|
1851
|
+
return this.adapter.list().map((v) => [v.method, v.endpoint]);
|
|
1543
1852
|
}
|
|
1544
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
|
+
});
|
|
1545
1862
|
|
|
1546
1863
|
// src/Server/ServerAbstract.ts
|
|
1547
1864
|
class ServerAbstract {
|
|
1548
1865
|
opts;
|
|
1549
1866
|
constructor(opts) {
|
|
1550
1867
|
this.opts = opts;
|
|
1551
|
-
|
|
1868
|
+
$routerStore.set(new Router(opts?.adapter));
|
|
1552
1869
|
}
|
|
1553
1870
|
get routes() {
|
|
1554
|
-
return
|
|
1871
|
+
return $routerStore.get().getRouteList();
|
|
1555
1872
|
}
|
|
1556
1873
|
setGlobalPrefix(value) {
|
|
1557
|
-
|
|
1874
|
+
$prefixStore.set(value);
|
|
1558
1875
|
}
|
|
1559
1876
|
async listen(port, hostname = "0.0.0.0") {
|
|
1560
1877
|
try {
|
|
1561
1878
|
process.on("SIGINT", () => this.close());
|
|
1562
1879
|
process.on("SIGTERM", () => this.close());
|
|
1563
|
-
|
|
1880
|
+
log.log(`Listening on ${hostname}:${port}`);
|
|
1564
1881
|
await this.handleBeforeListen?.();
|
|
1565
1882
|
this.serve({
|
|
1566
1883
|
port,
|
|
1567
|
-
hostname
|
|
1568
|
-
fetch: (r) => this.handle(r)
|
|
1884
|
+
hostname
|
|
1569
1885
|
});
|
|
1570
1886
|
} catch (err) {
|
|
1571
|
-
|
|
1887
|
+
log.error("Server unable to start:", err);
|
|
1572
1888
|
await this.close();
|
|
1573
1889
|
}
|
|
1574
1890
|
}
|
|
1575
1891
|
async handle(request) {
|
|
1576
1892
|
const req = new CRequest(request);
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
if (this.handleAfterResponse) {
|
|
1583
|
-
res = await this.handleAfterResponse(res);
|
|
1893
|
+
const handled = await this.handleRequest(req, () => {
|
|
1894
|
+
return;
|
|
1895
|
+
});
|
|
1896
|
+
if (!handled) {
|
|
1897
|
+
logFatal("WebSocket requests cannot be handled with this method.");
|
|
1584
1898
|
}
|
|
1585
|
-
return
|
|
1899
|
+
return handled;
|
|
1586
1900
|
}
|
|
1587
|
-
async
|
|
1901
|
+
async handleRequest(req, onUpgrade) {
|
|
1902
|
+
let res;
|
|
1588
1903
|
try {
|
|
1589
1904
|
if (req.isPreflight) {
|
|
1590
|
-
|
|
1591
|
-
}
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
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);
|
|
1601
1919
|
}
|
|
1602
1920
|
}
|
|
1603
|
-
|
|
1921
|
+
} catch (err) {
|
|
1922
|
+
res = await this.handleError(err);
|
|
1923
|
+
}
|
|
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);
|
|
1604
1930
|
}
|
|
1931
|
+
return res.response;
|
|
1605
1932
|
}
|
|
1606
1933
|
handleBeforeListen;
|
|
1607
1934
|
setOnBeforeListen(handler) {
|
|
@@ -1623,13 +1950,10 @@ class ServerAbstract {
|
|
|
1623
1950
|
this.handleError = handler;
|
|
1624
1951
|
}
|
|
1625
1952
|
defaultErrorHandler = (err) => {
|
|
1626
|
-
if (!(err instanceof Error)) {
|
|
1627
|
-
return new CResponse({ error: err, message: "Unknown" }, { status: Status.INTERNAL_SERVER_ERROR });
|
|
1628
|
-
}
|
|
1629
1953
|
if (err instanceof CError) {
|
|
1630
1954
|
return err.toResponse();
|
|
1631
1955
|
}
|
|
1632
|
-
return new CResponse({ error: err, message: err.message }, { status: Status.INTERNAL_SERVER_ERROR });
|
|
1956
|
+
return new CResponse({ error: err, message: "message" in err ? err.message : "Unknown" }, { status: Status.INTERNAL_SERVER_ERROR });
|
|
1633
1957
|
};
|
|
1634
1958
|
handleNotFound = (req) => this.defaultNotFoundHandler(req);
|
|
1635
1959
|
setOnNotFound(handler) {
|
|
@@ -1638,49 +1962,388 @@ class ServerAbstract {
|
|
|
1638
1962
|
defaultNotFoundHandler = (req) => {
|
|
1639
1963
|
return new CResponse({ error: true, message: `${req.method} on ${req.url} does not exist.` }, { status: Status.NOT_FOUND });
|
|
1640
1964
|
};
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1965
|
+
handlePreflight = (req) => this.defaultPreflightHandler(req);
|
|
1966
|
+
setOnPreflight(handler) {
|
|
1967
|
+
this.handlePreflight = handler;
|
|
1968
|
+
}
|
|
1969
|
+
defaultPreflightHandler = () => {
|
|
1970
|
+
return new CResponse("Departed");
|
|
1644
1971
|
};
|
|
1645
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
|
+
});
|
|
1646
1984
|
|
|
1647
|
-
// src/
|
|
1648
|
-
class
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
this.
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
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);
|
|
1669
2020
|
}
|
|
1670
2021
|
}
|
|
1671
2022
|
|
|
1672
|
-
// src/Server/Server.ts
|
|
1673
|
-
|
|
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);
|
|
2047
|
+
}
|
|
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);
|
|
2065
|
+
}
|
|
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);
|
|
2078
|
+
}
|
|
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
|
+
}
|
|
1674
2145
|
}
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
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;
|
|
2181
|
+
}
|
|
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;
|
|
2198
|
+
}
|
|
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);
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
return headers;
|
|
2281
|
+
}
|
|
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
|
|
1683
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
|
+
|
|
1684
2347
|
// src/utils/boolToString.ts
|
|
1685
2348
|
function boolToString(arg) {
|
|
1686
2349
|
return arg ? "true" : "false";
|
|
@@ -1691,24 +2354,41 @@ function isSomeArray(arg) {
|
|
|
1691
2354
|
return arg !== undefined && Array.isArray(arg) && arg.length > 0 && arg.every((a) => a !== null && a !== undefined);
|
|
1692
2355
|
}
|
|
1693
2356
|
|
|
1694
|
-
// src/
|
|
1695
|
-
|
|
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 {
|
|
1696
2369
|
opts;
|
|
1697
2370
|
constructor(opts) {
|
|
1698
2371
|
this.opts = opts;
|
|
1699
2372
|
if (opts === undefined) {
|
|
1700
|
-
|
|
2373
|
+
$corsStore.set(null);
|
|
1701
2374
|
} else {
|
|
1702
|
-
|
|
2375
|
+
$corsStore.set(this);
|
|
1703
2376
|
}
|
|
1704
2377
|
}
|
|
1705
2378
|
originKey = "Access-Control-Allow-Origin";
|
|
1706
2379
|
methodsKey = "Access-Control-Allow-Methods";
|
|
1707
2380
|
headersKey = "Access-Control-Allow-Headers";
|
|
1708
2381
|
credentialsKey = "Access-Control-Allow-Credentials";
|
|
2382
|
+
exposedHeadersKey = "Access-Control-Expose-Headers";
|
|
1709
2383
|
getCorsHeaders(req, res) {
|
|
1710
2384
|
const reqOrigin = req.headers.get("origin") ?? "";
|
|
1711
|
-
const {
|
|
2385
|
+
const {
|
|
2386
|
+
allowedOrigins,
|
|
2387
|
+
allowedMethods,
|
|
2388
|
+
allowedHeaders,
|
|
2389
|
+
exposedHeaders,
|
|
2390
|
+
credentials
|
|
2391
|
+
} = this.opts ?? {};
|
|
1712
2392
|
if (isSomeArray(allowedOrigins) && allowedOrigins.includes(reqOrigin)) {
|
|
1713
2393
|
res.headers.set(this.originKey, reqOrigin);
|
|
1714
2394
|
}
|
|
@@ -1718,6 +2398,9 @@ class Cors {
|
|
|
1718
2398
|
if (isSomeArray(allowedHeaders)) {
|
|
1719
2399
|
res.headers.set(this.headersKey, allowedHeaders.join(", "));
|
|
1720
2400
|
}
|
|
2401
|
+
if (isSomeArray(exposedHeaders)) {
|
|
2402
|
+
res.headers.set(this.exposedHeadersKey, exposedHeaders.join(", "));
|
|
2403
|
+
}
|
|
1721
2404
|
res.headers.set(this.credentialsKey, boolToString(credentials));
|
|
1722
2405
|
return res.headers;
|
|
1723
2406
|
}
|
|
@@ -1725,14 +2408,30 @@ class Cors {
|
|
|
1725
2408
|
const headers = this.getCorsHeaders(req, res);
|
|
1726
2409
|
res.headers.innerCombine(headers);
|
|
1727
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);
|
|
2421
|
+
}
|
|
1728
2422
|
}
|
|
1729
|
-
|
|
1730
|
-
|
|
2423
|
+
var init_XCors = __esm(() => {
|
|
2424
|
+
init_src();
|
|
2425
|
+
});
|
|
2426
|
+
|
|
2427
|
+
// src/XRepository/XRepository.ts
|
|
2428
|
+
class XRepository {
|
|
1731
2429
|
db;
|
|
1732
2430
|
constructor(db) {
|
|
1733
2431
|
this.db = db;
|
|
1734
2432
|
}
|
|
1735
2433
|
}
|
|
2434
|
+
|
|
1736
2435
|
// node_modules/memoirist/dist/bun/index.js
|
|
1737
2436
|
var Y = (v, b) => {
|
|
1738
2437
|
let A = b?.length ? {} : null;
|
|
@@ -1740,152 +2439,7 @@ var Y = (v, b) => {
|
|
|
1740
2439
|
for (let Q of b)
|
|
1741
2440
|
A[Q.part.charCodeAt(0)] = Q;
|
|
1742
2441
|
return { part: v, store: null, inert: A, params: null, wildcardStore: null };
|
|
1743
|
-
}
|
|
1744
|
-
var k = (v, b) => ({ ...v, part: b });
|
|
1745
|
-
var T = (v) => ({ name: v, store: null, inert: null });
|
|
1746
|
-
|
|
1747
|
-
class _ {
|
|
1748
|
-
config;
|
|
1749
|
-
root = {};
|
|
1750
|
-
history = [];
|
|
1751
|
-
deferred = [];
|
|
1752
|
-
constructor(v = {}) {
|
|
1753
|
-
this.config = v;
|
|
1754
|
-
if (v.lazy)
|
|
1755
|
-
this.find = this.lazyFind;
|
|
1756
|
-
if (v.onParam && !Array.isArray(v.onParam))
|
|
1757
|
-
this.config.onParam = [this.config.onParam];
|
|
1758
|
-
}
|
|
1759
|
-
static regex = { static: /:.+?(?=\/|$)/, params: /:.+?(?=\/|$)/g, optionalParams: /(\/:\w+\?)/g };
|
|
1760
|
-
lazyFind = (v, b) => {
|
|
1761
|
-
if (!this.config.lazy)
|
|
1762
|
-
return this.find;
|
|
1763
|
-
return this.build(), this.find(v, b);
|
|
1764
|
-
};
|
|
1765
|
-
build() {
|
|
1766
|
-
if (!this.config.lazy)
|
|
1767
|
-
return;
|
|
1768
|
-
for (let [v, b, A] of this.deferred)
|
|
1769
|
-
this.add(v, b, A, { lazy: false, ignoreHistory: true });
|
|
1770
|
-
this.deferred = [], this.find = (v, b) => {
|
|
1771
|
-
let A = this.root[v];
|
|
1772
|
-
if (!A)
|
|
1773
|
-
return null;
|
|
1774
|
-
return $(b, b.length, A, 0, this.config.onParam);
|
|
1775
|
-
};
|
|
1776
|
-
}
|
|
1777
|
-
add(v, b, A, { ignoreError: Q = false, ignoreHistory: O = false, lazy: V = this.config.lazy } = {}) {
|
|
1778
|
-
if (V)
|
|
1779
|
-
return this.find = this.lazyFind, this.deferred.push([v, b, A]), A;
|
|
1780
|
-
if (typeof b !== "string")
|
|
1781
|
-
throw new TypeError("Route path must be a string");
|
|
1782
|
-
if (b === "")
|
|
1783
|
-
b = "/";
|
|
1784
|
-
else if (b[0] !== "/")
|
|
1785
|
-
b = `/${b}`;
|
|
1786
|
-
let X = b[b.length - 1] === "*", J = b.match(_.regex.optionalParams);
|
|
1787
|
-
if (J) {
|
|
1788
|
-
let F = b.replaceAll("?", "");
|
|
1789
|
-
this.add(v, F, A, { ignoreError: Q, ignoreHistory: O, lazy: V });
|
|
1790
|
-
for (let B = 0;B < J.length; B++) {
|
|
1791
|
-
let D = b.replace(J[B], "");
|
|
1792
|
-
this.add(v, D, A, { ignoreError: true, ignoreHistory: O, lazy: V });
|
|
1793
|
-
}
|
|
1794
|
-
return A;
|
|
1795
|
-
}
|
|
1796
|
-
if (J)
|
|
1797
|
-
b = b.replaceAll("?", "");
|
|
1798
|
-
if (this.history.find(([F, B, D]) => F === v && B === b))
|
|
1799
|
-
return A;
|
|
1800
|
-
if (X || J && b.charCodeAt(b.length - 1) === 63)
|
|
1801
|
-
b = b.slice(0, -1);
|
|
1802
|
-
if (!O)
|
|
1803
|
-
this.history.push([v, b, A]);
|
|
1804
|
-
let K = b.split(_.regex.static), G = b.match(_.regex.params) || [];
|
|
1805
|
-
if (K[K.length - 1] === "")
|
|
1806
|
-
K.pop();
|
|
1807
|
-
let q;
|
|
1808
|
-
if (!this.root[v])
|
|
1809
|
-
q = this.root[v] = Y("/");
|
|
1810
|
-
else
|
|
1811
|
-
q = this.root[v];
|
|
1812
|
-
let U = 0;
|
|
1813
|
-
for (let F = 0;F < K.length; ++F) {
|
|
1814
|
-
let B = K[F];
|
|
1815
|
-
if (F > 0) {
|
|
1816
|
-
let D = G[U++].slice(1);
|
|
1817
|
-
if (q.params === null)
|
|
1818
|
-
q.params = T(D);
|
|
1819
|
-
else if (q.params.name !== D)
|
|
1820
|
-
if (Q)
|
|
1821
|
-
return A;
|
|
1822
|
-
else
|
|
1823
|
-
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`);
|
|
1824
|
-
let S = q.params;
|
|
1825
|
-
if (S.inert === null) {
|
|
1826
|
-
q = S.inert = Y(B);
|
|
1827
|
-
continue;
|
|
1828
|
-
}
|
|
1829
|
-
q = S.inert;
|
|
1830
|
-
}
|
|
1831
|
-
for (let D = 0;; ) {
|
|
1832
|
-
if (D === B.length) {
|
|
1833
|
-
if (D < q.part.length) {
|
|
1834
|
-
let S = k(q, q.part.slice(D));
|
|
1835
|
-
Object.assign(q, Y(B, [S]));
|
|
1836
|
-
}
|
|
1837
|
-
break;
|
|
1838
|
-
}
|
|
1839
|
-
if (D === q.part.length) {
|
|
1840
|
-
if (q.inert === null)
|
|
1841
|
-
q.inert = {};
|
|
1842
|
-
let S = q.inert[B.charCodeAt(D)];
|
|
1843
|
-
if (S) {
|
|
1844
|
-
q = S, B = B.slice(D), D = 0;
|
|
1845
|
-
continue;
|
|
1846
|
-
}
|
|
1847
|
-
let Z = Y(B.slice(D));
|
|
1848
|
-
q.inert[B.charCodeAt(D)] = Z, q = Z;
|
|
1849
|
-
break;
|
|
1850
|
-
}
|
|
1851
|
-
if (B[D] !== q.part[D]) {
|
|
1852
|
-
let S = k(q, q.part.slice(D)), Z = Y(B.slice(D));
|
|
1853
|
-
Object.assign(q, Y(q.part.slice(0, D), [S, Z])), q = Z;
|
|
1854
|
-
break;
|
|
1855
|
-
}
|
|
1856
|
-
++D;
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
if (U < G.length) {
|
|
1860
|
-
let B = G[U].slice(1);
|
|
1861
|
-
if (q.params === null)
|
|
1862
|
-
q.params = T(B);
|
|
1863
|
-
else if (q.params.name !== B)
|
|
1864
|
-
if (Q)
|
|
1865
|
-
return A;
|
|
1866
|
-
else
|
|
1867
|
-
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`);
|
|
1868
|
-
if (q.params.store === null)
|
|
1869
|
-
q.params.store = A;
|
|
1870
|
-
return q.params.store;
|
|
1871
|
-
}
|
|
1872
|
-
if (X) {
|
|
1873
|
-
if (q.wildcardStore === null)
|
|
1874
|
-
q.wildcardStore = A;
|
|
1875
|
-
return q.wildcardStore;
|
|
1876
|
-
}
|
|
1877
|
-
if (q.store === null)
|
|
1878
|
-
q.store = A;
|
|
1879
|
-
return q.store;
|
|
1880
|
-
}
|
|
1881
|
-
find(v, b) {
|
|
1882
|
-
let A = this.root[v];
|
|
1883
|
-
if (!A)
|
|
1884
|
-
return null;
|
|
1885
|
-
return $(b, b.length, A, 0, this.config.onParam);
|
|
1886
|
-
}
|
|
1887
|
-
}
|
|
1888
|
-
var $ = (v, b, A, Q, O) => {
|
|
2442
|
+
}, k = (v, b) => ({ ...v, part: b }), T = (v) => ({ name: v, store: null, inert: null }), _, $ = (v, b, A, Q, O) => {
|
|
1889
2443
|
let V = A.part, X = V.length, J = Q + X;
|
|
1890
2444
|
if (X > 1) {
|
|
1891
2445
|
if (J > b)
|
|
@@ -1943,13 +2497,155 @@ var $ = (v, b, A, Q, O) => {
|
|
|
1943
2497
|
if (A.wildcardStore !== null)
|
|
1944
2498
|
return { store: A.wildcardStore, params: { "*": v.substring(J, b) } };
|
|
1945
2499
|
return null;
|
|
1946
|
-
};
|
|
1947
|
-
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
|
+
});
|
|
1948
2645
|
|
|
1949
2646
|
// src/Router/adapters/MemoiristAdapter.ts
|
|
1950
2647
|
class MemoiristAdapter {
|
|
1951
2648
|
router = new w;
|
|
1952
|
-
pendingMiddlewares = new Map;
|
|
1953
2649
|
find(req) {
|
|
1954
2650
|
const method = req.method;
|
|
1955
2651
|
const pathname = req.urlObject.pathname;
|
|
@@ -1958,57 +2654,433 @@ class MemoiristAdapter {
|
|
|
1958
2654
|
if (!result)
|
|
1959
2655
|
return null;
|
|
1960
2656
|
return {
|
|
1961
|
-
route: result.store
|
|
1962
|
-
model: result.store.model,
|
|
2657
|
+
route: result.store,
|
|
1963
2658
|
params: result.params,
|
|
1964
|
-
search: Object.fromEntries(searchParams)
|
|
1965
|
-
middleware: compile(result.store.middlewares ?? [])
|
|
2659
|
+
search: Object.fromEntries(searchParams)
|
|
1966
2660
|
};
|
|
1967
2661
|
}
|
|
1968
2662
|
list() {
|
|
1969
|
-
return this.router.history.map((v) => v[2]
|
|
2663
|
+
return this.router.history.map((v) => v[2]);
|
|
1970
2664
|
}
|
|
1971
|
-
|
|
1972
|
-
this.router.add(data.method, data.endpoint,
|
|
1973
|
-
const pending = this.pendingMiddlewares.get(data.id);
|
|
1974
|
-
if (pending) {
|
|
1975
|
-
const store = this.router.find(data.method, data.endpoint)?.store;
|
|
1976
|
-
if (store)
|
|
1977
|
-
store.middlewares = pending;
|
|
1978
|
-
this.pendingMiddlewares.delete(data.id);
|
|
1979
|
-
}
|
|
2665
|
+
add(data) {
|
|
2666
|
+
this.router.add(data.method, data.endpoint, data);
|
|
1980
2667
|
}
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
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 {
|
|
1984
2695
|
return;
|
|
1985
|
-
|
|
2696
|
+
}
|
|
1986
2697
|
}
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
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));
|
|
1992
2737
|
}
|
|
1993
|
-
return;
|
|
1994
2738
|
}
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
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);
|
|
2006
2814
|
}
|
|
2007
2815
|
}
|
|
2008
2816
|
}
|
|
2817
|
+
async clear() {
|
|
2818
|
+
this.store.clear();
|
|
2819
|
+
}
|
|
2820
|
+
async size() {
|
|
2821
|
+
return this.store.size;
|
|
2822
|
+
}
|
|
2009
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
|
+
});
|
|
3031
|
+
|
|
2010
3032
|
// src/index.ts
|
|
2011
|
-
var
|
|
2012
|
-
|
|
2013
|
-
|
|
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();
|
|
2014
3086
|
})
|