1 |
|
2 | import { trace } from "@opentelemetry/api";
|
3 | import { SeverityNumber, logs } from "@opentelemetry/api-logs";
|
4 |
|
5 |
|
6 | var name = "@neoaren/comet";
|
7 | var version = "3.4.1";
|
8 |
|
9 |
|
10 | var otelLogger = logs.getLogger(name, version);
|
11 | function convert(...data) {
|
12 | return data.map((entry) => {
|
13 | if (typeof entry === "string") return entry;
|
14 | if (entry === void 0) return "undefined";
|
15 | return JSON.stringify(entry, null, 2);
|
16 | }).join(", ");
|
17 | }
|
18 | var logger = {
|
19 | trace: (...body) => otelLogger.emit({ severityNumber: SeverityNumber.TRACE, body: convert(body) }),
|
20 | debug: (...body) => otelLogger.emit({ severityNumber: SeverityNumber.DEBUG, body: convert(body) }),
|
21 | info: (...body) => otelLogger.emit({ severityNumber: SeverityNumber.INFO, body: convert(body) }),
|
22 | log: (...body) => otelLogger.emit({ severityNumber: SeverityNumber.INFO, body: convert(body) }),
|
23 | warn: (...body) => otelLogger.emit({ severityNumber: SeverityNumber.WARN, body: convert(body) }),
|
24 | error: (...body) => otelLogger.emit({ severityNumber: SeverityNumber.ERROR, body: convert(body) })
|
25 | };
|
26 | function recordException(exception) {
|
27 | if (exception instanceof Error || typeof exception === "string") {
|
28 | trace.getActiveSpan()?.recordException(exception);
|
29 | } else if (typeof exception === "object" && exception !== null && "toString" in exception) {
|
30 | trace.getActiveSpan()?.recordException(exception.toString());
|
31 | }
|
32 | }
|
33 |
|
34 |
|
35 | var defaultCookiesOptions = {
|
36 | decode: decodeURIComponent,
|
37 | encode: encodeURIComponent,
|
38 | limit: 64
|
39 | };
|
40 | var SameSite = ((SameSite2) => {
|
41 | SameSite2["Strict"] = "Strict";
|
42 | SameSite2["Lax"] = "Lax";
|
43 | SameSite2["None"] = "None";
|
44 | return SameSite2;
|
45 | })(SameSite || {});
|
46 | var Cookies = class _Cookies {
|
47 | data = new Map();
|
48 | get [Symbol.toStringTag]() {
|
49 | return `Cookies(${this.data.size})`;
|
50 | }
|
51 |
|
52 | get(name2) {
|
53 | return this.data.get(name2)?.value;
|
54 | }
|
55 |
|
56 | has(name2) {
|
57 | return this.data.has(name2);
|
58 | }
|
59 |
|
60 | set(name2, value, meta) {
|
61 | this.data.set(name2, { name: name2, value, ...meta ? { meta } : {} });
|
62 | }
|
63 |
|
64 | delete(name2) {
|
65 | this.data.delete(name2);
|
66 | }
|
67 |
|
68 | entries() {
|
69 | return [...this.data.entries()].map(([name2, cookie]) => [name2, cookie.value]);
|
70 | }
|
71 |
|
72 | keys() {
|
73 | return [...this.data.keys()];
|
74 | }
|
75 |
|
76 | values() {
|
77 | return [...this.data.values()].map((cookie) => cookie.value);
|
78 | }
|
79 |
|
80 | static async parse(headers, options) {
|
81 | const allOptions = this.getAllOptions(options);
|
82 | const cookies = new _Cookies();
|
83 | const pairs = headers.get("Cookie")?.split(";", allOptions.limit) ?? [];
|
84 | for (const pair of pairs) {
|
85 | let [name2, value] = pair.split("=", 2).map((component) => component.trim());
|
86 | if (!name2 || !value) {
|
87 | recordException(`[Comet] Failed to parse malformatted cookie "${pair}".`);
|
88 | continue;
|
89 | }
|
90 | if (value.startsWith('"') && value.endsWith('"')) value = value.slice(1, -1);
|
91 | try {
|
92 | if (allOptions.decode !== null) name2 = await allOptions.decode(name2);
|
93 | if (allOptions.decode !== null) value = await allOptions.decode(value);
|
94 | cookies.set(name2, value);
|
95 | } catch (error) {
|
96 | recordException(`[Comet] Failed to decode cookie "${pair}".`);
|
97 | recordException(error);
|
98 | }
|
99 | }
|
100 | return cookies;
|
101 | }
|
102 |
|
103 | static async serialize(cookies, headers, options) {
|
104 | const allOptions = this.getAllOptions(options);
|
105 | for (const cookie of cookies.data.values()) {
|
106 | const serialized = [];
|
107 | try {
|
108 | const name2 = allOptions.encode === null ? cookie.name : await allOptions.encode(cookie.name);
|
109 | const value = allOptions.encode === null ? cookie.value : await allOptions.encode(cookie.value);
|
110 | serialized.push(`${name2}=${value}`);
|
111 | } catch (error) {
|
112 | recordException(`[Comet] Failed to encode cookie "${cookie.name}".`);
|
113 | recordException(error);
|
114 | continue;
|
115 | }
|
116 | if (cookie.meta?.domain) serialized.push(`Domain=${cookie.meta.domain}`);
|
117 | if (cookie.meta?.expires) serialized.push(`Expires=${new Date(cookie.meta.expires).toUTCString()}`);
|
118 | if (cookie.meta?.httpOnly) serialized.push("HttpOnly");
|
119 | if (cookie.meta?.maxAge) serialized.push(`Max-Age=${cookie.meta.maxAge}`);
|
120 | if (cookie.meta?.path) serialized.push(`Path=${cookie.meta.path}`);
|
121 | if (cookie.meta?.sameSite) serialized.push(`SameSite=${cookie.meta.sameSite}`);
|
122 | if (cookie.meta?.secure) serialized.push("Secure");
|
123 | headers.append("Set-Cookie", serialized.join("; "));
|
124 | }
|
125 | }
|
126 |
|
127 | static getAllOptions(options) {
|
128 | return { ...defaultCookiesOptions, ...options };
|
129 | }
|
130 | };
|
131 |
|
132 |
|
133 | var NextData = class {
|
134 |
|
135 | constructor(data = {}) {
|
136 | this.data = data;
|
137 | }
|
138 | };
|
139 | var next = (extension) => new NextData(extension);
|
140 | function middleware(options, handler) {
|
141 | const _options = typeof options === "object" ? options : {};
|
142 | const _handler = typeof options === "function" ? options : handler;
|
143 | if (!_handler) throw new Error("[Comet] A middleware received no handler argument.");
|
144 | return {
|
145 | ..._options,
|
146 | handler: async (input) => {
|
147 | const nextData = await _handler(input);
|
148 | if (nextData instanceof NextData) Object.assign(input.event, nextData.data);
|
149 | }
|
150 | };
|
151 | }
|
152 |
|
153 |
|
154 | var Method = ((Method2) => {
|
155 | Method2["ALL"] = "ALL";
|
156 | Method2["GET"] = "GET";
|
157 | Method2["HEAD"] = "HEAD";
|
158 | Method2["POST"] = "POST";
|
159 | Method2["PUT"] = "PUT";
|
160 | Method2["DELETE"] = "DELETE";
|
161 | Method2["CONNECT"] = "CONNECT";
|
162 | Method2["OPTIONS"] = "OPTIONS";
|
163 | Method2["TRACE"] = "TRACE";
|
164 | Method2["PATCH"] = "PATCH";
|
165 | return Method2;
|
166 | })(Method || {});
|
167 | var ALL = "ALL" ;
|
168 | var GET = "GET" ;
|
169 | var HEAD = "HEAD" ;
|
170 | var POST = "POST" ;
|
171 | var PUT = "PUT" ;
|
172 | var DELETE = "DELETE" ;
|
173 | var CONNECT = "CONNECT" ;
|
174 | var OPTIONS = "OPTIONS" ;
|
175 | var TRACE = "TRACE" ;
|
176 | var PATCH = "PATCH" ;
|
177 |
|
178 |
|
179 | var defaultCorsOptions = {
|
180 | credentials: false,
|
181 | exposedHeaders: [],
|
182 | headers: [],
|
183 | maxAge: 86400,
|
184 | methods: [],
|
185 | origins: []
|
186 | };
|
187 | function getAllOptions(options) {
|
188 | const allOptions = { ...defaultCorsOptions, ...options };
|
189 | const allowedOrigins = parseListValue(allOptions.origins);
|
190 | const allowedHeaders = parseListValue(allOptions.headers);
|
191 | const allowedMethods = parseListValue(allOptions.methods);
|
192 | const exposedHeaders = parseListValue(allOptions.exposedHeaders);
|
193 | const { credentials: allowCredentials, maxAge } = allOptions;
|
194 | return { allowedOrigins, allowedHeaders, allowedMethods, exposedHeaders, allowCredentials, maxAge };
|
195 | }
|
196 | function parseListValue(value) {
|
197 | return Array.isArray(value) ? value : value.split(",").map((s) => s.trim());
|
198 | }
|
199 | var cors = (options) => middleware({
|
200 | name: "CORS"
|
201 | }, ({ event }) => {
|
202 | const { allowedOrigins, exposedHeaders, allowCredentials } = getAllOptions(options);
|
203 | const origin = event.headers.get("origin");
|
204 | if (allowedOrigins.includes("*")) {
|
205 | event.reply.headers.set("access-control-allow-origin", "*");
|
206 | } else if (origin && (allowedOrigins.includes(origin) || allowedOrigins.some((allowed) => allowed.startsWith("https://*.") && origin.endsWith(allowed.slice(9))))) {
|
207 | event.reply.headers.set("access-control-allow-origin", origin);
|
208 | event.reply.headers.append("vary", "origin");
|
209 | }
|
210 | if (allowCredentials) event.reply.headers.set("access-control-allow-credentials", "true");
|
211 | if (exposedHeaders.length > 0) event.reply.headers.set("access-control-expose-headers", exposedHeaders.join(","));
|
212 | return event.next();
|
213 | });
|
214 | var preflightHandler = (router, options) => middleware({
|
215 | name: "Preflight handler"
|
216 | }, ({ event }) => {
|
217 | if (event.method !== "OPTIONS" ) return event.next();
|
218 | const { allowedHeaders, allowedMethods, maxAge } = getAllOptions(options);
|
219 | const requestMethod = event.headers.get("access-control-request-method") ?? void 0;
|
220 | const route = router.find(event.pathname, requestMethod, void 0, true);
|
221 | if (!route) return event.reply.notFound();
|
222 | if (allowedHeaders.length > 0) event.reply.headers.set("access-control-allow-headers", allowedHeaders.join(","));
|
223 | if (allowedMethods.length > 0) event.reply.headers.set("access-control-allow-methods", allowedMethods.join(","));
|
224 | event.reply.headers.set("access-control-max-age", maxAge.toString());
|
225 | event.reply.headers.set("content-length", "0");
|
226 | return event.reply.noContent();
|
227 | });
|
228 |
|
229 |
|
230 | import { trace as trace2 } from "@opentelemetry/api";
|
231 | var Data = class _Data {
|
232 | constructor(request, method, pathname, hostname, headers, cookies, query, params, body, _raw, server2) {
|
233 | this.request = request;
|
234 | this.method = method;
|
235 | this.pathname = pathname;
|
236 | this.hostname = hostname;
|
237 | this.headers = headers;
|
238 | this.cookies = cookies;
|
239 | this.query = query;
|
240 | this.params = params;
|
241 | this.body = body;
|
242 | this._raw = _raw;
|
243 | this.server = server2;
|
244 | }
|
245 | static async fromRequest(request, options, serverName) {
|
246 | const url = new URL(request.url);
|
247 | const { raw, body } = await this.parseRequestBody(request);
|
248 | trace2.getActiveSpan()?.addEvent("convert request to data", {
|
249 | method: request.method,
|
250 | pathname: url.pathname,
|
251 | hostname: url.hostname,
|
252 | protocol: url.protocol,
|
253 | params: url.search
|
254 | });
|
255 | return new _Data(
|
256 | request,
|
257 | request.method.toUpperCase(),
|
258 | url.pathname,
|
259 | url.hostname.toLowerCase(),
|
260 | request.headers,
|
261 | await Cookies.parse(request.headers, options.cookies),
|
262 | Object.fromEntries(url.searchParams.entries()),
|
263 | {},
|
264 | body,
|
265 | raw,
|
266 | { name: serverName }
|
267 | );
|
268 | }
|
269 | static async parseRequestBody(request) {
|
270 | const contentType = request.headers.get("content-type")?.split(";")[0];
|
271 | trace2.getActiveSpan()?.addEvent("parse request body", {
|
272 | contentType: request.headers.get("content-type") ?? void 0,
|
273 | parsedContentType: contentType
|
274 | });
|
275 | switch (contentType) {
|
276 | case "application/json": {
|
277 | const text = await request.text();
|
278 | return { raw: text, body: JSON.parse(text) };
|
279 | }
|
280 | case "multipart/form-data": {
|
281 | const formData = await request.formData();
|
282 | const body = {};
|
283 | for (const [key, value] of formData.entries()) body[key] = value;
|
284 | return { body };
|
285 | }
|
286 | case "application/x-www-form-urlencoded": {
|
287 | const text = await request.text();
|
288 | const entries = text.split("&").map((x) => x.split("=").map(decodeURIComponent));
|
289 | return { body: Object.fromEntries(entries) };
|
290 | }
|
291 | default:
|
292 | return { body: void 0 };
|
293 | }
|
294 | }
|
295 | };
|
296 |
|
297 |
|
298 | import { trace as trace3 } from "@opentelemetry/api";
|
299 | var Status = ((Status2) => {
|
300 | Status2["Continue"] = "continue";
|
301 | Status2["SwitchingProtocols"] = "switchingProtocols";
|
302 | Status2["Processing"] = "processing";
|
303 | Status2["Ok"] = "ok";
|
304 | Status2["Created"] = "created";
|
305 | Status2["Accepted"] = "accepted";
|
306 | Status2["NonAuthoritativeInformation"] = "nonAuthoritativeInformation";
|
307 | Status2["NoContent"] = "noContent";
|
308 | Status2["ResetContent"] = "resetContent";
|
309 | Status2["PartialContent"] = "partialContent";
|
310 | Status2["MultiStatus"] = "multiStatus";
|
311 | Status2["MultipleChoices"] = "multipleChoices";
|
312 | Status2["MovedPermanently"] = "movedPermanently";
|
313 | Status2["MovedTemporarily"] = "movedTemporarily";
|
314 | Status2["SeeOther"] = "seeOther";
|
315 | Status2["NotModified"] = "notModified";
|
316 | Status2["UseProxy"] = "useProxy";
|
317 | Status2["TemporaryRedirect"] = "temporaryRedirect";
|
318 | Status2["PermanentRedirect"] = "permanentRedirect";
|
319 | Status2["BadRequest"] = "badRequest";
|
320 | Status2["Unauthorized"] = "unauthorized";
|
321 | Status2["PaymentRequired"] = "paymentRequired";
|
322 | Status2["Forbidden"] = "forbidden";
|
323 | Status2["NotFound"] = "notFound";
|
324 | Status2["MethodNotAllowed"] = "methodNotAllowed";
|
325 | Status2["NotAcceptable"] = "notAcceptable";
|
326 | Status2["ProxyAuthenticationRequired"] = "proxyAuthenticationRequired";
|
327 | Status2["RequestTimeout"] = "requestTimeout";
|
328 | Status2["Conflict"] = "conflict";
|
329 | Status2["Gone"] = "gone";
|
330 | Status2["LengthRequired"] = "lengthRequired";
|
331 | Status2["PreconditionFailed"] = "preconditionFailed";
|
332 | Status2["RequestTooLong"] = "requestTooLong";
|
333 | Status2["RequestUriTooLong"] = "requestUriTooLong";
|
334 | Status2["UnsupportedMediaType"] = "unsupportedMediaType";
|
335 | Status2["RequestedRangeNotSatisfiable"] = "requestedRangeNotSatisfiable";
|
336 | Status2["ExpectationFailed"] = "expectationFailed";
|
337 | Status2["ImATeapot"] = "imATeapot";
|
338 | Status2["InsufficientSpaceOnResource"] = "insufficientSpaceOnResource";
|
339 | Status2["MethodFailure"] = "methodFailure";
|
340 | Status2["MisdirectedRequest"] = "misdirectedRequest";
|
341 | Status2["UnprocessableEntity"] = "unprocessableEntity";
|
342 | Status2["FailedDependency"] = "failedDependency";
|
343 | Status2["PreconditionRequired"] = "preconditionRequired";
|
344 | Status2["TooManyRequests"] = "tooManyRequests";
|
345 | Status2["RequestHeaderFieldsTooLarge"] = "requestHeaderFieldsTooLarge";
|
346 | Status2["UnavailableForLegalReasons"] = "unavailableForLegalReasons";
|
347 | Status2["InternalServerError"] = "internalServerError";
|
348 | Status2["NotImplemented"] = "notImplemented";
|
349 | Status2["BadGateway"] = "badGateway";
|
350 | Status2["ServiceUnavailable"] = "serviceUnavailable";
|
351 | Status2["GatewayTimeout"] = "gatewayTimeout";
|
352 | Status2["HttpVersionNotSupported"] = "httpVersionNotSupported";
|
353 | Status2["InsufficientStorage"] = "insufficientStorage";
|
354 | Status2["NetworkAuthenticationRequired"] = "networkAuthenticationRequired";
|
355 | return Status2;
|
356 | })(Status || {});
|
357 | var Reply = class {
|
358 |
|
359 | body;
|
360 | status = Number.NaN;
|
361 | headers = new Headers();
|
362 | cookies = new Cookies();
|
363 |
|
364 | _raw;
|
365 |
|
366 | sent;
|
367 |
|
368 | static async toResponse(reply, options) {
|
369 | if (!reply.sent) {
|
370 | recordException("[Comet] No reply was sent for this event.");
|
371 | return new Response(null, { status: 500 });
|
372 | }
|
373 | if (reply._raw !== void 0) {
|
374 | trace3.getActiveSpan()?.addEvent("return raw response");
|
375 | return reply._raw;
|
376 | }
|
377 | const status = reply.status;
|
378 | const headers = reply.headers;
|
379 | await Cookies.serialize(reply.cookies, reply.headers, options.cookies);
|
380 | if (reply.body instanceof WebSocket) {
|
381 | trace3.getActiveSpan()?.addEvent("return websocket response");
|
382 | return new Response(null, { status, headers, webSocket: reply.body });
|
383 | }
|
384 | if (reply.body instanceof ReadableStream) {
|
385 | trace3.getActiveSpan()?.addEvent("return streamed response");
|
386 | return new Response(reply.body, { status, headers });
|
387 | }
|
388 | let body = null;
|
389 | if (reply.body) {
|
390 | headers.set("content-type", "application/json");
|
391 | body = options.dev ? JSON.stringify(reply.body, null, 2) : JSON.stringify(reply.body);
|
392 | }
|
393 | trace3.getActiveSpan()?.addEvent("convert response");
|
394 | return new Response(body, { status, headers });
|
395 | }
|
396 |
|
397 | send(status, body) {
|
398 | if (this.sent) {
|
399 | recordException("[Comet] Cannot send a reply after one has already been sent.");
|
400 | return this;
|
401 | }
|
402 | this.status = status;
|
403 | this.body = body;
|
404 | this.sent = new Date();
|
405 | trace3.getActiveSpan()?.addEvent("send reply", {
|
406 | status,
|
407 | sent: +this.sent
|
408 | });
|
409 | return this;
|
410 | }
|
411 |
|
412 | raw(response) {
|
413 | if (this.sent) {
|
414 | recordException("[Comet] Cannot send a reply after one has already been sent.");
|
415 | return this;
|
416 | }
|
417 | this._raw = response;
|
418 | this.sent = new Date();
|
419 | trace3.getActiveSpan()?.addEvent("raw reply", {
|
420 | sent: +this.sent
|
421 | });
|
422 | return this;
|
423 | }
|
424 |
|
425 | custom(status, body) {
|
426 | return this.send(status, body);
|
427 | }
|
428 |
|
429 | continue(body) {
|
430 | return this.send(100, body);
|
431 | }
|
432 |
|
433 | switchingProtocols(body) {
|
434 | return this.send(101, body);
|
435 | }
|
436 |
|
437 | processing(body) {
|
438 | return this.send(102, body);
|
439 | }
|
440 |
|
441 | ok(body) {
|
442 | return this.send(200, body);
|
443 | }
|
444 |
|
445 | created(body) {
|
446 | return this.send(201, body);
|
447 | }
|
448 |
|
449 | accepted(body) {
|
450 | return this.send(202, body);
|
451 | }
|
452 |
|
453 | nonAuthoritativeInformation(body) {
|
454 | return this.send(203, body);
|
455 | }
|
456 |
|
457 | noContent(body) {
|
458 | return this.send(204, body);
|
459 | }
|
460 |
|
461 | resetContent(body) {
|
462 | return this.send(205, body);
|
463 | }
|
464 |
|
465 | partialContent(body) {
|
466 | return this.send(206, body);
|
467 | }
|
468 |
|
469 | multiStatus(body) {
|
470 | return this.send(207, body);
|
471 | }
|
472 |
|
473 | multipleChoices(body) {
|
474 | return this.send(300, body);
|
475 | }
|
476 |
|
477 | movedPermanently(body) {
|
478 | return this.send(301, body);
|
479 | }
|
480 |
|
481 | movedTemporarily(body) {
|
482 | return this.send(302, body);
|
483 | }
|
484 |
|
485 | seeOther(body) {
|
486 | return this.send(303, body);
|
487 | }
|
488 |
|
489 | notModified(body) {
|
490 | return this.send(304, body);
|
491 | }
|
492 |
|
493 | useProxy(body) {
|
494 | return this.send(305, body);
|
495 | }
|
496 |
|
497 | temporaryRedirect(body) {
|
498 | return this.send(307, body);
|
499 | }
|
500 |
|
501 | permanentRedirect(body) {
|
502 | return this.send(308, body);
|
503 | }
|
504 |
|
505 | badRequest(body) {
|
506 | return this.send(400, body);
|
507 | }
|
508 |
|
509 | unauthorized(body) {
|
510 | return this.send(401, body);
|
511 | }
|
512 |
|
513 | paymentRequired(body) {
|
514 | return this.send(402, body);
|
515 | }
|
516 |
|
517 | forbidden(body) {
|
518 | return this.send(403, body);
|
519 | }
|
520 |
|
521 | notFound(body) {
|
522 | return this.send(404, body);
|
523 | }
|
524 |
|
525 | methodNotAllowed(body) {
|
526 | return this.send(405, body);
|
527 | }
|
528 |
|
529 | notAcceptable(body) {
|
530 | return this.send(406, body);
|
531 | }
|
532 |
|
533 | proxyAuthenticationRequired(body) {
|
534 | return this.send(407, body);
|
535 | }
|
536 |
|
537 | requestTimeout(body) {
|
538 | return this.send(408, body);
|
539 | }
|
540 |
|
541 | conflict(body) {
|
542 | return this.send(409, body);
|
543 | }
|
544 |
|
545 | gone(body) {
|
546 | return this.send(410, body);
|
547 | }
|
548 |
|
549 | lengthRequired(body) {
|
550 | return this.send(411, body);
|
551 | }
|
552 |
|
553 | preconditionFailed(body) {
|
554 | return this.send(412, body);
|
555 | }
|
556 |
|
557 | requestTooLong(body) {
|
558 | return this.send(413, body);
|
559 | }
|
560 |
|
561 | requestUriTooLong(body) {
|
562 | return this.send(414, body);
|
563 | }
|
564 |
|
565 | unsupportedMediaType(body) {
|
566 | return this.send(415, body);
|
567 | }
|
568 |
|
569 | requestedRangeNotSatisfiable(body) {
|
570 | return this.send(416, body);
|
571 | }
|
572 |
|
573 | expectationFailed(body) {
|
574 | return this.send(417, body);
|
575 | }
|
576 |
|
577 | imATeapot(body) {
|
578 | return this.send(418, body);
|
579 | }
|
580 |
|
581 | insufficientSpaceOnResource(body) {
|
582 | return this.send(419, body);
|
583 | }
|
584 |
|
585 | methodFailure(body) {
|
586 | return this.send(420, body);
|
587 | }
|
588 |
|
589 | misdirectedRequest(body) {
|
590 | return this.send(421, body);
|
591 | }
|
592 |
|
593 | unprocessableEntity(body) {
|
594 | return this.send(422, body);
|
595 | }
|
596 |
|
597 | failedDependency(body) {
|
598 | return this.send(424, body);
|
599 | }
|
600 |
|
601 | preconditionRequired(body) {
|
602 | return this.send(428, body);
|
603 | }
|
604 |
|
605 | tooManyRequests(body) {
|
606 | return this.send(429, body);
|
607 | }
|
608 |
|
609 | requestHeaderFieldsTooLarge(body) {
|
610 | return this.send(431, body);
|
611 | }
|
612 |
|
613 | unavailableForLegalReasons(body) {
|
614 | return this.send(451, body);
|
615 | }
|
616 |
|
617 | internalServerError(body) {
|
618 | return this.send(500, body);
|
619 | }
|
620 |
|
621 | notImplemented(body) {
|
622 | return this.send(501, body);
|
623 | }
|
624 |
|
625 | badGateway(body) {
|
626 | return this.send(502, body);
|
627 | }
|
628 |
|
629 | serviceUnavailable(body) {
|
630 | return this.send(503, body);
|
631 | }
|
632 |
|
633 | gatewayTimeout(body) {
|
634 | return this.send(504, body);
|
635 | }
|
636 |
|
637 | httpVersionNotSupported(body) {
|
638 | return this.send(505, body);
|
639 | }
|
640 |
|
641 | insufficientStorage(body) {
|
642 | return this.send(507, body);
|
643 | }
|
644 |
|
645 | networkAuthenticationRequired(body) {
|
646 | return this.send(511, body);
|
647 | }
|
648 | };
|
649 |
|
650 |
|
651 | var BASE_URL = "https://comet";
|
652 | function isValidPathname(value) {
|
653 | if (typeof value !== "string") return false;
|
654 | try {
|
655 | new URLPattern(value, BASE_URL);
|
656 | return true;
|
657 | } catch {
|
658 | return false;
|
659 | }
|
660 | }
|
661 | function isValidCompatibilityDate(value) {
|
662 | return typeof value === "string" && !Number.isNaN(new Date(value).valueOf());
|
663 | }
|
664 | function comparePathnames(check, against) {
|
665 | if (!against || against === "*") return true;
|
666 | return new URLPattern(against, BASE_URL).test(check, BASE_URL);
|
667 | }
|
668 | function compareMethods(check, against) {
|
669 | if (!against || against === "ALL" ) return true;
|
670 | return check === against;
|
671 | }
|
672 | function compareCompatibilityDates(check, against) {
|
673 | if (!against) return true;
|
674 | if (!check) return false;
|
675 | return new Date(check) >= new Date(against);
|
676 | }
|
677 | function getPathnameParameters(pathname, template) {
|
678 | const result = new URLPattern(template, BASE_URL).exec(pathname, BASE_URL);
|
679 | return result?.pathname?.groups ?? {};
|
680 | }
|
681 |
|
682 |
|
683 | var Router = class {
|
684 |
|
685 | constructor(options) {
|
686 | this.options = options;
|
687 | }
|
688 |
|
689 | routes = [];
|
690 | ready = true;
|
691 |
|
692 | register = (options, handler) => {
|
693 | const _register = (inputMethod) => {
|
694 | const pathname = `${this.options.prefix ?? ""}${options.pathname ?? "*"}`;
|
695 | const method2 = inputMethod ?? "ALL" ;
|
696 | const compatibilityDate = options.compatibilityDate;
|
697 | const name2 = options.name ?? `${method2} ${pathname}${compatibilityDate ? ` (${compatibilityDate})` : ""}`;
|
698 | if (!isValidPathname(pathname)) {
|
699 | recordException(`[Comet] Failed to set up route '${name2}' due to an invalid pathname.`);
|
700 | return;
|
701 | }
|
702 | if (options.compatibilityDate !== void 0 && !isValidCompatibilityDate(options.compatibilityDate)) {
|
703 | recordException(`[Comet] Failed to set up route '${name2}' due to an invalid compatibility date.`);
|
704 | return;
|
705 | }
|
706 | const schemas = { body: options.body, params: options.params, query: options.query };
|
707 | this.routes.push({ ...options, pathname, method: method2, name: name2, handler, schemas });
|
708 | };
|
709 | const { method } = options;
|
710 | if (Array.isArray(method)) {
|
711 | for (const each of method) _register(each);
|
712 | } else {
|
713 | _register(method);
|
714 | }
|
715 | this.ready = false;
|
716 | };
|
717 |
|
718 | find = (pathname, method, compatibilityDate, ignoreCompatibilityDate) => {
|
719 | for (const route of this.routes) {
|
720 | const doPathnamesMatch = comparePathnames(pathname, route.pathname);
|
721 | if (!doPathnamesMatch) continue;
|
722 | const doMethodsMatch = compareMethods(method, route.method);
|
723 | if (!doMethodsMatch) continue;
|
724 | if (ignoreCompatibilityDate) return route;
|
725 | const doCompatibilityDatesMatch = compareCompatibilityDates(compatibilityDate, route.compatibilityDate);
|
726 | if (doCompatibilityDatesMatch) return route;
|
727 | }
|
728 | };
|
729 |
|
730 | init = () => {
|
731 | if (this.ready) return;
|
732 | this.routes.sort((a, b) => {
|
733 | if (a.pathname !== b.pathname || a.method !== b.method) return 0;
|
734 | return compareCompatibilityDates(a.compatibilityDate, b.compatibilityDate) ? -1 : 1;
|
735 | });
|
736 | this.ready = true;
|
737 | };
|
738 | getRoutes = () => this.routes;
|
739 | };
|
740 |
|
741 |
|
742 | import { trace as trace4 } from "@opentelemetry/api";
|
743 | var schemaValidation = (route) => middleware({
|
744 | name: "Schema validation"
|
745 | }, async ({ event }) => {
|
746 | const { body: bodySchema, params: paramsSchema, query: querySchema } = route.schemas;
|
747 | const paramsResult = paramsSchema?.safeParse(event.params);
|
748 | trace4.getActiveSpan()?.addEvent("params schema parse", {
|
749 | success: paramsResult?.success,
|
750 | errors: paramsResult?.success ? void 0 : paramsResult?.error.issues.map((issue) => issue.message)
|
751 | });
|
752 | const queryResult = querySchema?.safeParse(event.query);
|
753 | trace4.getActiveSpan()?.addEvent("query schema parse", {
|
754 | success: queryResult?.success,
|
755 | errors: paramsResult?.success ? void 0 : paramsResult?.error.issues.map((issue) => issue.message)
|
756 | });
|
757 | const bodyResult = bodySchema?.safeParse(event.body);
|
758 | trace4.getActiveSpan()?.addEvent("body schema parse", {
|
759 | success: bodyResult?.success,
|
760 | errors: paramsResult?.success ? void 0 : paramsResult?.error.issues.map((issue) => issue.message)
|
761 | });
|
762 | const errors = {};
|
763 | if (paramsResult?.success === false) errors.params = paramsResult.error.issues;
|
764 | if (queryResult?.success === false) errors.query = queryResult.error.issues;
|
765 | if (bodyResult?.success === false) errors.body = bodyResult.error.issues;
|
766 | if (errors.body || errors.params || errors.query) {
|
767 | return event.reply.badRequest({ success: false, errors });
|
768 | }
|
769 | if (paramsResult?.success) event.params = paramsResult.data;
|
770 | if (queryResult?.success) event.query = queryResult.data;
|
771 | if (bodyResult?.success) event.body = bodyResult.data;
|
772 | return event.next();
|
773 | });
|
774 |
|
775 |
|
776 | import { SpanKind, trace as trace5 } from "@opentelemetry/api";
|
777 | var Server = class {
|
778 | constructor(options = {}) {
|
779 | this.options = options;
|
780 | this.router = new Router(options);
|
781 | this.route = this.router.register;
|
782 | }
|
783 | router;
|
784 | route;
|
785 | handler = async (request, env, ctxOrState) => {
|
786 | return trace5.getTracer(name, version).startActiveSpan("Comet Handler", {
|
787 | kind: SpanKind.SERVER,
|
788 | attributes: {
|
789 | name: this.options.name
|
790 | }
|
791 | }, async (span) => {
|
792 | try {
|
793 | this.router.init();
|
794 | const data = await Data.fromRequest(request, this.options, this.options.name);
|
795 | const reply = new Reply();
|
796 | const isDurableObject = "id" in ctxOrState;
|
797 | const event = {
|
798 | ...data,
|
799 | reply,
|
800 | next,
|
801 | isDurableObject,
|
802 | ...isDurableObject ? { state: ctxOrState } : { ctx: ctxOrState }
|
803 | };
|
804 | const input = { event, env, logger };
|
805 | span.setAttribute("comet.server.durable_object", isDurableObject);
|
806 | if (this.options.before) {
|
807 | for (const mw of this.options.before) {
|
808 | await trace5.getTracer(name, version).startActiveSpan(
|
809 | `Comet Middleware${mw.name ? ` ${mw.name}` : ""}`,
|
810 | {
|
811 | attributes: {
|
812 | "comet.mw.name": mw.name,
|
813 | "comet.mw.type": "global-before"
|
814 | }
|
815 | },
|
816 | async (span2) => {
|
817 | await mw.handler(input);
|
818 | span2.end();
|
819 | }
|
820 | );
|
821 | if (event.reply.sent) break;
|
822 | }
|
823 | }
|
824 | if (!event.reply.sent) {
|
825 | await trace5.getTracer(name, version).startActiveSpan(
|
826 | "Comet CORS Middleware",
|
827 | {
|
828 | attributes: {
|
829 | "comet.mw.name": "CORS",
|
830 | "comet.mw.type": "global-before",
|
831 | "comet.mw.cors.origin": event.headers.get("origin") ?? void 0,
|
832 | "comet.mw.cors.method": event.method
|
833 | }
|
834 | },
|
835 | async (span2) => {
|
836 | await cors(this.options.cors).handler(input);
|
837 | span2.end();
|
838 | }
|
839 | );
|
840 | }
|
841 | if (!event.reply.sent) {
|
842 | await trace5.getTracer(name, version).startActiveSpan(
|
843 | "Comet Routing",
|
844 | {
|
845 | attributes: {
|
846 | "comet.routing.compatibility_date": event.headers.get("x-compatibility-date") ?? void 0,
|
847 | "comet.routing.pathname": event.pathname,
|
848 | "comet.routing.method": event.method
|
849 | }
|
850 | },
|
851 | async (span2) => {
|
852 | const compatibilityDate = event.headers.get("x-compatibility-date") ?? void 0;
|
853 | if (compatibilityDate && new Date(compatibilityDate) > new Date() && !this.options.dev) {
|
854 | event.reply.badRequest({ message: "Invalid compatibility date" });
|
855 | } else {
|
856 | const route = this.router.find(event.pathname, event.method, compatibilityDate);
|
857 | if (!route) {
|
858 | if (event.method === "OPTIONS" ) {
|
859 | await preflightHandler(this.router, this.options.cors).handler(input);
|
860 | } else {
|
861 | event.reply.notFound();
|
862 | }
|
863 | } else {
|
864 | event.params = getPathnameParameters(event.pathname, route.pathname);
|
865 | if (!event.reply.sent) schemaValidation(route).handler(input);
|
866 | if (route.before) {
|
867 | for (const mw of route.before) {
|
868 | await trace5.getTracer(name, version).startActiveSpan(
|
869 | `Comet Middleware${mw.name ? ` ${mw.name}` : ""}`,
|
870 | {
|
871 | attributes: {
|
872 | "comet.mw.name": mw.name,
|
873 | "comet.mw.type": "local-before"
|
874 | }
|
875 | },
|
876 | async (span3) => {
|
877 | await mw.handler(input);
|
878 | span3.end();
|
879 | }
|
880 | );
|
881 | if (event.reply.sent) break;
|
882 | }
|
883 | }
|
884 | if (!event.reply.sent) {
|
885 | await trace5.getTracer(name, version).startActiveSpan(
|
886 | "Comet Main Handler",
|
887 | {
|
888 | attributes: {
|
889 | "comet.route.name": route.name,
|
890 | "comet.route.pathname": route.pathname,
|
891 | "comet.route.compatibility_date": route.compatibilityDate,
|
892 | "comet.route.has_body_schema": !!route.schemas.body,
|
893 | "comet.route.has_query_schema": !!route.schemas.query,
|
894 | "comet.route.has_params_schema": !!route.schemas.params,
|
895 | "comet.route.method": route.method
|
896 | }
|
897 | },
|
898 | async (span3) => {
|
899 | await route.handler(input);
|
900 | span3.end();
|
901 | }
|
902 | );
|
903 | }
|
904 | if (route.after) {
|
905 | if (isDurableObject) {
|
906 | for (const mw of route.after) {
|
907 | await trace5.getTracer(name, version).startActiveSpan(
|
908 | `Comet Middleware${mw.name ? ` ${mw.name}` : ""}`,
|
909 | {
|
910 | attributes: {
|
911 | "comet.mw.name": mw.name,
|
912 | "comet.mw.type": "local-after"
|
913 | }
|
914 | },
|
915 | async (span3) => {
|
916 | await mw.handler(input);
|
917 | span3.end();
|
918 | }
|
919 | );
|
920 | }
|
921 | } else {
|
922 | ctxOrState.waitUntil(Promise.allSettled(route.after.map(async (mw) => {
|
923 | const span3 = trace5.getTracer(name, version).startSpan(`Comet Middleware${mw.name ? ` ${mw.name}` : ""}`, {
|
924 | attributes: {
|
925 | "comet.mw.name": mw.name,
|
926 | "comet.mw.type": "local-after"
|
927 | }
|
928 | });
|
929 | await mw.handler(input);
|
930 | span3.end();
|
931 | })));
|
932 | }
|
933 | }
|
934 | }
|
935 | }
|
936 | span2.end();
|
937 | }
|
938 | );
|
939 | }
|
940 | if (this.options.after) {
|
941 | if (isDurableObject) {
|
942 | for (const mw of this.options.after) {
|
943 | await trace5.getTracer(name, version).startActiveSpan(
|
944 | `Comet Middleware${mw.name ? ` ${mw.name}` : ""}`,
|
945 | {
|
946 | attributes: {
|
947 | "comet.mw.name": mw.name,
|
948 | "comet.mw.type": "global-after"
|
949 | }
|
950 | },
|
951 | async (span2) => {
|
952 | await mw.handler(input);
|
953 | span2.end();
|
954 | }
|
955 | );
|
956 | }
|
957 | } else {
|
958 | ctxOrState.waitUntil(Promise.allSettled(this.options.after.map(async (mw) => {
|
959 | const span2 = trace5.getTracer(name, version).startSpan(`Comet Middleware${mw.name ? ` ${mw.name}` : ""}`, {
|
960 | attributes: {
|
961 | "comet.mw.name": mw.name,
|
962 | "comet.mw.type": "global-after"
|
963 | }
|
964 | });
|
965 | await mw.handler(input);
|
966 | span2.end();
|
967 | })));
|
968 | }
|
969 | }
|
970 | span.end();
|
971 | return await Reply.toResponse(event.reply, this.options);
|
972 | } catch (error) {
|
973 | recordException("[Comet] Failed to handle request.");
|
974 | recordException(error);
|
975 | span.end();
|
976 | return new Response(null, { status: 500 });
|
977 | }
|
978 | });
|
979 | };
|
980 | static getRouter(server2) {
|
981 | return server2.router;
|
982 | }
|
983 | };
|
984 | function server(options) {
|
985 | return new Server(options);
|
986 | }
|
987 | export {
|
988 | ALL,
|
989 | BASE_URL,
|
990 | CONNECT,
|
991 | Cookies,
|
992 | DELETE,
|
993 | Data,
|
994 | GET,
|
995 | HEAD,
|
996 | Method,
|
997 | OPTIONS,
|
998 | PATCH,
|
999 | POST,
|
1000 | PUT,
|
1001 | Reply,
|
1002 | Router,
|
1003 | SameSite,
|
1004 | Server,
|
1005 | Status,
|
1006 | TRACE,
|
1007 | compareCompatibilityDates,
|
1008 | compareMethods,
|
1009 | comparePathnames,
|
1010 | cors,
|
1011 | defaultCookiesOptions,
|
1012 | getPathnameParameters,
|
1013 | isValidCompatibilityDate,
|
1014 | isValidPathname,
|
1015 | logger,
|
1016 | middleware,
|
1017 | next,
|
1018 | preflightHandler,
|
1019 | recordException,
|
1020 | schemaValidation,
|
1021 | server
|
1022 | };
|