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