@barqel/barq 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +8 -4
  2. package/dist/app.d.ts +0 -2
  3. package/dist/app.d.ts.map +1 -1
  4. package/dist/context.d.ts +0 -2
  5. package/dist/context.d.ts.map +1 -1
  6. package/dist/cookies.d.ts.map +1 -1
  7. package/dist/cors.d.ts.map +1 -1
  8. package/dist/errors.d.ts.map +1 -1
  9. package/dist/http.d.ts.map +1 -1
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +4870 -10
  13. package/dist/index.js.map +24 -1
  14. package/dist/internal/ip.d.ts.map +1 -1
  15. package/dist/internal/node-compat.d.ts +2 -0
  16. package/dist/internal/node-compat.d.ts.map +1 -0
  17. package/dist/internal/pathname.d.ts.map +1 -1
  18. package/dist/internal/query.d.ts.map +1 -1
  19. package/dist/internal/scan.d.ts.map +1 -1
  20. package/dist/internal/shutdown.d.ts.map +1 -1
  21. package/dist/internal/trie.d.ts.map +1 -1
  22. package/dist/middleware.d.ts.map +1 -1
  23. package/dist/node-patch.d.ts +3 -0
  24. package/dist/node-patch.d.ts.map +1 -0
  25. package/dist/node-patch.js +4870 -0
  26. package/dist/node-patch.js.map +24 -0
  27. package/dist/types.d.ts.map +1 -1
  28. package/dist/validation.d.ts.map +1 -1
  29. package/package.json +72 -58
  30. package/dist/app.js +0 -1370
  31. package/dist/app.js.map +0 -1
  32. package/dist/context.js +0 -261
  33. package/dist/context.js.map +0 -1
  34. package/dist/cookies.js +0 -234
  35. package/dist/cookies.js.map +0 -1
  36. package/dist/cors.js +0 -82
  37. package/dist/cors.js.map +0 -1
  38. package/dist/errors.js +0 -81
  39. package/dist/errors.js.map +0 -1
  40. package/dist/http.js +0 -127
  41. package/dist/http.js.map +0 -1
  42. package/dist/internal/ip.js +0 -151
  43. package/dist/internal/ip.js.map +0 -1
  44. package/dist/internal/pathname.js +0 -158
  45. package/dist/internal/pathname.js.map +0 -1
  46. package/dist/internal/query.js +0 -126
  47. package/dist/internal/query.js.map +0 -1
  48. package/dist/internal/scan.js +0 -1069
  49. package/dist/internal/scan.js.map +0 -1
  50. package/dist/internal/shutdown.js +0 -30
  51. package/dist/internal/shutdown.js.map +0 -1
  52. package/dist/internal/trie.js +0 -560
  53. package/dist/internal/trie.js.map +0 -1
  54. package/dist/middleware.js +0 -269
  55. package/dist/middleware.js.map +0 -1
  56. package/dist/types.js +0 -2
  57. package/dist/types.js.map +0 -1
  58. package/dist/validation.js +0 -32
  59. package/dist/validation.js.map +0 -1
@@ -0,0 +1,4870 @@
1
+ // src/internal/node-compat.ts
2
+ import cluster from "node:cluster";
3
+ import crypto from "node:crypto";
4
+ import fs from "node:fs";
5
+ import http from "node:http";
6
+ import https from "node:https";
7
+ import { cpus as cpus2 } from "node:os";
8
+ import { Readable } from "node:stream";
9
+
10
+ // src/app.ts
11
+ import { cpus } from "node:os";
12
+
13
+ // src/cookies.ts
14
+ import { timingSafeEqual } from "node:crypto";
15
+
16
+ class CookieJarImpl {
17
+ secret;
18
+ onMutation;
19
+ state;
20
+ constructor(secret, requestHeaders, onMutation) {
21
+ this.secret = secret;
22
+ this.onMutation = onMutation;
23
+ this.state = { cookies: null, requestHeaders, pending: null };
24
+ }
25
+ get(name) {
26
+ return getCookies(this.state).get(name);
27
+ }
28
+ getSigned(name, customSecret) {
29
+ const signed = getCookies(this.state).get(name);
30
+ if (!signed)
31
+ return null;
32
+ const signingSecret = customSecret ?? this.secret;
33
+ if (!signingSecret)
34
+ return null;
35
+ return unsign(signed, signingSecret);
36
+ }
37
+ set(name, value, options) {
38
+ const cookieOptions = snapshotOptions(options);
39
+ validateCookie(name, cookieOptions);
40
+ getCookies(this.state).set(name, value);
41
+ getPending(this.state).push({
42
+ name,
43
+ headerString: buildCookieString(name, value, cookieOptions)
44
+ });
45
+ this.onMutation?.();
46
+ }
47
+ setSigned(name, value, options, customSecret) {
48
+ const signingSecret = customSecret ?? this.secret;
49
+ if (!signingSecret) {
50
+ throw new Error("A non-empty secret is required to set a signed cookie");
51
+ }
52
+ const cookieOptions = snapshotOptions(options);
53
+ validateCookie(name, cookieOptions);
54
+ const signed = sign(value, signingSecret);
55
+ getCookies(this.state).set(name, signed);
56
+ getPending(this.state).push({
57
+ name,
58
+ headerString: buildCookieString(name, signed, cookieOptions)
59
+ });
60
+ this.onMutation?.();
61
+ }
62
+ delete(name, options) {
63
+ const cookieOptions = snapshotOptions(options);
64
+ validateCookie(name, cookieOptions);
65
+ getCookies(this.state).delete(name);
66
+ getPending(this.state).push({
67
+ name,
68
+ headerString: buildCookieString(name, "", {
69
+ ...cookieOptions,
70
+ maxAge: 0,
71
+ expires: new Date(0)
72
+ })
73
+ });
74
+ this.onMutation?.();
75
+ }
76
+ hasPending() {
77
+ return (this.state.pending?.length ?? 0) > 0;
78
+ }
79
+ apply(headers) {
80
+ const pending = this.state.pending;
81
+ if (pending === null)
82
+ return;
83
+ for (const cookie of pending) {
84
+ headers.append("set-cookie", cookie.headerString);
85
+ }
86
+ pending.length = 0;
87
+ }
88
+ }
89
+ function normalizeSameSite(value) {
90
+ if (!value)
91
+ return "Lax";
92
+ const lower = value.toLowerCase();
93
+ if (lower === "strict")
94
+ return "Strict";
95
+ if (lower === "lax")
96
+ return "Lax";
97
+ if (lower === "none")
98
+ return "None";
99
+ return value;
100
+ }
101
+ function buildCookieString(name, value, options) {
102
+ validateCookie(name, options);
103
+ let cookie = `${name}=${encodeURIComponent(value)}`;
104
+ if (options.path)
105
+ cookie += `; Path=${options.path}`;
106
+ if (options.domain)
107
+ cookie += `; Domain=${options.domain}`;
108
+ if (options.maxAge !== undefined)
109
+ cookie += `; Max-Age=${options.maxAge}`;
110
+ if (options.expires)
111
+ cookie += `; Expires=${options.expires.toUTCString()}`;
112
+ if (options.httpOnly !== false)
113
+ cookie += "; HttpOnly";
114
+ if (options.secure)
115
+ cookie += "; Secure";
116
+ const sameSite = normalizeSameSite(options.sameSite);
117
+ if (sameSite)
118
+ cookie += `; SameSite=${sameSite}`;
119
+ return cookie;
120
+ }
121
+ function sign(value, secret) {
122
+ const hasher = new Bun.CryptoHasher("sha256", secret);
123
+ hasher.update(value);
124
+ const sig = hasher.digest("base64url");
125
+ return `${value}.${sig}`;
126
+ }
127
+ function unsign(signedValue, secret) {
128
+ const lastDot = signedValue.lastIndexOf(".");
129
+ if (lastDot <= 0 || lastDot === signedValue.length - 1)
130
+ return null;
131
+ const value = signedValue.slice(0, lastDot);
132
+ const sig = signedValue.slice(lastDot + 1);
133
+ const hasher = new Bun.CryptoHasher("sha256", secret);
134
+ hasher.update(value);
135
+ const expected = hasher.digest("base64url");
136
+ const actualBytes = Buffer.from(sig);
137
+ const expectedBytes = Buffer.from(expected);
138
+ if (actualBytes.length !== expectedBytes.length)
139
+ return null;
140
+ if (!timingSafeEqual(actualBytes, expectedBytes))
141
+ return null;
142
+ return value;
143
+ }
144
+ function decodeCookieValue(value) {
145
+ try {
146
+ return decodeURIComponent(value);
147
+ } catch {
148
+ return value;
149
+ }
150
+ }
151
+ function validateCookie(name, options) {
152
+ if (!/^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/.test(name)) {
153
+ throw new TypeError("Cookie name must be a valid HTTP token");
154
+ }
155
+ if (options.path !== undefined && (!options.path.startsWith("/") || /[;\r\n\0]/.test(options.path))) {
156
+ throw new TypeError("Cookie path must start with '/' and contain no controls");
157
+ }
158
+ if (options.domain !== undefined && (!/^(?:\.?[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?)(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?)*$/.test(options.domain) || options.domain.includes(".."))) {
159
+ throw new TypeError("Cookie domain is invalid");
160
+ }
161
+ if (options.maxAge !== undefined && (!Number.isSafeInteger(options.maxAge) || options.maxAge < 0)) {
162
+ throw new TypeError("Cookie maxAge must be a non-negative safe integer");
163
+ }
164
+ if (options.expires !== undefined && !Number.isFinite(options.expires.getTime())) {
165
+ throw new TypeError("Cookie expires must be a valid Date");
166
+ }
167
+ if (options.sameSite !== undefined && !["strict", "lax", "none"].includes(options.sameSite.toLowerCase())) {
168
+ throw new TypeError("Cookie sameSite must be Strict, Lax, or None");
169
+ }
170
+ if (options.sameSite?.toLowerCase() === "none" && !options.secure) {
171
+ throw new TypeError("SameSite=None cookies must also be Secure");
172
+ }
173
+ if (name.startsWith("__Secure-") && !options.secure) {
174
+ throw new TypeError("__Secure- cookies must also be Secure");
175
+ }
176
+ if (name.startsWith("__Host-") && (!options.secure || options.path !== "/" || options.domain !== undefined)) {
177
+ throw new TypeError("__Host- cookies must be Secure, use Path=/, and omit Domain");
178
+ }
179
+ }
180
+ function snapshotOptions(options) {
181
+ if (!options)
182
+ return {};
183
+ return {
184
+ ...options,
185
+ ...options.expires === undefined ? {} : { expires: new Date(options.expires.getTime()) }
186
+ };
187
+ }
188
+ function parseCookieHeader(header) {
189
+ const cookies = new Map;
190
+ let pos = 0;
191
+ const len = header.length;
192
+ while (pos < len) {
193
+ while (pos < len && header.charCodeAt(pos) === 32)
194
+ pos++;
195
+ if (pos >= len)
196
+ break;
197
+ const eq = header.indexOf("=", pos);
198
+ if (eq === -1)
199
+ break;
200
+ const name = header.slice(pos, eq).trim();
201
+ pos = eq + 1;
202
+ let end = header.indexOf(";", pos);
203
+ if (end === -1)
204
+ end = len;
205
+ const value = header.slice(pos, end);
206
+ if (name)
207
+ cookies.set(name, decodeCookieValue(value));
208
+ pos = end + 1;
209
+ }
210
+ return cookies;
211
+ }
212
+ function getCookies(state) {
213
+ if (state.cookies !== null)
214
+ return state.cookies;
215
+ const header = state.requestHeaders?.get("cookie") ?? "";
216
+ state.requestHeaders = undefined;
217
+ state.cookies = header.length === 0 ? new Map : parseCookieHeader(header);
218
+ return state.cookies;
219
+ }
220
+ function getPending(state) {
221
+ if (state.pending === null)
222
+ state.pending = [];
223
+ return state.pending;
224
+ }
225
+ function createCookieJar(secret, requestHeaders, onMutation) {
226
+ return new CookieJarImpl(secret ?? "", requestHeaders, onMutation);
227
+ }
228
+ function applyPendingCookies(cookieJar, headers) {
229
+ if (!(cookieJar instanceof CookieJarImpl)) {
230
+ throw new TypeError("CookieJar was not created by Barq");
231
+ }
232
+ cookieJar.apply(headers);
233
+ }
234
+
235
+ // src/http.ts
236
+ var NULL_BODY_STATUSES = new Set([204, 205, 304]);
237
+ var DEFAULT_JSON_HEADERS = Object.freeze({
238
+ "content-type": "application/json; charset=utf-8"
239
+ });
240
+ var DEFAULT_JSON_INIT = Object.freeze({
241
+ status: 200,
242
+ headers: DEFAULT_JSON_HEADERS
243
+ });
244
+ var DEFAULT_TEXT_HEADERS = Object.freeze({
245
+ "content-type": "text/plain; charset=utf-8"
246
+ });
247
+ function isNullBodyStatus(status) {
248
+ return status >= 100 && status < 200 || NULL_BODY_STATUSES.has(status);
249
+ }
250
+ function createJsonResponse(data, init) {
251
+ if (data === undefined || typeof data === "function" || typeof data === "symbol") {
252
+ return new Response(JSON.stringify(data), init);
253
+ }
254
+ return Response.json(data, init);
255
+ }
256
+ function json(data, init) {
257
+ if (init === undefined) {
258
+ if (typeof data === "object" && data !== null) {
259
+ return new Response(JSON.stringify(data), DEFAULT_JSON_INIT);
260
+ }
261
+ return createJsonResponse(data, DEFAULT_JSON_INIT);
262
+ }
263
+ if (typeof init === "number") {
264
+ if (isNullBodyStatus(init)) {
265
+ return new Response(null, { status: init });
266
+ }
267
+ return createJsonResponse(data, {
268
+ status: init,
269
+ headers: DEFAULT_JSON_HEADERS
270
+ });
271
+ }
272
+ const status = init.status ?? 200;
273
+ if (isNullBodyStatus(status)) {
274
+ return new Response(null, { ...init, status });
275
+ }
276
+ if (init.headers === undefined) {
277
+ return createJsonResponse(data, {
278
+ ...init,
279
+ status,
280
+ headers: DEFAULT_JSON_HEADERS
281
+ });
282
+ }
283
+ const headers = new Headers(init.headers);
284
+ if (!headers.has("content-type")) {
285
+ headers.set("content-type", "application/json; charset=utf-8");
286
+ }
287
+ return createJsonResponse(data, { ...init, status, headers });
288
+ }
289
+ function text(body, init) {
290
+ if (init === undefined) {
291
+ return new Response(body);
292
+ }
293
+ if (typeof init === "number") {
294
+ if (isNullBodyStatus(init)) {
295
+ return new Response(null, { status: init });
296
+ }
297
+ return new Response(body, {
298
+ status: init,
299
+ headers: DEFAULT_TEXT_HEADERS
300
+ });
301
+ }
302
+ const status = init.status ?? 200;
303
+ if (isNullBodyStatus(status)) {
304
+ return new Response(null, { ...init, status });
305
+ }
306
+ if (init.headers === undefined) {
307
+ return new Response(body, {
308
+ ...init,
309
+ status,
310
+ headers: DEFAULT_TEXT_HEADERS
311
+ });
312
+ }
313
+ const headers = new Headers(init.headers);
314
+ if (!headers.has("content-type")) {
315
+ headers.set("content-type", "text/plain; charset=utf-8");
316
+ }
317
+ return new Response(body, { ...init, status, headers });
318
+ }
319
+ function empty(status = 204, headers) {
320
+ const init = headers !== undefined ? { status, headers } : { status };
321
+ return new Response(null, init);
322
+ }
323
+ var CONTROL_CHARS = /[\u0000-\u001f\u007f]/;
324
+ var ALLOWED_REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
325
+ function redirect(url, status = 302, allowlist) {
326
+ if (!ALLOWED_REDIRECT_STATUSES.has(status)) {
327
+ throw new TypeError(`redirect status must be one of: ${Array.from(ALLOWED_REDIRECT_STATUSES).join(", ")}`);
328
+ }
329
+ if (CONTROL_CHARS.test(url) || url.includes("\\")) {
330
+ throw new TypeError("redirect target contains control or backslash characters");
331
+ }
332
+ if (url.charCodeAt(0) === 47) {
333
+ if (url.charCodeAt(1) === 47) {
334
+ throw new TypeError("redirect target must not be protocol-relative");
335
+ }
336
+ } else {
337
+ let parsed;
338
+ try {
339
+ parsed = new URL(url);
340
+ } catch {
341
+ throw new TypeError("redirect target must be a root-relative path or an absolute URL");
342
+ }
343
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
344
+ throw new TypeError(`redirect target protocol is not allowed: ${parsed.protocol}`);
345
+ }
346
+ const host = parsed.host.toLowerCase();
347
+ if (allowlist !== undefined && !allowlist.has(host)) {
348
+ throw new TypeError(`redirect target host is not allowlisted: ${host}`);
349
+ }
350
+ }
351
+ const res = new Response(null, { status });
352
+ res.headers.set("location", url);
353
+ return res;
354
+ }
355
+
356
+ // src/internal/ip.ts
357
+ import { isIP } from "node:net";
358
+ function ipv4ToNumber(bytes) {
359
+ return (bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3]) >>> 0;
360
+ }
361
+ function compileTrustProxy(trust) {
362
+ if (!trust)
363
+ return () => false;
364
+ if (trust === true)
365
+ return () => true;
366
+ if (typeof trust === "function")
367
+ return trust;
368
+ const ranges = typeof trust === "string" ? [trust] : trust;
369
+ if (ranges.length === 0)
370
+ return () => false;
371
+ const matchers = [];
372
+ for (const range of ranges) {
373
+ if (range === "loopback") {
374
+ matchers.push((ip) => {
375
+ const addr = parseIpAddress(ip);
376
+ if (addr === null)
377
+ return false;
378
+ if (addr.length === 4)
379
+ return addr[0] === 127;
380
+ return addr.slice(0, 15).every((b) => b === 0) && addr[15] === 1;
381
+ });
382
+ continue;
383
+ }
384
+ const slash = range.indexOf("/");
385
+ const netText = slash === -1 ? range : range.slice(0, slash);
386
+ const netBytes = parseIpAddress(netText);
387
+ if (!netBytes)
388
+ continue;
389
+ const bits = slash === -1 ? netBytes.length * 8 : Number(range.slice(slash + 1));
390
+ if (netBytes.length === 4) {
391
+ const netNum = ipv4ToNumber(netBytes);
392
+ const mask = bits === 0 ? 0 : ~0 << 32 - bits >>> 0;
393
+ const expected = (netNum & mask) >>> 0;
394
+ matchers.push((ip) => {
395
+ const addr = parseIpAddress(ip);
396
+ if (addr?.length !== 4)
397
+ return false;
398
+ return (ipv4ToNumber(addr) & mask) >>> 0 === expected;
399
+ });
400
+ } else {
401
+ matchers.push((ip) => ipMatchesRange(ip, range));
402
+ }
403
+ }
404
+ return (ip) => matchers.some((m) => m(ip));
405
+ }
406
+ function isIpRange(value) {
407
+ if (value === "loopback")
408
+ return true;
409
+ const slash = value.indexOf("/");
410
+ if (slash !== value.lastIndexOf("/"))
411
+ return false;
412
+ const address = slash === -1 ? value : value.slice(0, slash);
413
+ const bytes = parseIpAddress(address);
414
+ if (bytes === null)
415
+ return false;
416
+ if (slash === -1)
417
+ return true;
418
+ const bitsText = value.slice(slash + 1);
419
+ if (!/^\d+$/.test(bitsText))
420
+ return false;
421
+ const bits = Number(bitsText);
422
+ return Number.isInteger(bits) && bits >= 0 && bits <= bytes.length * 8;
423
+ }
424
+ function ipMatchesRange(ip, range) {
425
+ const address = parseIpAddress(ip);
426
+ if (address === null)
427
+ return false;
428
+ if (range === "loopback") {
429
+ if (address.length === 4)
430
+ return address[0] === 127;
431
+ return address.slice(0, 15).every((byte) => byte === 0) && address[15] === 1;
432
+ }
433
+ const slash = range.indexOf("/");
434
+ const networkText = slash === -1 ? range : range.slice(0, slash);
435
+ const network = parseIpAddress(networkText);
436
+ if (network === null || address.length !== network.length)
437
+ return false;
438
+ const bits = slash === -1 ? network.length * 8 : Number(range.slice(slash + 1));
439
+ if (!Number.isInteger(bits) || bits < 0 || bits > network.length * 8) {
440
+ return false;
441
+ }
442
+ const fullBytes = Math.floor(bits / 8);
443
+ for (let i = 0;i < fullBytes; i++) {
444
+ if (address[i] !== network[i])
445
+ return false;
446
+ }
447
+ const remainingBits = bits % 8;
448
+ if (remainingBits === 0)
449
+ return true;
450
+ const mask = 255 << 8 - remainingBits & 255;
451
+ return (address[fullBytes] & mask) === (network[fullBytes] & mask);
452
+ }
453
+ function isValidIpAddress(value) {
454
+ return parseIpAddress(value) !== null;
455
+ }
456
+ function parseIpAddress(value) {
457
+ const version = isIP(value);
458
+ if (version === 4) {
459
+ const bytes = value.split(".").map(Number);
460
+ if (bytes.length !== 4)
461
+ return null;
462
+ return Uint8Array.from(bytes);
463
+ }
464
+ if (version !== 6)
465
+ return null;
466
+ let address = value.toLowerCase();
467
+ if (address.includes(".")) {
468
+ const separator = address.lastIndexOf(":");
469
+ const ipv4 = address.slice(separator + 1).split(".").map(Number);
470
+ if (separator === -1 || ipv4.length !== 4)
471
+ return null;
472
+ const high = (ipv4[0] << 8 | ipv4[1]).toString(16);
473
+ const low = (ipv4[2] << 8 | ipv4[3]).toString(16);
474
+ address = `${address.slice(0, separator + 1)}${high}:${low}`;
475
+ }
476
+ const halves = address.split("::");
477
+ if (halves.length > 2)
478
+ return null;
479
+ const left = halves[0] ? halves[0].split(":") : [];
480
+ const right = halves.length === 2 && halves[1] ? halves[1].split(":") : [];
481
+ const missing = 8 - left.length - right.length;
482
+ if (halves.length === 1 && missing !== 0 || halves.length === 2 && missing < 1) {
483
+ return null;
484
+ }
485
+ const groups = [
486
+ ...left,
487
+ ...new Array(halves.length === 2 ? missing : 0).fill("0"),
488
+ ...right
489
+ ];
490
+ if (groups.length !== 8 || groups.some((group) => !/^[0-9a-f]{1,4}$/.test(group))) {
491
+ return null;
492
+ }
493
+ const bytes = new Uint8Array(16);
494
+ for (let i = 0;i < groups.length; i++) {
495
+ const group = Number.parseInt(groups[i], 16);
496
+ bytes[i * 2] = group >>> 8;
497
+ bytes[i * 2 + 1] = group & 255;
498
+ }
499
+ return bytes;
500
+ }
501
+
502
+ // src/errors.ts
503
+ class HttpError extends Error {
504
+ status;
505
+ body;
506
+ headers;
507
+ constructor(status, body, headers) {
508
+ if (!Number.isInteger(status) || status < 100 || status > 599) {
509
+ throw new Error(`Invalid HTTP status code: ${status}. Must be an integer between 100 and 599.`);
510
+ }
511
+ super(typeof body === "string" ? body : `HTTP ${status}`);
512
+ this.name = "HttpError";
513
+ this.status = status;
514
+ this.body = body ?? { error: defaultStatusText(status) };
515
+ if (headers !== undefined)
516
+ this.headers = headers;
517
+ }
518
+ }
519
+ function defaultStatusText(status) {
520
+ switch (status) {
521
+ case 400:
522
+ return "Bad Request";
523
+ case 401:
524
+ return "Unauthorized";
525
+ case 403:
526
+ return "Forbidden";
527
+ case 404:
528
+ return "Not Found";
529
+ case 405:
530
+ return "Method Not Allowed";
531
+ case 408:
532
+ return "Request Timeout";
533
+ case 409:
534
+ return "Conflict";
535
+ case 413:
536
+ return "Payload Too Large";
537
+ case 418:
538
+ return "I'm a teapot";
539
+ case 422:
540
+ return "Unprocessable Entity";
541
+ case 429:
542
+ return "Too Many Requests";
543
+ case 500:
544
+ return "Internal Server Error";
545
+ case 502:
546
+ return "Bad Gateway";
547
+ case 503:
548
+ return "Service Unavailable";
549
+ case 504:
550
+ return "Gateway Timeout";
551
+ default:
552
+ return status >= 500 ? "Internal Server Error" : "Error";
553
+ }
554
+ }
555
+ function safeJson(status, body, headers) {
556
+ try {
557
+ const init = headers !== undefined ? { status, headers } : { status };
558
+ return json(body, init);
559
+ } catch {
560
+ return new Response("Internal Server Error", {
561
+ status: 500,
562
+ headers: { "content-type": "text/plain; charset=utf-8" }
563
+ });
564
+ }
565
+ }
566
+ function errorToResponse(err, development) {
567
+ if (err instanceof Response) {
568
+ return err;
569
+ }
570
+ if (err instanceof HttpError) {
571
+ return safeJson(err.status, err.body, err.headers);
572
+ }
573
+ if (development) {
574
+ const message = err instanceof Error ? err.message : String(err);
575
+ const stack = err instanceof Error ? err.stack : undefined;
576
+ return safeJson(500, { error: "Internal Server Error", message, stack });
577
+ }
578
+ return safeJson(500, { error: "Internal Server Error" });
579
+ }
580
+ var createErrorResponse = errorToResponse;
581
+
582
+ // src/internal/pathname.ts
583
+ function decodeSegment(seg) {
584
+ if (seg.indexOf("%") === -1)
585
+ return seg;
586
+ try {
587
+ return decodeURIComponent(seg);
588
+ } catch {
589
+ return seg;
590
+ }
591
+ }
592
+ function decodePercentSegment(seg) {
593
+ try {
594
+ return decodeURIComponent(seg);
595
+ } catch {
596
+ return seg;
597
+ }
598
+ }
599
+ function isDotSegment(seg) {
600
+ return seg === "." || seg === "..";
601
+ }
602
+ function hasDotSegment(path) {
603
+ let i = 0;
604
+ const len = path.length;
605
+ while (i < len) {
606
+ while (i < len && path.charCodeAt(i) === 47)
607
+ i++;
608
+ if (i >= len)
609
+ break;
610
+ const endIdx = path.indexOf("/", i);
611
+ const segEnd = endIdx === -1 ? len : endIdx;
612
+ const segmentLength = segEnd - i;
613
+ if (segmentLength === 1 && path.charCodeAt(i) === 46 || segmentLength === 2 && path.charCodeAt(i) === 46 && path.charCodeAt(i + 1) === 46) {
614
+ return true;
615
+ }
616
+ const percent = path.indexOf("%", i);
617
+ if (percent !== -1 && percent < segEnd) {
618
+ const decoded = decodePercentSegment(path.slice(i, segEnd));
619
+ if (isDotSegment(decoded))
620
+ return true;
621
+ }
622
+ if (endIdx === -1)
623
+ break;
624
+ i = endIdx + 1;
625
+ }
626
+ return false;
627
+ }
628
+ function targetStart(url) {
629
+ if (url.charCodeAt(0) === 47)
630
+ return 0;
631
+ if (url.charCodeAt(4) === 58 && url.charCodeAt(5) === 47 && url.charCodeAt(6) === 47)
632
+ return 7;
633
+ if (url.charCodeAt(5) === 58 && url.charCodeAt(6) === 47 && url.charCodeAt(7) === 47)
634
+ return 8;
635
+ const scheme = url.indexOf("://");
636
+ return scheme === -1 ? 0 : scheme + 3;
637
+ }
638
+ function normalizeDotSegments(path) {
639
+ const len = path.length;
640
+ const segments = [];
641
+ let start = 0;
642
+ while (start < len) {
643
+ while (start < len && path.charCodeAt(start) === 47)
644
+ start++;
645
+ if (start >= len)
646
+ break;
647
+ const end = path.indexOf("/", start);
648
+ const segEnd = end === -1 ? len : end;
649
+ const rawSeg = path.slice(start, segEnd);
650
+ const decodedSeg = decodeSegment(rawSeg);
651
+ if (decodedSeg === ".") {} else if (decodedSeg === "..") {
652
+ segments.pop();
653
+ } else {
654
+ segments.push(rawSeg);
655
+ }
656
+ if (end === -1)
657
+ break;
658
+ start = end + 1;
659
+ }
660
+ const res = `/${segments.join("/")}`;
661
+ const endsWithSlash = path.endsWith("/") || path.endsWith("/.") || path.endsWith("/..");
662
+ return path.length > 1 && endsWithSlash && res !== "/" ? `${res}/` : res;
663
+ }
664
+ function scanPathname(url) {
665
+ const s = targetStart(url);
666
+ const slash = url.indexOf("/", s);
667
+ if (slash === -1)
668
+ return "/";
669
+ let end = url.indexOf("?", slash);
670
+ if (end === -1) {
671
+ end = url.indexOf("#", slash);
672
+ if (end === -1)
673
+ end = url.length;
674
+ } else {
675
+ const hash = url.indexOf("#", slash);
676
+ if (hash !== -1 && hash < end)
677
+ end = hash;
678
+ }
679
+ const raw = url.slice(slash, end);
680
+ if (raw.indexOf("%00") !== -1 || raw.indexOf("\x00") !== -1) {
681
+ throw new HttpError(400, { error: "Bad Request" });
682
+ }
683
+ if (raw.indexOf(".") === -1 && raw.indexOf("%") === -1)
684
+ return raw;
685
+ return hasDotSegment(raw) ? normalizeDotSegments(raw) : raw;
686
+ }
687
+ function parseRequestTarget(url) {
688
+ const s = targetStart(url);
689
+ const slash = url.indexOf("/", s);
690
+ let pathname;
691
+ let query;
692
+ if (slash === -1) {
693
+ pathname = "/";
694
+ const q = url.indexOf("?", s);
695
+ const h = url.indexOf("#", s);
696
+ if (q !== -1 && (h === -1 || q < h)) {
697
+ query = h === -1 ? url.slice(q + 1) : url.slice(q + 1, h);
698
+ }
699
+ } else {
700
+ let end = url.indexOf("?", slash);
701
+ const hash = url.indexOf("#", slash);
702
+ if (hash !== -1 && (end === -1 || hash < end))
703
+ end = hash;
704
+ if (end === -1) {
705
+ end = url.length;
706
+ } else if (url.charCodeAt(end) === 63) {
707
+ query = hash !== -1 && hash > end ? url.slice(end + 1, hash) : url.slice(end + 1);
708
+ }
709
+ const raw = url.slice(slash, end);
710
+ if (raw.indexOf("%00") !== -1 || raw.indexOf("\x00") !== -1) {
711
+ throw new HttpError(400, { error: "Bad Request" });
712
+ }
713
+ pathname = hasDotSegment(raw) ? normalizeDotSegments(raw) : raw;
714
+ }
715
+ return { pathname, query };
716
+ }
717
+
718
+ // src/internal/query.ts
719
+ function decodeQueryComponent(value) {
720
+ const hasPlus = value.indexOf("+") !== -1;
721
+ const hasPercent = value.indexOf("%") !== -1;
722
+ if (!hasPlus && !hasPercent)
723
+ return value;
724
+ const formValue = hasPlus ? value.replace(/\+/g, " ") : value;
725
+ if (!hasPercent)
726
+ return formValue;
727
+ try {
728
+ return decodeURIComponent(formValue);
729
+ } catch {
730
+ return new URLSearchParams(`v=${value}`).get("v") ?? "";
731
+ }
732
+ }
733
+ function findQueryParam(url, name, startPos) {
734
+ const queryStart = startPos !== undefined && startPos >= 0 ? startPos : url.indexOf("?");
735
+ if (queryStart === -1)
736
+ return null;
737
+ const hashPos = url.indexOf("#", queryStart);
738
+ const len = hashPos === -1 ? url.length : hashPos;
739
+ let s = queryStart + 1;
740
+ const nameLen = name.length;
741
+ while (s < len) {
742
+ if (url.startsWith(name, s)) {
743
+ const eqPos = s + nameLen;
744
+ if (eqPos >= len)
745
+ return "";
746
+ const nextChar = url.charCodeAt(eqPos);
747
+ if (nextChar === 61) {
748
+ const valStart = eqPos + 1;
749
+ let amp = url.indexOf("&", valStart);
750
+ if (amp === -1 || amp > len)
751
+ amp = len;
752
+ const val = url.slice(valStart, amp);
753
+ if (val.indexOf("+") === -1 && val.indexOf("%") === -1) {
754
+ return val;
755
+ }
756
+ return decodeQueryComponent(val);
757
+ }
758
+ if (nextChar === 38) {
759
+ return "";
760
+ }
761
+ }
762
+ const amp = url.indexOf("&", s);
763
+ if (amp === -1 || amp >= len)
764
+ break;
765
+ s = amp + 1;
766
+ }
767
+ return null;
768
+ }
769
+ function findQueryParamAll(url, name) {
770
+ const res = [];
771
+ const queryStart = url.indexOf("?");
772
+ if (queryStart === -1)
773
+ return res;
774
+ const hashPos = url.indexOf("#", queryStart);
775
+ const len = hashPos === -1 ? url.length : hashPos;
776
+ let s = queryStart + 1;
777
+ const nLen = name.length;
778
+ while (s < len) {
779
+ let amp = url.indexOf("&", s);
780
+ if (amp === -1 || amp > len)
781
+ amp = len;
782
+ let eq = url.indexOf("=", s);
783
+ if (eq === -1 || eq > amp)
784
+ eq = amp;
785
+ if (eq - s === nLen && url.startsWith(name, s)) {
786
+ const val = eq < amp ? url.slice(eq + 1, amp) : "";
787
+ if (val.indexOf("%") === -1 && val.indexOf("+") === -1) {
788
+ res.push(val);
789
+ } else {
790
+ try {
791
+ res.push(decodeURIComponent(val.replace(/\+/g, " ")));
792
+ } catch {
793
+ res.push(val);
794
+ }
795
+ }
796
+ }
797
+ s = amp + 1;
798
+ }
799
+ return res;
800
+ }
801
+ function parseAllQueryParams(url) {
802
+ const qIdx = url.indexOf("?");
803
+ if (qIdx === -1)
804
+ return Object.create(null);
805
+ const hashPos = url.indexOf("#", qIdx);
806
+ const len = hashPos === -1 ? url.length : hashPos;
807
+ const res = Object.create(null);
808
+ let s = qIdx + 1;
809
+ while (s < len) {
810
+ let amp = url.indexOf("&", s);
811
+ if (amp === -1 || amp > len)
812
+ amp = len;
813
+ let eq = url.indexOf("=", s);
814
+ if (eq === -1 || eq > amp)
815
+ eq = amp;
816
+ const k = decodeQueryComponent(url.slice(s, eq));
817
+ const v = eq < amp ? decodeQueryComponent(url.slice(eq + 1, amp)) : "";
818
+ if (res[k] === undefined)
819
+ res[k] = v;
820
+ s = amp + 1;
821
+ }
822
+ return res;
823
+ }
824
+
825
+ // src/context.ts
826
+ var TEXT_DECODER = new TextDecoder;
827
+
828
+ class Context {
829
+ req;
830
+ params;
831
+ _hasPendingCookies = false;
832
+ server;
833
+ application;
834
+ _pathname;
835
+ _query = null;
836
+ _url = null;
837
+ _queryParams = null;
838
+ _lazy = null;
839
+ constructor(req, server, params, application, pathname) {
840
+ this.req = req;
841
+ this.server = server;
842
+ this.params = params;
843
+ this.application = application;
844
+ this._pathname = pathname ?? null;
845
+ this._query = null;
846
+ }
847
+ _getLazy() {
848
+ let lazy = this._lazy;
849
+ if (lazy === null) {
850
+ lazy = {};
851
+ this._lazy = lazy;
852
+ }
853
+ return lazy;
854
+ }
855
+ get development() {
856
+ return this.application.development;
857
+ }
858
+ get redirectHosts() {
859
+ return this.application.redirectHosts;
860
+ }
861
+ get trustProxy() {
862
+ return this.application.trustProxy;
863
+ }
864
+ get cookies() {
865
+ const lazy = this._getLazy();
866
+ if (!lazy.cookies) {
867
+ lazy.cookies = createCookieJar(this.application.cookieSecret ?? "", this.req.headers, () => {
868
+ this._hasPendingCookies = true;
869
+ });
870
+ }
871
+ return lazy.cookies;
872
+ }
873
+ _cookieJarIfCreated() {
874
+ return this._lazy?.cookies ?? null;
875
+ }
876
+ get state() {
877
+ const lazy = this._getLazy();
878
+ if (!lazy.state) {
879
+ lazy.state = Object.create(null);
880
+ }
881
+ return lazy.state;
882
+ }
883
+ get valid() {
884
+ const lazy = this._lazy;
885
+ if (lazy && lazy.valid !== undefined)
886
+ return lazy.valid;
887
+ return lazy?.state?.valid;
888
+ }
889
+ set valid(val) {
890
+ this._getLazy().valid = val;
891
+ this.state.valid = val;
892
+ }
893
+ get pathname() {
894
+ if (this._pathname !== null)
895
+ return this._pathname;
896
+ const p = scanPathname(this.req.url);
897
+ this._pathname = p;
898
+ return p;
899
+ }
900
+ get query() {
901
+ if (this._query)
902
+ return this._query;
903
+ const url = this.req.url;
904
+ const qIdx = url.indexOf("?");
905
+ if (qIdx === -1) {
906
+ const sp = new URLSearchParams("");
907
+ this._query = sp;
908
+ return sp;
909
+ }
910
+ const hashIdx = url.indexOf("#", qIdx);
911
+ const qStr = hashIdx === -1 ? url.slice(qIdx + 1) : url.slice(qIdx + 1, hashIdx);
912
+ const sp = new URLSearchParams(qStr);
913
+ this._query = sp;
914
+ return sp;
915
+ }
916
+ queryParam(name) {
917
+ if (this._query)
918
+ return this._query.get(name);
919
+ if (this._queryParams === null) {
920
+ if (this._url === null)
921
+ this._url = this.req.url;
922
+ this._queryParams = parseAllQueryParams(this._url);
923
+ }
924
+ return this._queryParams[name] ?? null;
925
+ }
926
+ queryParamAll(name) {
927
+ return this.query.getAll(name);
928
+ }
929
+ get ip() {
930
+ const lazy = this._lazy;
931
+ if (lazy && typeof lazy.ip === "string")
932
+ return lazy.ip;
933
+ const directIp = this.getDirectIp();
934
+ if (!this.isTrustedProxy(directIp)) {
935
+ this._getLazy().ip = directIp;
936
+ return directIp;
937
+ }
938
+ const forwarded = this.req.headers.get("x-forwarded-for");
939
+ if (forwarded) {
940
+ const hops = forwarded.split(",").map((hop) => hop.trim());
941
+ if (hops.every(isValidIpAddress)) {
942
+ let clientIp = directIp;
943
+ for (let i = hops.length - 1;i >= 0; i--) {
944
+ if (clientIp && !this.isTrustedProxy(clientIp))
945
+ break;
946
+ clientIp = hops[i];
947
+ }
948
+ this._getLazy().ip = clientIp;
949
+ return clientIp;
950
+ }
951
+ this._getLazy().ip = directIp;
952
+ return directIp;
953
+ }
954
+ const realIp = this.req.headers.get("x-real-ip")?.trim();
955
+ if (realIp && isValidIpAddress(realIp)) {
956
+ this._getLazy().ip = realIp;
957
+ return realIp;
958
+ }
959
+ this._getLazy().ip = directIp;
960
+ return directIp;
961
+ }
962
+ isTrustedProxy(ip) {
963
+ const trust = this.trustProxy;
964
+ if (trust === true)
965
+ return true;
966
+ if (trust === false || !ip)
967
+ return false;
968
+ if (this.application.trustedProxyChecker) {
969
+ return this.application.trustedProxyChecker(ip);
970
+ }
971
+ if (typeof trust === "function")
972
+ return trust(ip);
973
+ if (typeof trust !== "string") {
974
+ return trust.some((range) => ipMatchesRange(ip, range));
975
+ }
976
+ return ipMatchesRange(ip, trust);
977
+ }
978
+ getDirectIp() {
979
+ const info = this.server?.requestIP(this.req);
980
+ return info?.address ?? "";
981
+ }
982
+ get bodyStream() {
983
+ return this.req.body;
984
+ }
985
+ stream() {
986
+ return this.req.body;
987
+ }
988
+ _getBodyBuffer() {
989
+ const lazy = this._getLazy();
990
+ if (!lazy.bodyBufferPromise) {
991
+ lazy.bodyBufferPromise = this.req.arrayBuffer().catch((err) => {
992
+ lazy.bodyBufferPromise = null;
993
+ throw err;
994
+ });
995
+ }
996
+ return lazy.bodyBufferPromise;
997
+ }
998
+ arrayBuffer() {
999
+ return this._getBodyBuffer();
1000
+ }
1001
+ text() {
1002
+ const lazy = this._getLazy();
1003
+ if (!lazy.textPromise) {
1004
+ lazy.textPromise = this._getBodyBuffer().then((buf) => TEXT_DECODER.decode(buf)).catch((err) => {
1005
+ lazy.textPromise = null;
1006
+ throw err;
1007
+ });
1008
+ }
1009
+ return lazy.textPromise;
1010
+ }
1011
+ json() {
1012
+ const lazy = this._getLazy();
1013
+ if (!lazy.jsonPromise) {
1014
+ lazy.jsonPromise = this._getBodyBuffer().then((buf) => JSON.parse(TEXT_DECODER.decode(buf))).catch((err) => {
1015
+ lazy.jsonPromise = null;
1016
+ throw err;
1017
+ });
1018
+ }
1019
+ return lazy.jsonPromise;
1020
+ }
1021
+ blob() {
1022
+ const lazy = this._getLazy();
1023
+ if (!lazy.blobPromise) {
1024
+ const ct = this.req.headers.get("content-type") ?? "application/octet-stream";
1025
+ lazy.blobPromise = this._getBodyBuffer().then((buf) => new Blob([buf], { type: ct })).catch((err) => {
1026
+ lazy.blobPromise = null;
1027
+ throw err;
1028
+ });
1029
+ }
1030
+ return lazy.blobPromise;
1031
+ }
1032
+ formData() {
1033
+ const lazy = this._getLazy();
1034
+ if (!lazy.formDataPromise) {
1035
+ lazy.formDataPromise = this._getBodyBuffer().then((buf) => {
1036
+ const ct = this.req.headers.get("content-type") ?? "";
1037
+ const tempRes = new Response(buf, {
1038
+ headers: { "content-type": ct }
1039
+ });
1040
+ return tempRes.formData();
1041
+ }).catch((err) => {
1042
+ lazy.formDataPromise = null;
1043
+ throw err;
1044
+ });
1045
+ }
1046
+ return lazy.formDataPromise;
1047
+ }
1048
+ redirect(url, status = 302) {
1049
+ return redirect(url, status, this.redirectHosts);
1050
+ }
1051
+ upgrade(data) {
1052
+ if (!this.server) {
1053
+ throw new Error("Cannot upgrade WebSocket: server instance is not available");
1054
+ }
1055
+ return this.server.upgrade(this.req, { data });
1056
+ }
1057
+ timeout(seconds) {
1058
+ if (this.server) {
1059
+ this.server.timeout(this.req, seconds);
1060
+ }
1061
+ return this;
1062
+ }
1063
+ disableTimeout() {
1064
+ if (this.server) {
1065
+ this.server.timeout(this.req, 0);
1066
+ }
1067
+ return this;
1068
+ }
1069
+ }
1070
+
1071
+ // src/internal/scan.ts
1072
+ var ESCAPE_JSON_CHARS_RE = /[\u0000-\u001f"\\]/;
1073
+ function escapeJsonString(value) {
1074
+ if (!ESCAPE_JSON_CHARS_RE.test(value))
1075
+ return value;
1076
+ return JSON.stringify(value).slice(1, -1);
1077
+ }
1078
+ function isIdentStart(c) {
1079
+ return c >= 97 && c <= 122 || c >= 65 && c <= 90 || c === 95 || c === 36 || c > 127;
1080
+ }
1081
+ function isIdentPart(c) {
1082
+ return isIdentStart(c) || c >= 48 && c <= 57;
1083
+ }
1084
+ function isSpace(c) {
1085
+ return c === 32 || c === 9 || c === 10 || c === 13 || c === 12 || c === 11;
1086
+ }
1087
+ var KEYWORDS_BEFORE_REGEX = new Set([
1088
+ "return",
1089
+ "typeof",
1090
+ "instanceof",
1091
+ "in",
1092
+ "of",
1093
+ "new",
1094
+ "delete",
1095
+ "void",
1096
+ "throw",
1097
+ "case",
1098
+ "do",
1099
+ "else",
1100
+ "yield",
1101
+ "await"
1102
+ ]);
1103
+ var PUNCT_BEFORE_REGEX = new Set([
1104
+ "(",
1105
+ "[",
1106
+ "{",
1107
+ ",",
1108
+ ";",
1109
+ ":",
1110
+ "?",
1111
+ "!",
1112
+ "=",
1113
+ "==",
1114
+ "===",
1115
+ "!=",
1116
+ "!==",
1117
+ "&&",
1118
+ "||",
1119
+ "??",
1120
+ "+",
1121
+ "-",
1122
+ "*",
1123
+ "/",
1124
+ "%",
1125
+ "&",
1126
+ "|",
1127
+ "^",
1128
+ "~",
1129
+ "<",
1130
+ ">",
1131
+ "<=",
1132
+ ">=",
1133
+ "=>",
1134
+ "+=",
1135
+ "-=",
1136
+ "*=",
1137
+ "/=",
1138
+ "%=",
1139
+ "&=",
1140
+ "|=",
1141
+ "^=",
1142
+ "&&=",
1143
+ "||=",
1144
+ "??=",
1145
+ "<<",
1146
+ ">>",
1147
+ ">>>",
1148
+ "<<=",
1149
+ ">>=",
1150
+ ">>>="
1151
+ ]);
1152
+ function tokenize(src) {
1153
+ const tokens = [];
1154
+ const len = src.length;
1155
+ let i = 0;
1156
+ let last = "";
1157
+ while (i < len) {
1158
+ const c = src.charCodeAt(i);
1159
+ if (isSpace(c)) {
1160
+ i++;
1161
+ continue;
1162
+ }
1163
+ if (c === 47 && src.charCodeAt(i + 1) === 47) {
1164
+ i += 2;
1165
+ while (i < len && src.charCodeAt(i) !== 10)
1166
+ i++;
1167
+ continue;
1168
+ }
1169
+ if (c === 47 && src.charCodeAt(i + 1) === 42) {
1170
+ i += 2;
1171
+ while (i < len && !(src.charCodeAt(i) === 42 && src.charCodeAt(i + 1) === 47))
1172
+ i++;
1173
+ i += 2;
1174
+ continue;
1175
+ }
1176
+ if (c === 34 || c === 39) {
1177
+ const q = c;
1178
+ const start = i;
1179
+ i++;
1180
+ while (i < len) {
1181
+ const cc = src.charCodeAt(i);
1182
+ if (cc === 92) {
1183
+ i += 2;
1184
+ continue;
1185
+ }
1186
+ if (cc === q) {
1187
+ i++;
1188
+ break;
1189
+ }
1190
+ if (cc === 10)
1191
+ break;
1192
+ i++;
1193
+ }
1194
+ tokens.push({
1195
+ type: "str",
1196
+ value: src.slice(start + 1, i - 1),
1197
+ start,
1198
+ end: i
1199
+ });
1200
+ last = "str";
1201
+ continue;
1202
+ }
1203
+ if (c === 96) {
1204
+ i = tokenizeTemplate(src, i, tokens);
1205
+ last = "template";
1206
+ continue;
1207
+ }
1208
+ if (c === 47) {
1209
+ let isRegex;
1210
+ if (last === "" || last === "regex" || last === "num")
1211
+ isRegex = true;
1212
+ else if (last === "str" || last === "template")
1213
+ isRegex = false;
1214
+ else if (last === "ident")
1215
+ isRegex = KEYWORDS_BEFORE_REGEX.has(last);
1216
+ else
1217
+ isRegex = PUNCT_BEFORE_REGEX.has(last);
1218
+ if (isRegex) {
1219
+ const start = i;
1220
+ i++;
1221
+ let inClass = false;
1222
+ while (i < len) {
1223
+ const cc = src.charCodeAt(i);
1224
+ if (cc === 92) {
1225
+ i += 2;
1226
+ continue;
1227
+ }
1228
+ if (cc === 91) {
1229
+ inClass = true;
1230
+ i++;
1231
+ continue;
1232
+ }
1233
+ if (cc === 93) {
1234
+ inClass = false;
1235
+ i++;
1236
+ continue;
1237
+ }
1238
+ if (cc === 47 && !inClass) {
1239
+ i++;
1240
+ break;
1241
+ }
1242
+ if (cc === 10)
1243
+ break;
1244
+ i++;
1245
+ }
1246
+ while (i < len && isIdentPart(src.charCodeAt(i)))
1247
+ i++;
1248
+ tokens.push({ type: "regex", value: "", start, end: i });
1249
+ last = "regex";
1250
+ continue;
1251
+ }
1252
+ tokens.push({ type: "punct", value: "/", start: i, end: i + 1 });
1253
+ last = "/";
1254
+ i++;
1255
+ continue;
1256
+ }
1257
+ if (isIdentStart(c)) {
1258
+ const start = i;
1259
+ i++;
1260
+ while (i < len && isIdentPart(src.charCodeAt(i)))
1261
+ i++;
1262
+ const value = src.slice(start, i);
1263
+ tokens.push({ type: "ident", value, start, end: i });
1264
+ last = value;
1265
+ continue;
1266
+ }
1267
+ if (c >= 48 && c <= 57) {
1268
+ const start = i;
1269
+ i++;
1270
+ while (i < len) {
1271
+ const cc = src.charCodeAt(i);
1272
+ if (cc >= 48 && cc <= 57 || cc === 46 || cc === 95 || cc >= 97 && cc <= 122 || cc >= 65 && cc <= 90)
1273
+ i++;
1274
+ else if ((cc === 43 || cc === 45) && (src.charCodeAt(i - 1) === 101 || src.charCodeAt(i - 1) === 69))
1275
+ i++;
1276
+ else
1277
+ break;
1278
+ }
1279
+ tokens.push({ type: "num", value: src.slice(start, i), start, end: i });
1280
+ last = "num";
1281
+ continue;
1282
+ }
1283
+ const start = i;
1284
+ const cc2 = src.charCodeAt(i + 1);
1285
+ const cc3 = src.charCodeAt(i + 2);
1286
+ const cc4 = src.charCodeAt(i + 3);
1287
+ let op = src[i];
1288
+ if (c === 62 && cc2 === 62 && cc3 === 62 && cc4 === 61)
1289
+ op = ">>>=";
1290
+ else if (c === 61 && cc2 === 61 && cc3 === 61)
1291
+ op = "===";
1292
+ else if (c === 33 && cc2 === 61 && cc3 === 61)
1293
+ op = "!==";
1294
+ else if (c === 42 && cc2 === 42 && cc3 === 61)
1295
+ op = "**=";
1296
+ else if (c === 60 && cc2 === 60 && cc3 === 61)
1297
+ op = "<<=";
1298
+ else if (c === 62 && cc2 === 62 && cc3 === 61)
1299
+ op = ">>=";
1300
+ else if (c === 62 && cc2 === 62 && cc3 === 62)
1301
+ op = ">>>";
1302
+ else if (c === 46 && cc2 === 46 && cc3 === 46)
1303
+ op = "...";
1304
+ else if (c === 63 && cc2 === 63 && cc3 === 61)
1305
+ op = "??=";
1306
+ else if (c === 38 && cc2 === 38 && cc3 === 61)
1307
+ op = "&&=";
1308
+ else if (c === 124 && cc2 === 124 && cc3 === 61)
1309
+ op = "||=";
1310
+ else if (c === 61 && cc2 === 62)
1311
+ op = "=>";
1312
+ else if (c === 61 && cc2 === 61)
1313
+ op = "==";
1314
+ else if (c === 33 && cc2 === 61)
1315
+ op = "!=";
1316
+ else if (c === 60 && cc2 === 61)
1317
+ op = "<=";
1318
+ else if (c === 62 && cc2 === 61)
1319
+ op = ">=";
1320
+ else if (c === 38 && cc2 === 38)
1321
+ op = "&&";
1322
+ else if (c === 124 && cc2 === 124)
1323
+ op = "||";
1324
+ else if (c === 63 && cc2 === 46)
1325
+ op = "?.";
1326
+ else if (c === 63 && cc2 === 63)
1327
+ op = "??";
1328
+ else if (c === 43 && cc2 === 43)
1329
+ op = "++";
1330
+ else if (c === 45 && cc2 === 45)
1331
+ op = "--";
1332
+ else if (c === 42 && cc2 === 42)
1333
+ op = "**";
1334
+ else if (c === 60 && cc2 === 60)
1335
+ op = "<<";
1336
+ else if (c === 62 && cc2 === 62)
1337
+ op = ">>";
1338
+ else if (c === 43 && cc2 === 61)
1339
+ op = "+=";
1340
+ else if (c === 45 && cc2 === 61)
1341
+ op = "-=";
1342
+ else if (c === 42 && cc2 === 61)
1343
+ op = "*=";
1344
+ else if (c === 47 && cc2 === 61)
1345
+ op = "/=";
1346
+ else if (c === 37 && cc2 === 61)
1347
+ op = "%=";
1348
+ else if (c === 38 && cc2 === 61)
1349
+ op = "&=";
1350
+ else if (c === 124 && cc2 === 61)
1351
+ op = "|=";
1352
+ else if (c === 94 && cc2 === 61)
1353
+ op = "^=";
1354
+ i += op.length;
1355
+ tokens.push({ type: "punct", value: op, start, end: i });
1356
+ last = op;
1357
+ }
1358
+ tokens.push({ type: "eof", value: "", start: len, end: len });
1359
+ return tokens;
1360
+ }
1361
+ function tokenizeTemplate(src, start, out) {
1362
+ let i = start + 1;
1363
+ const len = src.length;
1364
+ let strStart = i;
1365
+ while (i < len) {
1366
+ const c = src.charCodeAt(i);
1367
+ if (c === 92) {
1368
+ i += 2;
1369
+ continue;
1370
+ }
1371
+ if (c === 96) {
1372
+ if (i > strStart) {
1373
+ out.push({
1374
+ type: "str",
1375
+ value: src.slice(strStart, i),
1376
+ start: strStart,
1377
+ end: i
1378
+ });
1379
+ }
1380
+ return i + 1;
1381
+ }
1382
+ if (c === 36 && src.charCodeAt(i + 1) === 123) {
1383
+ if (i > strStart) {
1384
+ out.push({
1385
+ type: "str",
1386
+ value: src.slice(strStart, i),
1387
+ start: strStart,
1388
+ end: i
1389
+ });
1390
+ }
1391
+ out.push({ type: "punct", value: "${", start: i, end: i + 2 });
1392
+ i += 2;
1393
+ const exprStart = i;
1394
+ let depth = 1;
1395
+ while (i < len && depth > 0) {
1396
+ const cc = src.charCodeAt(i);
1397
+ if (cc === 92) {
1398
+ i += 2;
1399
+ continue;
1400
+ }
1401
+ if (cc === 34 || cc === 39) {
1402
+ const q = cc;
1403
+ i++;
1404
+ while (i < len) {
1405
+ const c2 = src.charCodeAt(i);
1406
+ if (c2 === 92) {
1407
+ i += 2;
1408
+ continue;
1409
+ }
1410
+ if (c2 === q) {
1411
+ i++;
1412
+ break;
1413
+ }
1414
+ i++;
1415
+ }
1416
+ continue;
1417
+ }
1418
+ if (cc === 96) {
1419
+ i = tokenizeTemplate(src, i, out);
1420
+ continue;
1421
+ }
1422
+ if (cc === 123) {
1423
+ depth++;
1424
+ i++;
1425
+ continue;
1426
+ }
1427
+ if (cc === 125) {
1428
+ depth--;
1429
+ if (depth === 0)
1430
+ break;
1431
+ i++;
1432
+ continue;
1433
+ }
1434
+ i++;
1435
+ }
1436
+ const inner = src.slice(exprStart, i);
1437
+ const innerTokens = tokenize(inner);
1438
+ for (const t of innerTokens) {
1439
+ if (t.type === "eof")
1440
+ continue;
1441
+ out.push({ ...t, start: t.start + exprStart, end: t.end + exprStart });
1442
+ }
1443
+ out.push({ type: "punct", value: "}", start: i, end: i + 1 });
1444
+ i++;
1445
+ strStart = i;
1446
+ continue;
1447
+ }
1448
+ i++;
1449
+ }
1450
+ if (i > strStart) {
1451
+ out.push({
1452
+ type: "str",
1453
+ value: src.slice(strStart, i),
1454
+ start: strStart,
1455
+ end: i
1456
+ });
1457
+ }
1458
+ return i;
1459
+ }
1460
+ function analyzeHandler(fn) {
1461
+ let src;
1462
+ try {
1463
+ src = fn.toString();
1464
+ } catch {
1465
+ return makeUnknown();
1466
+ }
1467
+ const tokens = tokenize(src);
1468
+ let i = 0;
1469
+ if (tokens[i]?.type === "ident" && tokens[i].value === "async")
1470
+ i++;
1471
+ if (tokens[i]?.type === "ident" && tokens[i].value === "function") {
1472
+ i++;
1473
+ if (tokens[i]?.type === "ident")
1474
+ i++;
1475
+ }
1476
+ if (tokens[i]?.type === "punct" && tokens[i].value === "(") {
1477
+ i++;
1478
+ const first = tokens[i];
1479
+ if (first?.type === "punct" && first.value === ")") {
1480
+ i++;
1481
+ const body = walkBody(tokens, i, null);
1482
+ return {
1483
+ isNoArg: true,
1484
+ contextProps: new Set,
1485
+ hasDynamicAccess: false,
1486
+ isDestructured: false,
1487
+ destructuredProps: new Set,
1488
+ literal: body.literal,
1489
+ arglessJsonCall: false,
1490
+ paramSerializer: null,
1491
+ paramParts: null
1492
+ };
1493
+ }
1494
+ if (first?.type === "punct" && first.value === "{") {
1495
+ const { names, next } = parseDestructure(tokens, i);
1496
+ const body = walkBody(tokens, next, null);
1497
+ return {
1498
+ isNoArg: false,
1499
+ contextProps: new Set,
1500
+ hasDynamicAccess: false,
1501
+ isDestructured: true,
1502
+ destructuredProps: names,
1503
+ literal: body.literal,
1504
+ arglessJsonCall: false,
1505
+ paramSerializer: body.paramSerializer,
1506
+ paramParts: body.paramParts
1507
+ };
1508
+ }
1509
+ if (first?.type === "ident") {
1510
+ const name = first.value;
1511
+ i++;
1512
+ const body = walkBody(tokens, i, name);
1513
+ return {
1514
+ isNoArg: false,
1515
+ contextProps: body.props,
1516
+ hasDynamicAccess: body.hasDynamic,
1517
+ isDestructured: false,
1518
+ destructuredProps: new Set,
1519
+ literal: body.literal,
1520
+ arglessJsonCall: body.arglessJsonCall,
1521
+ paramSerializer: body.paramSerializer,
1522
+ paramParts: body.paramParts
1523
+ };
1524
+ }
1525
+ return makeUnknown();
1526
+ }
1527
+ if (tokens[i]?.type === "ident") {
1528
+ const name = tokens[i].value;
1529
+ i++;
1530
+ const body = walkBody(tokens, i, name);
1531
+ return {
1532
+ isNoArg: false,
1533
+ contextProps: body.props,
1534
+ hasDynamicAccess: body.hasDynamic,
1535
+ isDestructured: false,
1536
+ destructuredProps: new Set,
1537
+ literal: body.literal,
1538
+ arglessJsonCall: body.arglessJsonCall,
1539
+ paramSerializer: body.paramSerializer,
1540
+ paramParts: body.paramParts
1541
+ };
1542
+ }
1543
+ return makeUnknown();
1544
+ }
1545
+ function parseDestructure(tokens, braceStart) {
1546
+ const names = new Set;
1547
+ let i = braceStart + 1;
1548
+ let depth = 1;
1549
+ while (i < tokens.length) {
1550
+ const t = tokens[i];
1551
+ if (t.type === "eof")
1552
+ break;
1553
+ if (t.type === "punct") {
1554
+ if (t.value === "{")
1555
+ depth++;
1556
+ else if (t.value === "}") {
1557
+ depth--;
1558
+ i++;
1559
+ if (depth === 0)
1560
+ break;
1561
+ continue;
1562
+ } else if (t.value === "[")
1563
+ depth += 100;
1564
+ else if (t.value === "]")
1565
+ depth -= 100;
1566
+ }
1567
+ if (t.type === "ident" && depth === 1) {
1568
+ const prev = tokens[i - 1];
1569
+ const next = tokens[i + 1];
1570
+ if (prev?.type === "punct" && prev.value === ":") {
1571
+ names.add(t.value);
1572
+ } else if (next?.type !== "punct" || next.value !== ":") {
1573
+ names.add(t.value);
1574
+ }
1575
+ }
1576
+ i++;
1577
+ }
1578
+ while (i < tokens.length) {
1579
+ const t = tokens[i];
1580
+ if (t.type === "eof")
1581
+ break;
1582
+ if (t.type === "punct" && t.value === ")") {
1583
+ i++;
1584
+ break;
1585
+ }
1586
+ i++;
1587
+ }
1588
+ return { names, next: i };
1589
+ }
1590
+ function walkBody(tokens, from, paramName) {
1591
+ const props = new Set;
1592
+ let hasDynamic = false;
1593
+ let arglessJsonCall = false;
1594
+ let bodyStart = -1;
1595
+ let i = from;
1596
+ let parenDepth = 0;
1597
+ if (tokens[from]?.type === "punct" && tokens[from].value === "{") {
1598
+ bodyStart = from + 1;
1599
+ } else {
1600
+ while (i < tokens.length) {
1601
+ const t = tokens[i];
1602
+ if (t.type === "eof")
1603
+ break;
1604
+ if (t.type === "punct") {
1605
+ if (t.value === "(" || t.value === "[" || t.value === "{") {
1606
+ parenDepth++;
1607
+ } else if (t.value === ")" || t.value === "]" || t.value === "}") {
1608
+ if (parenDepth > 0)
1609
+ parenDepth--;
1610
+ } else if (t.value === "=>" && parenDepth === 0) {
1611
+ const next = tokens[i + 1];
1612
+ if (next?.type === "punct" && next.value === "{") {
1613
+ bodyStart = i + 2;
1614
+ } else {
1615
+ bodyStart = i + 1;
1616
+ }
1617
+ break;
1618
+ }
1619
+ if (t.value === ")" && parenDepth === 0 && i + 1 < tokens.length) {
1620
+ const next = tokens[i + 1];
1621
+ if (next?.type === "punct" && next.value === "{") {
1622
+ bodyStart = i + 2;
1623
+ break;
1624
+ }
1625
+ }
1626
+ }
1627
+ i++;
1628
+ }
1629
+ }
1630
+ if (bodyStart < 0) {
1631
+ return {
1632
+ props,
1633
+ hasDynamic,
1634
+ literal: null,
1635
+ arglessJsonCall: false,
1636
+ paramSerializer: null,
1637
+ paramParts: null
1638
+ };
1639
+ }
1640
+ if (paramName !== null) {
1641
+ for (let j = bodyStart;j < tokens.length; j++) {
1642
+ const t = tokens[j];
1643
+ if (t.type === "eof")
1644
+ break;
1645
+ if (t.type !== "ident" || t.value !== paramName)
1646
+ continue;
1647
+ const n = tokens[j + 1];
1648
+ if (!n)
1649
+ continue;
1650
+ if (n.type === "punct" && (n.value === "." || n.value === "?.")) {
1651
+ const key = tokens[j + 2];
1652
+ if (key?.type === "ident") {
1653
+ props.add(key.value);
1654
+ if (key.value === "json") {
1655
+ const pOpen = tokens[j + 3];
1656
+ const pClose = tokens[j + 4];
1657
+ if (pOpen?.type === "punct" && pOpen.value === "(" && pClose?.type === "punct" && pClose.value === ")") {
1658
+ const prev1 = tokens[j - 1];
1659
+ const prev2 = tokens[j - 2];
1660
+ const isPrecededByReturn = prev1?.type === "punct" && prev1.value === "=>" || prev1?.type === "ident" && prev1.value === "return" || prev1?.type === "ident" && prev1.value === "await" && (prev2?.type === "punct" && prev2.value === "=>" || prev2?.type === "ident" && prev2.value === "return");
1661
+ const next1 = tokens[j + 5];
1662
+ const next2 = tokens[j + 6];
1663
+ const isEndOfBody = isBodyEnd(next1) && (next1?.value !== ";" || isBodyEnd(next2));
1664
+ if (isPrecededByReturn && isEndOfBody) {
1665
+ arglessJsonCall = true;
1666
+ }
1667
+ }
1668
+ }
1669
+ j += 2;
1670
+ continue;
1671
+ }
1672
+ hasDynamic = true;
1673
+ continue;
1674
+ }
1675
+ if (n.type === "punct" && n.value === "[") {
1676
+ const key = tokens[j + 2];
1677
+ const close = tokens[j + 3];
1678
+ if (key?.type === "str" && close?.type === "punct" && close.value === "]") {
1679
+ props.add(key.value);
1680
+ j += 3;
1681
+ continue;
1682
+ }
1683
+ hasDynamic = true;
1684
+ continue;
1685
+ }
1686
+ const prev = tokens[j - 1];
1687
+ if (prev?.type === "punct" && prev.value === "...") {
1688
+ hasDynamic = true;
1689
+ }
1690
+ }
1691
+ }
1692
+ const literal = tryExtractLiteral(tokens, bodyStart);
1693
+ const paramExtraction = literal === null ? tryExtractParamSerializer(tokens, bodyStart, paramName) : null;
1694
+ const paramSerializer = paramExtraction?.serializer ?? null;
1695
+ const paramParts = paramExtraction?.parts ?? null;
1696
+ return {
1697
+ props,
1698
+ hasDynamic,
1699
+ literal,
1700
+ arglessJsonCall,
1701
+ paramSerializer,
1702
+ paramParts
1703
+ };
1704
+ }
1705
+ function isBodyEnd(t) {
1706
+ if (!t)
1707
+ return true;
1708
+ if (t.type === "eof")
1709
+ return true;
1710
+ if (t.type === "punct" && (t.value === ";" || t.value === "}"))
1711
+ return true;
1712
+ return false;
1713
+ }
1714
+ function tryExtractLiteral(tokens, bodyStart) {
1715
+ const t = tokens[bodyStart];
1716
+ if (!t || t.type === "eof")
1717
+ return null;
1718
+ if (t.type === "ident" && t.value === "return") {
1719
+ return tryExtractLiteral(tokens, bodyStart + 1);
1720
+ }
1721
+ if (t.type === "str") {
1722
+ if (isBodyEnd(tokens[bodyStart + 1])) {
1723
+ return { kind: "string", value: t.value };
1724
+ }
1725
+ return null;
1726
+ }
1727
+ if (t.type === "punct" && t.value === "(") {
1728
+ const inner = tokens[bodyStart + 1];
1729
+ if (inner?.type === "punct" && inner.value === "{") {
1730
+ const obj = extractFlatObject(tokens, bodyStart + 1);
1731
+ if (!obj.ok)
1732
+ return null;
1733
+ const afterBrace = tokens[obj.end];
1734
+ if (afterBrace?.type !== "punct" || afterBrace.value !== ")")
1735
+ return null;
1736
+ if (!isBodyEnd(tokens[obj.end + 1]))
1737
+ return null;
1738
+ return { kind: "json", value: JSON.stringify(obj.value) };
1739
+ }
1740
+ return null;
1741
+ }
1742
+ if (t.type === "punct" && t.value === "{") {
1743
+ const next = tokens[bodyStart + 1];
1744
+ if (next && (next.type === "ident" || next.type === "str" || next.type === "num") && tokens[bodyStart + 2]?.type === "punct" && tokens[bodyStart + 2].value === ":") {
1745
+ const obj = extractFlatObject(tokens, bodyStart);
1746
+ if (obj.ok) {
1747
+ if (isBodyEnd(tokens[obj.end])) {
1748
+ return { kind: "json", value: JSON.stringify(obj.value) };
1749
+ }
1750
+ return null;
1751
+ }
1752
+ return null;
1753
+ }
1754
+ let j = bodyStart + 1;
1755
+ while (j < tokens.length) {
1756
+ const tt = tokens[j];
1757
+ if (tt.type === "eof")
1758
+ return null;
1759
+ if (tt.type === "punct" && tt.value === "}")
1760
+ return null;
1761
+ if (tt.type === "ident" && tt.value === "return") {
1762
+ return tryExtractLiteral(tokens, j + 1);
1763
+ }
1764
+ if (tt.type === "punct" && tt.value === ";")
1765
+ return null;
1766
+ if (tt.type === "ident" && tt.value !== "return")
1767
+ return null;
1768
+ j++;
1769
+ }
1770
+ return null;
1771
+ }
1772
+ return null;
1773
+ }
1774
+ function extractFlatObject(tokens, braceStart) {
1775
+ let i = braceStart + 1;
1776
+ const obj = {};
1777
+ let expectKey = true;
1778
+ let key = null;
1779
+ while (i < tokens.length) {
1780
+ const t = tokens[i];
1781
+ if (t.type === "eof")
1782
+ return { ok: false };
1783
+ if (t.type === "punct" && t.value === "}") {
1784
+ if (!expectKey)
1785
+ return { ok: false };
1786
+ return { ok: true, end: i + 1, value: obj };
1787
+ }
1788
+ if (expectKey) {
1789
+ if (t.type === "ident" || t.type === "str" || t.type === "num")
1790
+ key = t.value;
1791
+ else
1792
+ return { ok: false };
1793
+ i++;
1794
+ const colon = tokens[i];
1795
+ if (colon?.type !== "punct" || colon.value !== ":")
1796
+ return { ok: false };
1797
+ i++;
1798
+ expectKey = false;
1799
+ continue;
1800
+ }
1801
+ if (t.type === "str") {
1802
+ obj[key] = t.value;
1803
+ i++;
1804
+ } else if (t.type === "num") {
1805
+ obj[key] = Number(t.value);
1806
+ i++;
1807
+ } else if (t.type === "ident") {
1808
+ if (t.value === "true")
1809
+ obj[key] = true;
1810
+ else if (t.value === "false")
1811
+ obj[key] = false;
1812
+ else if (t.value === "null")
1813
+ obj[key] = null;
1814
+ else
1815
+ return { ok: false };
1816
+ i++;
1817
+ } else if (t.type === "punct" && t.value === "!" && tokens[i + 1]?.type === "num") {
1818
+ const n = tokens[i + 1].value;
1819
+ obj[key] = n === "1";
1820
+ i += 2;
1821
+ } else if (t.type === "punct" && t.value === "-" && tokens[i + 1]?.type === "num") {
1822
+ obj[key] = -Number(tokens[i + 1].value);
1823
+ i += 2;
1824
+ } else {
1825
+ return { ok: false };
1826
+ }
1827
+ const sep = tokens[i];
1828
+ if (sep?.type === "punct" && sep.value === ",") {
1829
+ i++;
1830
+ expectKey = true;
1831
+ continue;
1832
+ }
1833
+ if (sep?.type === "punct" && sep.value === "}") {
1834
+ return { ok: true, end: i + 1, value: obj };
1835
+ }
1836
+ return { ok: false };
1837
+ }
1838
+ return { ok: false };
1839
+ }
1840
+ function extractParamObject(tokens, braceStart, paramName) {
1841
+ let i = braceStart + 1;
1842
+ const parts = [];
1843
+ let expectKey = true;
1844
+ let key = null;
1845
+ let hasParam = false;
1846
+ while (i < tokens.length) {
1847
+ const t = tokens[i];
1848
+ if (t.type === "eof")
1849
+ return { ok: false };
1850
+ if (t.type === "punct" && t.value === "}") {
1851
+ if (!expectKey)
1852
+ return { ok: false };
1853
+ return hasParam ? { ok: true, end: i + 1, parts } : { ok: false };
1854
+ }
1855
+ if (expectKey) {
1856
+ if (t.type === "ident" || t.type === "str" || t.type === "num") {
1857
+ key = t.value;
1858
+ } else {
1859
+ return { ok: false };
1860
+ }
1861
+ i++;
1862
+ const colon = tokens[i];
1863
+ if (colon?.type !== "punct" || colon.value !== ":")
1864
+ return { ok: false };
1865
+ i++;
1866
+ expectKey = false;
1867
+ continue;
1868
+ }
1869
+ if (paramName !== null && t.type === "ident" && t.value === paramName) {
1870
+ const dot1 = tokens[i + 1];
1871
+ const pIdent = tokens[i + 2];
1872
+ const dot2 = tokens[i + 3];
1873
+ const pKey = tokens[i + 4];
1874
+ if (dot1?.type === "punct" && (dot1.value === "." || dot1.value === "?.") && pIdent?.type === "ident" && pIdent.value === "params" && dot2?.type === "punct" && (dot2.value === "." || dot2.value === "?.") && pKey?.type === "ident") {
1875
+ hasParam = true;
1876
+ parts.push({ key, isParam: true, paramKey: pKey.value });
1877
+ i += 5;
1878
+ const sep = tokens[i];
1879
+ if (sep?.type === "punct" && sep.value === ",") {
1880
+ i++;
1881
+ expectKey = true;
1882
+ continue;
1883
+ }
1884
+ if (sep?.type === "punct" && sep.value === "}") {
1885
+ return { ok: true, end: i + 1, parts };
1886
+ }
1887
+ return { ok: false };
1888
+ }
1889
+ }
1890
+ if (t.type === "ident" && t.value === "params") {
1891
+ const dot = tokens[i + 1];
1892
+ const pKey = tokens[i + 2];
1893
+ if (dot?.type === "punct" && (dot.value === "." || dot.value === "?.") && pKey?.type === "ident") {
1894
+ hasParam = true;
1895
+ parts.push({ key, isParam: true, paramKey: pKey.value });
1896
+ i += 3;
1897
+ const sep = tokens[i];
1898
+ if (sep?.type === "punct" && sep.value === ",") {
1899
+ i++;
1900
+ expectKey = true;
1901
+ continue;
1902
+ }
1903
+ if (sep?.type === "punct" && sep.value === "}") {
1904
+ return { ok: true, end: i + 1, parts };
1905
+ }
1906
+ return { ok: false };
1907
+ }
1908
+ }
1909
+ if (t.type === "str") {
1910
+ parts.push({
1911
+ key,
1912
+ isParam: false,
1913
+ literalValue: JSON.stringify(t.value)
1914
+ });
1915
+ i++;
1916
+ } else if (t.type === "num") {
1917
+ parts.push({
1918
+ key,
1919
+ isParam: false,
1920
+ literalValue: t.value
1921
+ });
1922
+ i++;
1923
+ } else if (t.type === "ident") {
1924
+ if (t.value === "true" || t.value === "false" || t.value === "null") {
1925
+ parts.push({
1926
+ key,
1927
+ isParam: false,
1928
+ literalValue: t.value
1929
+ });
1930
+ i++;
1931
+ } else {
1932
+ return { ok: false };
1933
+ }
1934
+ } else if (t.type === "punct" && t.value === "!" && tokens[i + 1]?.type === "num") {
1935
+ parts.push({
1936
+ key,
1937
+ isParam: false,
1938
+ literalValue: tokens[i + 1].value === "1" ? "true" : "false"
1939
+ });
1940
+ i += 2;
1941
+ } else if (t.type === "punct" && t.value === "-" && tokens[i + 1]?.type === "num") {
1942
+ parts.push({
1943
+ key,
1944
+ isParam: false,
1945
+ literalValue: `-${tokens[i + 1].value}`
1946
+ });
1947
+ i += 2;
1948
+ } else {
1949
+ return { ok: false };
1950
+ }
1951
+ const sep = tokens[i];
1952
+ if (sep?.type === "punct" && sep.value === ",") {
1953
+ i++;
1954
+ expectKey = true;
1955
+ continue;
1956
+ }
1957
+ if (sep?.type === "punct" && sep.value === "}") {
1958
+ return hasParam ? { ok: true, end: i + 1, parts } : { ok: false };
1959
+ }
1960
+ return { ok: false };
1961
+ }
1962
+ return { ok: false };
1963
+ }
1964
+ function buildParamSerializer(parts) {
1965
+ const chunks = [];
1966
+ const keys = [];
1967
+ let current = "{";
1968
+ for (let i = 0;i < parts.length; i++) {
1969
+ const part = parts[i];
1970
+ if (i > 0)
1971
+ current += ",";
1972
+ current += `${JSON.stringify(part.key)}:`;
1973
+ if (part.isParam) {
1974
+ current += '"';
1975
+ chunks.push(current);
1976
+ keys.push(part.paramKey);
1977
+ current = '"';
1978
+ } else {
1979
+ current += part.literalValue;
1980
+ }
1981
+ }
1982
+ current += "}";
1983
+ chunks.push(current);
1984
+ if (keys.length === 1) {
1985
+ const c0 = chunks[0];
1986
+ const c1 = chunks[1];
1987
+ const k0 = keys[0];
1988
+ return (p) => c0 + escapeJsonString(typeof p === "string" ? p : p[k0] ?? "") + c1;
1989
+ }
1990
+ if (keys.length === 2) {
1991
+ const c0 = chunks[0];
1992
+ const c1 = chunks[1];
1993
+ const c2 = chunks[2];
1994
+ const k0 = keys[0];
1995
+ const k1 = keys[1];
1996
+ return (p) => `${c0}${escapeJsonString(typeof p === "string" ? p : p[k0] ?? "")}${c1}${typeof p === "string" ? "" : escapeJsonString(p[k1] ?? "")}${c2}`;
1997
+ }
1998
+ return (p) => {
1999
+ let out = chunks[0];
2000
+ for (let j = 0;j < keys.length; j++) {
2001
+ out += escapeJsonString(typeof p === "string" ? j === 0 ? p : "" : p[keys[j]] ?? "") + chunks[j + 1];
2002
+ }
2003
+ return out;
2004
+ };
2005
+ }
2006
+ function tryExtractParamSerializer(tokens, bodyStart, paramName) {
2007
+ const t = tokens[bodyStart];
2008
+ if (!t || t.type === "eof")
2009
+ return null;
2010
+ if (t.type === "punct" && t.value === "(") {
2011
+ const inner = tokens[bodyStart + 1];
2012
+ if (inner?.type === "punct" && inner.value === "{") {
2013
+ const res = extractParamObject(tokens, bodyStart + 1, paramName);
2014
+ if (!res.ok)
2015
+ return null;
2016
+ const afterBrace = tokens[res.end];
2017
+ if (afterBrace?.type !== "punct" || afterBrace.value !== ")")
2018
+ return null;
2019
+ if (!isBodyEnd(tokens[res.end + 1]))
2020
+ return null;
2021
+ return { serializer: buildParamSerializer(res.parts), parts: res.parts };
2022
+ }
2023
+ return null;
2024
+ }
2025
+ if (t.type === "punct" && t.value === "{") {
2026
+ const next = tokens[bodyStart + 1];
2027
+ if (next && (next.type === "ident" || next.type === "str" || next.type === "num") && tokens[bodyStart + 2]?.type === "punct" && tokens[bodyStart + 2].value === ":") {
2028
+ const res = extractParamObject(tokens, bodyStart, paramName);
2029
+ if (res.ok && isBodyEnd(tokens[res.end])) {
2030
+ return {
2031
+ serializer: buildParamSerializer(res.parts),
2032
+ parts: res.parts
2033
+ };
2034
+ }
2035
+ return null;
2036
+ }
2037
+ let j = bodyStart + 1;
2038
+ while (j < tokens.length) {
2039
+ const tt = tokens[j];
2040
+ if (tt.type === "eof")
2041
+ return null;
2042
+ if (tt.type === "punct" && tt.value === "}")
2043
+ return null;
2044
+ if (tt.type === "ident" && tt.value === "return") {
2045
+ return tryExtractParamSerializer(tokens, j + 1, paramName);
2046
+ }
2047
+ if (tt.type === "punct" && tt.value === ";")
2048
+ return null;
2049
+ if (tt.type === "ident" && tt.value !== "return")
2050
+ return null;
2051
+ j++;
2052
+ }
2053
+ return null;
2054
+ }
2055
+ return null;
2056
+ }
2057
+ function makeUnknown() {
2058
+ return {
2059
+ isNoArg: false,
2060
+ contextProps: new Set,
2061
+ hasDynamicAccess: true,
2062
+ isDestructured: false,
2063
+ destructuredProps: new Set,
2064
+ literal: null,
2065
+ arglessJsonCall: false,
2066
+ paramSerializer: null,
2067
+ paramParts: null
2068
+ };
2069
+ }
2070
+
2071
+ // src/internal/shutdown.ts
2072
+ async function stopServer(server, hardTimeoutMs) {
2073
+ let timer;
2074
+ let forced = false;
2075
+ let stopPromise = null;
2076
+ try {
2077
+ stopPromise = Promise.resolve(server.stop()).then(() => {});
2078
+ await Promise.race([
2079
+ stopPromise,
2080
+ new Promise((resolve) => {
2081
+ timer = setTimeout(() => {
2082
+ forced = true;
2083
+ stopPromise = Promise.resolve(server.stop(true)).then(() => {});
2084
+ resolve();
2085
+ }, hardTimeoutMs);
2086
+ timer?.unref?.();
2087
+ })
2088
+ ]);
2089
+ } finally {
2090
+ if (timer !== undefined) {
2091
+ clearTimeout(timer);
2092
+ }
2093
+ }
2094
+ await stopPromise;
2095
+ return {
2096
+ forced,
2097
+ pending: 0
2098
+ };
2099
+ }
2100
+
2101
+ // src/internal/trie.ts
2102
+ var MATCH_HANDLER = Symbol("barq.match.handler");
2103
+ var MATCH_NOT_ALLOWED = Symbol("barq.match.not-allowed");
2104
+ var METHOD_BITS = {
2105
+ GET: 1 << 0,
2106
+ POST: 1 << 1,
2107
+ PUT: 1 << 2,
2108
+ DELETE: 1 << 3,
2109
+ PATCH: 1 << 4,
2110
+ HEAD: 1 << 5,
2111
+ OPTIONS: 1 << 6
2112
+ };
2113
+ var STATIC_CHILD_SCAN_THRESHOLD = 4;
2114
+ function methodBit(method) {
2115
+ return METHOD_BITS[method] ?? 0;
2116
+ }
2117
+ function createNode() {
2118
+ return {
2119
+ staticChildren: null,
2120
+ staticChildKeys: [],
2121
+ staticChildNodes: [],
2122
+ paramChildren: null,
2123
+ paramChild: null,
2124
+ paramName: null,
2125
+ wildcardChild: null,
2126
+ wildcardName: null,
2127
+ handlers: null,
2128
+ allow: null,
2129
+ notAllowed: null
2130
+ };
2131
+ }
2132
+ function cloneNode(node) {
2133
+ const staticChildren = node.staticChildren ? new Map(Array.from(node.staticChildren, ([key, child]) => [
2134
+ key,
2135
+ cloneNode(child)
2136
+ ])) : null;
2137
+ const staticChildKeys = node.staticChildKeys.slice();
2138
+ const staticChildNodes = staticChildren ? staticChildKeys.map((key) => staticChildren.get(key)) : [];
2139
+ const paramChildren = node.paramChildren ? new Map(Array.from(node.paramChildren, ([name, child]) => [
2140
+ name,
2141
+ cloneNode(child)
2142
+ ])) : null;
2143
+ let handlers = null;
2144
+ if (node.handlers !== null) {
2145
+ handlers = Object.assign(Object.create(null), node.handlers);
2146
+ }
2147
+ return {
2148
+ staticChildren,
2149
+ staticChildKeys,
2150
+ staticChildNodes,
2151
+ paramChildren,
2152
+ paramChild: node.paramChild ? cloneNode(node.paramChild) : null,
2153
+ paramName: node.paramName,
2154
+ wildcardChild: node.wildcardChild ? cloneNode(node.wildcardChild) : null,
2155
+ wildcardName: node.wildcardName,
2156
+ handlers,
2157
+ allow: node.allow,
2158
+ notAllowed: node.notAllowed
2159
+ };
2160
+ }
2161
+ var MAX_OPTIONAL_PARAMS = 8;
2162
+ function parsePattern(pattern) {
2163
+ if (pattern.length === 0 || pattern.charCodeAt(0) !== 47) {
2164
+ throw new Error(`Invalid route pattern "${pattern}": must start with /`);
2165
+ }
2166
+ if (pattern.indexOf("#") !== -1) {
2167
+ throw new Error(`Invalid route pattern "${pattern}": must not contain #`);
2168
+ }
2169
+ let p = pattern;
2170
+ if (p.length > 1 && p.charCodeAt(p.length - 1) === 47) {
2171
+ p = p.slice(0, -1);
2172
+ }
2173
+ const segments = [];
2174
+ const names = new Set;
2175
+ let i = 1;
2176
+ while (i < p.length) {
2177
+ const slash = p.indexOf("/", i);
2178
+ const end = slash === -1 ? p.length : slash;
2179
+ const seg = p.slice(i, end);
2180
+ if (seg.length === 0) {
2181
+ throw new Error(`Invalid route pattern "${pattern}": empty segment (//)`);
2182
+ }
2183
+ const c0 = seg.charCodeAt(0);
2184
+ if (seg.includes("?") && !(c0 === 58 && seg.endsWith("?") && seg.indexOf("?") === seg.length - 1)) {
2185
+ throw new Error(`Invalid route pattern "${pattern}": malformed optional parameter`);
2186
+ }
2187
+ if (c0 === 58) {
2188
+ const optional = seg.endsWith("?");
2189
+ const name = optional ? seg.slice(1, -1) : seg.slice(1);
2190
+ if (name.length === 0) {
2191
+ throw new Error(`Invalid route pattern "${pattern}": empty parameter name in segment ":${name}"`);
2192
+ }
2193
+ if (names.has(name)) {
2194
+ throw new Error(`Invalid route pattern "${pattern}": duplicate parameter name "${name}"`);
2195
+ }
2196
+ names.add(name);
2197
+ if (name.includes("?")) {
2198
+ throw new Error(`Invalid route pattern "${pattern}": malformed optional parameter`);
2199
+ }
2200
+ segments.push(optional ? { kind: "param", name, optional: true } : { kind: "param", name });
2201
+ } else if (c0 === 42) {
2202
+ if (end !== p.length) {
2203
+ throw new Error(`Invalid route pattern "${pattern}": wildcard * must be the final segment`);
2204
+ }
2205
+ const name = seg.length > 1 ? seg.slice(1) : null;
2206
+ if (name !== null) {
2207
+ if (names.has(name)) {
2208
+ throw new Error(`Invalid route pattern "${pattern}": duplicate parameter name "${name}"`);
2209
+ }
2210
+ names.add(name);
2211
+ }
2212
+ segments.push({ kind: "wildcard", name });
2213
+ } else {
2214
+ segments.push({ kind: "static", value: seg });
2215
+ }
2216
+ i = end + 1;
2217
+ }
2218
+ const optionalCount = segments.reduce((count, segment) => count + (segment.kind === "param" && segment.optional ? 1 : 0), 0);
2219
+ if (optionalCount > MAX_OPTIONAL_PARAMS) {
2220
+ throw new RangeError(`Route pattern exceeds the limit of ${MAX_OPTIONAL_PARAMS} optional parameters`);
2221
+ }
2222
+ return segments;
2223
+ }
2224
+ function _segmentEquals(path, start, end, key) {
2225
+ const n = end - start;
2226
+ if (key.length !== n)
2227
+ return false;
2228
+ for (let i = 0;i < n; i++) {
2229
+ if (path.charCodeAt(start + i) !== key.charCodeAt(i))
2230
+ return false;
2231
+ }
2232
+ return true;
2233
+ }
2234
+ function decodeParam(raw) {
2235
+ if (raw.indexOf("%") === -1)
2236
+ return raw;
2237
+ try {
2238
+ return decodeURIComponent(raw);
2239
+ } catch {
2240
+ throw new HttpError(400, { error: "Bad Request" });
2241
+ }
2242
+ }
2243
+ function matchNode(rootNode, pathname, startI, method, paramNames, paramValues, startDepth) {
2244
+ let node = rootNode;
2245
+ let i = startI;
2246
+ const depth = startDepth;
2247
+ while (true) {
2248
+ const len = pathname.length;
2249
+ if (i >= len) {
2250
+ const handlers = node.handlers;
2251
+ if (handlers === null)
2252
+ return null;
2253
+ let handler = handlers[method];
2254
+ if (handler === undefined && method === "HEAD") {
2255
+ handler = handlers.GET;
2256
+ }
2257
+ if (handler === undefined) {
2258
+ return node.notAllowed;
2259
+ }
2260
+ if (depth === 0)
2261
+ return handler;
2262
+ const p = Object.create(null);
2263
+ p[MATCH_HANDLER] = handler;
2264
+ for (let k = 0;k < depth; k++) {
2265
+ p[paramNames[k]] = paramValues[k];
2266
+ }
2267
+ return p;
2268
+ }
2269
+ const slash = pathname.indexOf("/", i);
2270
+ const segEnd = slash === -1 ? len : slash;
2271
+ if (segEnd === i) {
2272
+ if (slash === len - 1) {
2273
+ return matchNode(node, pathname, len, method, paramNames, paramValues, depth);
2274
+ }
2275
+ return null;
2276
+ }
2277
+ const nextI = slash === -1 ? len : slash + 1;
2278
+ let notAllowedCandidate = null;
2279
+ const staticChildren = node.staticChildren;
2280
+ if (staticChildren !== null) {
2281
+ let child;
2282
+ if (staticChildren.size <= STATIC_CHILD_SCAN_THRESHOLD) {
2283
+ const keys = node.staticChildKeys;
2284
+ const nodes = node.staticChildNodes;
2285
+ for (let childIndex = 0;childIndex < keys.length; childIndex++) {
2286
+ if (_segmentEquals(pathname, i, segEnd, keys[childIndex])) {
2287
+ child = nodes[childIndex];
2288
+ break;
2289
+ }
2290
+ }
2291
+ } else {
2292
+ child = staticChildren.get(pathname.slice(i, segEnd));
2293
+ }
2294
+ if (child !== undefined) {
2295
+ const hasParamChildren = node.paramChild !== null || node.paramChildren !== null && node.paramChildren.size > 0;
2296
+ if (!hasParamChildren && node.wildcardChild === null) {
2297
+ node = child;
2298
+ i = nextI;
2299
+ continue;
2300
+ }
2301
+ const res = matchNode(child, pathname, nextI, method, paramNames, paramValues, depth);
2302
+ if (res !== null) {
2303
+ if (MATCH_NOT_ALLOWED in res) {
2304
+ notAllowedCandidate = res;
2305
+ } else {
2306
+ return res;
2307
+ }
2308
+ }
2309
+ }
2310
+ }
2311
+ if (node.paramChild !== null && node.paramName !== null) {
2312
+ const child = node.paramChild;
2313
+ const paramName = node.paramName;
2314
+ if (nextI >= len && child.handlers !== null) {
2315
+ let leafH = child.handlers[method];
2316
+ if (leafH === undefined && method === "HEAD")
2317
+ leafH = child.handlers.GET;
2318
+ if (leafH !== undefined) {
2319
+ const paramVal = pathname.indexOf("%", i) !== -1 ? decodeParam(pathname.slice(i, segEnd)) : pathname.slice(i, segEnd);
2320
+ const p = {
2321
+ [paramName]: paramVal,
2322
+ [MATCH_HANDLER]: leafH
2323
+ };
2324
+ if (depth === 0)
2325
+ return p;
2326
+ for (let k = 0;k < depth; k++) {
2327
+ p[paramNames[k]] = paramValues[k];
2328
+ }
2329
+ return p;
2330
+ }
2331
+ }
2332
+ paramNames[depth] = paramName;
2333
+ paramValues[depth] = decodeParam(pathname.slice(i, segEnd));
2334
+ const res = matchNode(child, pathname, nextI, method, paramNames, paramValues, depth + 1);
2335
+ if (res !== null) {
2336
+ if (MATCH_NOT_ALLOWED in res) {
2337
+ notAllowedCandidate ??= res;
2338
+ } else {
2339
+ return res;
2340
+ }
2341
+ }
2342
+ } else if (node.paramChildren !== null && node.paramChildren.size > 0) {
2343
+ for (const [paramName, child] of node.paramChildren) {
2344
+ if (nextI >= len && child.handlers !== null) {
2345
+ let leafH = child.handlers[method];
2346
+ if (leafH === undefined && method === "HEAD")
2347
+ leafH = child.handlers.GET;
2348
+ if (leafH !== undefined) {
2349
+ const paramVal = pathname.indexOf("%", i) !== -1 ? decodeParam(pathname.slice(i, segEnd)) : pathname.slice(i, segEnd);
2350
+ const p = {
2351
+ [paramName]: paramVal,
2352
+ [MATCH_HANDLER]: leafH
2353
+ };
2354
+ if (depth === 0)
2355
+ return p;
2356
+ for (let k = 0;k < depth; k++) {
2357
+ p[paramNames[k]] = paramValues[k];
2358
+ }
2359
+ return p;
2360
+ }
2361
+ }
2362
+ paramNames[depth] = paramName;
2363
+ paramValues[depth] = decodeParam(pathname.slice(i, segEnd));
2364
+ const res = matchNode(child, pathname, nextI, method, paramNames, paramValues, depth + 1);
2365
+ if (res !== null) {
2366
+ if (MATCH_NOT_ALLOWED in res) {
2367
+ notAllowedCandidate ??= res;
2368
+ } else {
2369
+ return res;
2370
+ }
2371
+ }
2372
+ }
2373
+ }
2374
+ if (node.wildcardChild !== null) {
2375
+ let wildcardDepth = depth;
2376
+ if (node.wildcardName !== null) {
2377
+ let rest = pathname.slice(i);
2378
+ if (rest.length > 1 && rest.charCodeAt(rest.length - 1) === 47) {
2379
+ rest = rest.slice(0, -1);
2380
+ }
2381
+ paramNames[wildcardDepth] = node.wildcardName;
2382
+ paramValues[wildcardDepth] = decodeParam(rest);
2383
+ wildcardDepth++;
2384
+ }
2385
+ const handlers = node.wildcardChild.handlers;
2386
+ if (handlers !== null) {
2387
+ let handler = handlers[method];
2388
+ if (handler === undefined && method === "HEAD") {
2389
+ handler = handlers.GET;
2390
+ }
2391
+ if (handler === undefined) {
2392
+ return node.wildcardChild.notAllowed;
2393
+ }
2394
+ if (wildcardDepth === 0)
2395
+ return handler;
2396
+ const p = Object.create(null);
2397
+ for (let k = 0;k < wildcardDepth; k++) {
2398
+ p[paramNames[k]] = paramValues[k];
2399
+ }
2400
+ p[MATCH_HANDLER] = handler;
2401
+ return p;
2402
+ }
2403
+ }
2404
+ return notAllowedCandidate;
2405
+ }
2406
+ }
2407
+
2408
+ class SegmentTrie {
2409
+ root = createNode();
2410
+ staticRoutes = new Map;
2411
+ staticNotAllowed = new Map;
2412
+ maxStaticLength = 0;
2413
+ paramNameBuffer = [];
2414
+ paramValueBuffer = [];
2415
+ addBatch(routes) {
2416
+ if (routes.length === 0)
2417
+ return;
2418
+ if (routes.length === 1) {
2419
+ const route = routes[0];
2420
+ this.add(route.method, route.pattern, route.handler);
2421
+ return;
2422
+ }
2423
+ const staged = this.clone();
2424
+ const parsedPatterns = new Map;
2425
+ for (const route of routes) {
2426
+ let segments = parsedPatterns.get(route.pattern);
2427
+ if (segments === undefined) {
2428
+ segments = parsePattern(route.pattern);
2429
+ parsedPatterns.set(route.pattern, segments);
2430
+ }
2431
+ staged.addWithSegments(route.method, route.pattern, segments, route.handler);
2432
+ }
2433
+ this.root = staged.root;
2434
+ this.staticRoutes = staged.staticRoutes;
2435
+ this.staticNotAllowed = staged.staticNotAllowed;
2436
+ this.maxStaticLength = staged.maxStaticLength;
2437
+ }
2438
+ clone() {
2439
+ const copy = new SegmentTrie;
2440
+ copy.root = cloneNode(this.root);
2441
+ copy.staticRoutes = new Map(Array.from(this.staticRoutes, ([path, handlers]) => [
2442
+ path,
2443
+ Object.assign(Object.create(null), handlers)
2444
+ ]));
2445
+ copy.staticNotAllowed = new Map(this.staticNotAllowed);
2446
+ copy.maxStaticLength = this.maxStaticLength;
2447
+ return copy;
2448
+ }
2449
+ add(method, pattern, handler) {
2450
+ const segments = parsePattern(pattern);
2451
+ let optionalCount = 0;
2452
+ for (const segment of segments) {
2453
+ if (segment.kind === "param" && segment.optional)
2454
+ optionalCount++;
2455
+ }
2456
+ if (optionalCount === 0) {
2457
+ this.addParsed(method, pattern, segments, handler, false);
2458
+ return;
2459
+ }
2460
+ const staged = this.clone();
2461
+ staged.addWithSegments(method, pattern, segments, handler);
2462
+ this.root = staged.root;
2463
+ this.staticRoutes = staged.staticRoutes;
2464
+ this.staticNotAllowed = staged.staticNotAllowed;
2465
+ }
2466
+ addWithSegments(method, pattern, segments, handler) {
2467
+ let optionalCount = 0;
2468
+ for (const segment of segments) {
2469
+ if (segment.kind === "param" && segment.optional)
2470
+ optionalCount++;
2471
+ }
2472
+ if (optionalCount === 0) {
2473
+ this.addParsed(method, pattern, segments, handler, false);
2474
+ return;
2475
+ }
2476
+ const selected = [];
2477
+ const addVariants = (index) => {
2478
+ if (index === segments.length) {
2479
+ const variant = selected.length === 0 ? "/" : `/${selected.map((segment) => segment.kind === "static" ? segment.value : segment.kind === "param" ? `:${segment.name}` : `*${segment.name ?? ""}`).join("/")}`;
2480
+ this.addParsed(method, variant, selected, handler, true);
2481
+ return;
2482
+ }
2483
+ const segment = segments[index];
2484
+ if (segment.kind === "param" && segment.optional) {
2485
+ selected.push({ kind: "param", name: segment.name });
2486
+ addVariants(index + 1);
2487
+ selected.pop();
2488
+ addVariants(index + 1);
2489
+ return;
2490
+ }
2491
+ selected.push(segment);
2492
+ addVariants(index + 1);
2493
+ selected.pop();
2494
+ };
2495
+ addVariants(0);
2496
+ }
2497
+ addParsed(method, pattern, segments, handler, _allowConflictingParamNames) {
2498
+ const bit = methodBit(method);
2499
+ if (bit === 0) {
2500
+ throw new Error(`Unsupported HTTP method "${method}" for route "${pattern}"`);
2501
+ }
2502
+ const isPureStatic = segments.every((s) => s.kind === "static");
2503
+ let cleanPattern;
2504
+ if (isPureStatic) {
2505
+ cleanPattern = pattern.length > 1 && pattern.charCodeAt(pattern.length - 1) === 47 ? pattern.slice(0, -1) : pattern;
2506
+ if (cleanPattern.length > this.maxStaticLength) {
2507
+ this.maxStaticLength = cleanPattern.length;
2508
+ }
2509
+ }
2510
+ let node = this.root;
2511
+ for (const seg of segments) {
2512
+ if (seg.kind === "static") {
2513
+ if (node.staticChildren === null) {
2514
+ node.staticChildren = new Map;
2515
+ }
2516
+ let child = node.staticChildren.get(seg.value);
2517
+ if (child === undefined) {
2518
+ child = createNode();
2519
+ node.staticChildren.set(seg.value, child);
2520
+ node.staticChildKeys.push(seg.value);
2521
+ node.staticChildNodes.push(child);
2522
+ }
2523
+ node = child;
2524
+ } else if (seg.kind === "param") {
2525
+ if (node.wildcardChild !== null) {
2526
+ throw new Error(`Ambiguous routes: wildcard "${node.wildcardName ?? "*"}" and param ":${seg.name}" compete at the same position in "${pattern}"`);
2527
+ }
2528
+ if (node.paramChildren === null) {
2529
+ node.paramChildren = new Map;
2530
+ }
2531
+ let child = node.paramChildren.get(seg.name);
2532
+ if (child === undefined) {
2533
+ child = createNode();
2534
+ node.paramChildren.set(seg.name, child);
2535
+ if (node.paramChild === null && node.paramChildren.size === 1) {
2536
+ node.paramChild = child;
2537
+ node.paramName = seg.name;
2538
+ } else {
2539
+ node.paramChild = null;
2540
+ node.paramName = null;
2541
+ }
2542
+ }
2543
+ node = child;
2544
+ } else {
2545
+ if (node.wildcardChild !== null) {
2546
+ if (node.wildcardName !== seg.name) {
2547
+ throw new Error(`Conflicting wildcards at the same position: "*${node.wildcardName ?? ""}" vs "*${seg.name ?? ""}" (route "${pattern}")`);
2548
+ }
2549
+ } else {
2550
+ if (node.paramChildren !== null && node.paramChildren.size > 0) {
2551
+ const existingParam = node.paramChildren.keys().next().value;
2552
+ if (existingParam !== undefined) {
2553
+ throw new Error(`Ambiguous routes: param ":${existingParam}" and wildcard "*${seg.name ?? ""}" compete at the same position in "${pattern}"`);
2554
+ }
2555
+ }
2556
+ node.wildcardChild = createNode();
2557
+ node.wildcardName = seg.name;
2558
+ }
2559
+ node = node.wildcardChild;
2560
+ }
2561
+ }
2562
+ if (node.handlers?.[method] !== undefined) {
2563
+ throw new Error(`Duplicate route: ${method} ${pattern} is already registered`);
2564
+ }
2565
+ if (node.handlers === null)
2566
+ node.handlers = Object.create(null);
2567
+ node.handlers[method] = handler;
2568
+ node.allow = SegmentTrie.computeAllow(node.handlers);
2569
+ node.notAllowed = Object.freeze({
2570
+ [MATCH_NOT_ALLOWED]: node.allow
2571
+ });
2572
+ if (isPureStatic) {
2573
+ let sHandlers = this.staticRoutes.get(cleanPattern);
2574
+ if (sHandlers === undefined) {
2575
+ sHandlers = Object.create(null);
2576
+ this.staticRoutes.set(cleanPattern, sHandlers);
2577
+ }
2578
+ sHandlers[method] = handler;
2579
+ const sAllow = SegmentTrie.computeAllow(sHandlers);
2580
+ this.staticNotAllowed.set(cleanPattern, Object.freeze({ [MATCH_NOT_ALLOWED]: sAllow }));
2581
+ }
2582
+ }
2583
+ static computeAllow(handlers) {
2584
+ const methods = Object.keys(handlers);
2585
+ if (methods.includes("GET") && !methods.includes("HEAD")) {
2586
+ return [...methods, "HEAD"].join(", ");
2587
+ }
2588
+ return methods.join(", ");
2589
+ }
2590
+ match(method, pathname) {
2591
+ const len = pathname.length;
2592
+ const cleanPath = len > 1 && pathname.charCodeAt(len - 1) === 47 ? pathname.slice(0, -1) : pathname;
2593
+ if (cleanPath.length <= this.maxStaticLength) {
2594
+ const sHandlers = this.staticRoutes.get(cleanPath);
2595
+ if (sHandlers !== undefined) {
2596
+ let handler = sHandlers[method];
2597
+ if (handler === undefined && method === "HEAD") {
2598
+ handler = sHandlers.GET;
2599
+ }
2600
+ if (handler !== undefined) {
2601
+ return handler;
2602
+ }
2603
+ const dynamicMatch = matchNode(this.root, pathname, 1, method, this.paramNameBuffer, this.paramValueBuffer, 0);
2604
+ if (this.paramNameBuffer.length > 0) {
2605
+ this.paramNameBuffer.length = 0;
2606
+ this.paramValueBuffer.length = 0;
2607
+ }
2608
+ if (dynamicMatch !== null && !(MATCH_NOT_ALLOWED in dynamicMatch)) {
2609
+ return dynamicMatch;
2610
+ }
2611
+ return this.staticNotAllowed.get(cleanPath);
2612
+ }
2613
+ }
2614
+ const res = matchNode(this.root, pathname, 1, method, this.paramNameBuffer, this.paramValueBuffer, 0);
2615
+ if (this.paramNameBuffer.length > 0) {
2616
+ this.paramNameBuffer.length = 0;
2617
+ this.paramValueBuffer.length = 0;
2618
+ }
2619
+ return res;
2620
+ }
2621
+ }
2622
+
2623
+ // src/middleware.ts
2624
+ function isThenable(value) {
2625
+ return (typeof value === "object" || typeof value === "function") && value !== null && typeof value.then === "function";
2626
+ }
2627
+ function mergeState(ctx, value) {
2628
+ if (typeof value === "object" && value !== null) {
2629
+ Object.assign(ctx.state, value);
2630
+ }
2631
+ }
2632
+ function composeMiddlewareDispatcher(mws, errorResolver) {
2633
+ if (mws.length > 64 || mws.some((middleware) => middleware.after !== undefined)) {
2634
+ return (ctx, handler) => runPipeline(mws, ctx, handler, errorResolver);
2635
+ }
2636
+ let next = (ctx, handler) => {
2637
+ let result;
2638
+ try {
2639
+ result = handler(ctx);
2640
+ } catch (error) {
2641
+ return handlePipelineError(mws, ctx, error, mws.length, errorResolver);
2642
+ }
2643
+ if (isThenable(result)) {
2644
+ return Promise.resolve(result).catch((error) => handlePipelineError(mws, ctx, error, mws.length, errorResolver));
2645
+ }
2646
+ return result;
2647
+ };
2648
+ for (let i = mws.length - 1;i >= 0; i--) {
2649
+ const middleware = mws[i];
2650
+ const hook = middleware.before;
2651
+ const following = next;
2652
+ next = (ctx, handler) => {
2653
+ if (!hook)
2654
+ return following(ctx, handler);
2655
+ let result;
2656
+ try {
2657
+ result = hook(ctx);
2658
+ } catch (error) {
2659
+ return handlePipelineError(mws, ctx, error, i, errorResolver);
2660
+ }
2661
+ if (result === undefined)
2662
+ return following(ctx, handler);
2663
+ if (isThenable(result)) {
2664
+ return Promise.resolve(result).then((value) => {
2665
+ if (value instanceof Response)
2666
+ return value;
2667
+ mergeState(ctx, value);
2668
+ return following(ctx, handler);
2669
+ }, (error) => handlePipelineError(mws, ctx, error, i, errorResolver));
2670
+ }
2671
+ if (result instanceof Response)
2672
+ return result;
2673
+ mergeState(ctx, result);
2674
+ return following(ctx, handler);
2675
+ };
2676
+ }
2677
+ return next;
2678
+ }
2679
+ function composeMiddlewares(mws, handler, errorResolver) {
2680
+ const dispatch = composeMiddlewareDispatcher(mws, errorResolver);
2681
+ return (ctx) => dispatch(ctx, handler);
2682
+ }
2683
+ function runPipeline(mws, ctx, handler, errorResolver) {
2684
+ let i = 0;
2685
+ const len = mws.length;
2686
+ while (i < len) {
2687
+ const hook = mws[i].before;
2688
+ if (hook) {
2689
+ let r;
2690
+ try {
2691
+ r = hook(ctx);
2692
+ } catch (err) {
2693
+ return handlePipelineError(mws, ctx, err, i, errorResolver);
2694
+ }
2695
+ if (r !== undefined) {
2696
+ if (r instanceof Response) {
2697
+ return unwindAfter(mws, ctx, r, i + 1, errorResolver);
2698
+ }
2699
+ if (isThenable(r)) {
2700
+ return resumeBefore(mws, ctx, handler, r, i, errorResolver);
2701
+ }
2702
+ mergeState(ctx, r);
2703
+ }
2704
+ }
2705
+ i++;
2706
+ }
2707
+ return invokeHandler(mws, ctx, handler, len, errorResolver);
2708
+ }
2709
+ function continueBefore(mws, ctx, handler, startIndex, errorResolver) {
2710
+ let i = startIndex;
2711
+ const len = mws.length;
2712
+ while (i < len) {
2713
+ const hook = mws[i].before;
2714
+ if (hook) {
2715
+ let r;
2716
+ try {
2717
+ r = hook(ctx);
2718
+ } catch (err) {
2719
+ return handlePipelineError(mws, ctx, err, i, errorResolver);
2720
+ }
2721
+ if (r !== undefined) {
2722
+ if (r instanceof Response) {
2723
+ return unwindAfter(mws, ctx, r, i + 1, errorResolver);
2724
+ }
2725
+ if (isThenable(r)) {
2726
+ return resumeBefore(mws, ctx, handler, r, i, errorResolver);
2727
+ }
2728
+ mergeState(ctx, r);
2729
+ }
2730
+ }
2731
+ i++;
2732
+ }
2733
+ return invokeHandler(mws, ctx, handler, len, errorResolver);
2734
+ }
2735
+ function invokeHandler(mws, ctx, handler, entered, errorResolver) {
2736
+ let res;
2737
+ try {
2738
+ res = handler(ctx);
2739
+ } catch (err) {
2740
+ return handlePipelineError(mws, ctx, err, entered, errorResolver);
2741
+ }
2742
+ if (isThenable(res)) {
2743
+ return resumeHandler(mws, ctx, res, entered, errorResolver);
2744
+ }
2745
+ return unwindAfter(mws, ctx, res, entered, errorResolver);
2746
+ }
2747
+ function resumeBefore(mws, ctx, handler, promise, index, errorResolver) {
2748
+ return Promise.resolve(promise).then((r) => {
2749
+ if (r instanceof Response) {
2750
+ return unwindAfter(mws, ctx, r, index + 1, errorResolver);
2751
+ }
2752
+ mergeState(ctx, r);
2753
+ return continueBefore(mws, ctx, handler, index + 1, errorResolver);
2754
+ }, (err) => handlePipelineError(mws, ctx, err, index, errorResolver));
2755
+ }
2756
+ function resumeHandler(mws, ctx, promise, entered, errorResolver) {
2757
+ return Promise.resolve(promise).then((res) => unwindAfter(mws, ctx, res, entered, errorResolver), (err) => handlePipelineError(mws, ctx, err, entered, errorResolver));
2758
+ }
2759
+ function handlePipelineError(mws, ctx, err, entered, errorResolver) {
2760
+ if (errorResolver !== undefined) {
2761
+ let res;
2762
+ try {
2763
+ res = errorResolver(err, ctx);
2764
+ } catch (resolverErr) {
2765
+ const fallback = errorToResponse(resolverErr, ctx.development);
2766
+ return unwindAfter(mws, ctx, fallback, entered, errorResolver);
2767
+ }
2768
+ if (isThenable(res)) {
2769
+ return res.then((resolved) => unwindAfter(mws, ctx, resolved, entered, errorResolver), (resolverErr) => {
2770
+ const fallback = errorToResponse(resolverErr, ctx.development);
2771
+ return unwindAfter(mws, ctx, fallback, entered, errorResolver);
2772
+ });
2773
+ }
2774
+ return unwindAfter(mws, ctx, res, entered, errorResolver);
2775
+ }
2776
+ const res = errorToResponse(err, ctx.development);
2777
+ return unwindAfter(mws, ctx, res, entered, errorResolver);
2778
+ }
2779
+ function unwindAfter(mws, ctx, res, enteredCount, errorResolver) {
2780
+ let currentRes = res;
2781
+ for (let j = enteredCount - 1;j >= 0; j--) {
2782
+ const hook = mws[j].after;
2783
+ if (hook) {
2784
+ let r;
2785
+ try {
2786
+ r = hook(ctx, currentRes);
2787
+ } catch (err) {
2788
+ if (errorResolver !== undefined) {
2789
+ try {
2790
+ const resolved = errorResolver(err, ctx);
2791
+ if (isThenable(resolved)) {
2792
+ return resolved.then((resolvedRes) => continueUnwind(mws, ctx, j - 1, resolvedRes, errorResolver), (resolverErr) => continueUnwind(mws, ctx, j - 1, errorToResponse(resolverErr, ctx.development), errorResolver));
2793
+ }
2794
+ currentRes = resolved;
2795
+ continue;
2796
+ } catch (resolverErr) {
2797
+ currentRes = errorToResponse(resolverErr, ctx.development);
2798
+ continue;
2799
+ }
2800
+ }
2801
+ currentRes = errorToResponse(err, ctx.development);
2802
+ continue;
2803
+ }
2804
+ if (r !== undefined) {
2805
+ if (isThenable(r)) {
2806
+ return resumeUnwind(mws, ctx, r, j - 1, currentRes, errorResolver);
2807
+ }
2808
+ if (r instanceof Response) {
2809
+ currentRes = r;
2810
+ }
2811
+ }
2812
+ }
2813
+ }
2814
+ return currentRes;
2815
+ }
2816
+ function resumeUnwind(mws, ctx, promise, nextIndex, currentRes, errorResolver) {
2817
+ return Promise.resolve(promise).then((r) => {
2818
+ const next = r instanceof Response ? r : currentRes;
2819
+ return continueUnwind(mws, ctx, nextIndex, next, errorResolver);
2820
+ }, (err) => {
2821
+ if (errorResolver !== undefined) {
2822
+ try {
2823
+ const resolved = errorResolver(err, ctx);
2824
+ if (isThenable(resolved)) {
2825
+ return resolved.then((resolvedRes) => continueUnwind(mws, ctx, nextIndex, resolvedRes, errorResolver), (resolverErr) => continueUnwind(mws, ctx, nextIndex, errorToResponse(resolverErr, ctx.development), errorResolver));
2826
+ }
2827
+ return continueUnwind(mws, ctx, nextIndex, resolved, errorResolver);
2828
+ } catch (resolverErr) {
2829
+ return continueUnwind(mws, ctx, nextIndex, errorToResponse(resolverErr, ctx.development), errorResolver);
2830
+ }
2831
+ }
2832
+ const next = errorToResponse(err, ctx.development);
2833
+ return continueUnwind(mws, ctx, nextIndex, next, errorResolver);
2834
+ });
2835
+ }
2836
+ function continueUnwind(mws, ctx, startIndex, currentRes, errorResolver) {
2837
+ let cur = currentRes;
2838
+ for (let j = startIndex;j >= 0; j--) {
2839
+ const hook = mws[j].after;
2840
+ if (hook) {
2841
+ let r;
2842
+ try {
2843
+ r = hook(ctx, cur);
2844
+ } catch (err) {
2845
+ if (errorResolver !== undefined) {
2846
+ try {
2847
+ const resolved = errorResolver(err, ctx);
2848
+ if (isThenable(resolved)) {
2849
+ return resolved.then((resolvedRes) => continueUnwind(mws, ctx, j - 1, resolvedRes, errorResolver), (resolverErr) => continueUnwind(mws, ctx, j - 1, errorToResponse(resolverErr, ctx.development), errorResolver));
2850
+ }
2851
+ cur = resolved;
2852
+ continue;
2853
+ } catch (resolverErr) {
2854
+ cur = errorToResponse(resolverErr, ctx.development);
2855
+ continue;
2856
+ }
2857
+ }
2858
+ cur = errorToResponse(err, ctx.development);
2859
+ continue;
2860
+ }
2861
+ if (r !== undefined) {
2862
+ if (isThenable(r)) {
2863
+ return resumeUnwind(mws, ctx, r, j - 1, cur, errorResolver);
2864
+ }
2865
+ if (r instanceof Response) {
2866
+ cur = r;
2867
+ }
2868
+ }
2869
+ }
2870
+ }
2871
+ return cur;
2872
+ }
2873
+
2874
+ // src/app.ts
2875
+ var METHODS = [
2876
+ "GET",
2877
+ "POST",
2878
+ "PUT",
2879
+ "DELETE",
2880
+ "PATCH",
2881
+ "HEAD",
2882
+ "OPTIONS"
2883
+ ];
2884
+ var MAX_ROUTE_SEGMENTS = 256;
2885
+ var EMPTY_PARAMS = Object.freeze(Object.create(null));
2886
+ var FAST_JSON_HEADERS = new Headers({
2887
+ "content-type": "application/json; charset=utf-8"
2888
+ });
2889
+ var FAST_TEXT_HEADERS = new Headers({
2890
+ "content-type": "text/plain; charset=utf-8"
2891
+ });
2892
+
2893
+ class ReadonlySetView {
2894
+ source;
2895
+ constructor(source) {
2896
+ this.source = source;
2897
+ }
2898
+ get size() {
2899
+ return this.source.size;
2900
+ }
2901
+ has(value) {
2902
+ return this.source.has(value);
2903
+ }
2904
+ forEach(callback, thisArg) {
2905
+ this.source.forEach((value) => {
2906
+ callback.call(thisArg, value, value, this);
2907
+ });
2908
+ }
2909
+ entries() {
2910
+ return this.source.entries();
2911
+ }
2912
+ keys() {
2913
+ return this.source.keys();
2914
+ }
2915
+ values() {
2916
+ return this.source.values();
2917
+ }
2918
+ [Symbol.iterator]() {
2919
+ return this.source[Symbol.iterator]();
2920
+ }
2921
+ get [Symbol.toStringTag]() {
2922
+ return "Set";
2923
+ }
2924
+ }
2925
+ function createReadonlySet(source) {
2926
+ return new ReadonlySetView(source);
2927
+ }
2928
+ var EMPTY_REDIRECT_HOSTS = createReadonlySet(new Set);
2929
+ function expandOptionalPatterns(pattern) {
2930
+ if (!pattern.includes("?"))
2931
+ return [pattern];
2932
+ const segments = pattern.split("/").filter(Boolean);
2933
+ const optIndices = [];
2934
+ for (let i = 0;i < segments.length; i++) {
2935
+ const seg = segments[i];
2936
+ if (seg.startsWith(":") && seg.endsWith("?")) {
2937
+ optIndices.push(i);
2938
+ }
2939
+ }
2940
+ if (optIndices.length === 0)
2941
+ return [pattern];
2942
+ const variants = [];
2943
+ const count = 1 << optIndices.length;
2944
+ for (let mask = 0;mask < count; mask++) {
2945
+ const parts = [];
2946
+ for (let i = 0;i < segments.length; i++) {
2947
+ const optPos = optIndices.indexOf(i);
2948
+ if (optPos >= 0) {
2949
+ if (mask & 1 << optPos) {
2950
+ parts.push(segments[i].slice(0, -1));
2951
+ }
2952
+ } else {
2953
+ parts.push(segments[i]);
2954
+ }
2955
+ }
2956
+ variants.push(parts.length === 0 ? "/" : `/${parts.join("/")}`);
2957
+ }
2958
+ return variants;
2959
+ }
2960
+ var LIGHT_SUPPORTED_PROPS = new Set([
2961
+ "req",
2962
+ "params",
2963
+ "pathname",
2964
+ "queryParam",
2965
+ "queryParamAll",
2966
+ "state",
2967
+ "stream",
2968
+ "bodyStream"
2969
+ ]);
2970
+ function classifyProps(props) {
2971
+ for (const p of props) {
2972
+ if (!LIGHT_SUPPORTED_PROPS.has(p)) {
2973
+ return {
2974
+ isContextFree: false,
2975
+ isLightweight: false,
2976
+ isParamsOnly: false,
2977
+ isJsonBodyOnly: false
2978
+ };
2979
+ }
2980
+ }
2981
+ const hasParams = props.has("params") || props.size === 0;
2982
+ const hasQuery = props.has("queryParam") || props.has("queryParamAll");
2983
+ if (hasParams && props.size === 1) {
2984
+ return {
2985
+ isContextFree: false,
2986
+ isLightweight: true,
2987
+ isParamsOnly: true,
2988
+ isJsonBodyOnly: false
2989
+ };
2990
+ }
2991
+ if (hasParams || hasQuery || props.size > 0) {
2992
+ return {
2993
+ isContextFree: false,
2994
+ isLightweight: true,
2995
+ isParamsOnly: false,
2996
+ isJsonBodyOnly: false
2997
+ };
2998
+ }
2999
+ return {
3000
+ isContextFree: false,
3001
+ isLightweight: false,
3002
+ isParamsOnly: false,
3003
+ isJsonBodyOnly: false
3004
+ };
3005
+ }
3006
+ function classify(analysis) {
3007
+ if (analysis.isNoArg) {
3008
+ return {
3009
+ isContextFree: true,
3010
+ isLightweight: false,
3011
+ isParamsOnly: false,
3012
+ isJsonBodyOnly: false
3013
+ };
3014
+ }
3015
+ if (analysis.arglessJsonCall && !analysis.isDestructured && analysis.contextProps.size === 1 && analysis.contextProps.has("json")) {
3016
+ return {
3017
+ isContextFree: false,
3018
+ isLightweight: false,
3019
+ isParamsOnly: false,
3020
+ isJsonBodyOnly: true
3021
+ };
3022
+ }
3023
+ if (analysis.isDestructured) {
3024
+ return classifyProps(analysis.destructuredProps);
3025
+ }
3026
+ if (analysis.hasDynamicAccess) {
3027
+ return {
3028
+ isContextFree: false,
3029
+ isLightweight: false,
3030
+ isParamsOnly: false,
3031
+ isJsonBodyOnly: false
3032
+ };
3033
+ }
3034
+ return classifyProps(analysis.contextProps);
3035
+ }
3036
+ function detectHandlerNeeds(fn) {
3037
+ try {
3038
+ return classify(analyzeHandler(fn));
3039
+ } catch {
3040
+ return {
3041
+ isContextFree: false,
3042
+ isLightweight: false,
3043
+ isParamsOnly: false,
3044
+ isJsonBodyOnly: false
3045
+ };
3046
+ }
3047
+ }
3048
+
3049
+ class FastLightContext {
3050
+ req;
3051
+ params;
3052
+ _pathname;
3053
+ _state;
3054
+ _hasPendingCookies = false;
3055
+ _url;
3056
+ _qPos = -2;
3057
+ constructor(req, params) {
3058
+ this.req = req;
3059
+ this.params = params;
3060
+ }
3061
+ init(req, params) {
3062
+ this.req = req;
3063
+ this.params = params;
3064
+ this._pathname = undefined;
3065
+ this._state = undefined;
3066
+ this._hasPendingCookies = false;
3067
+ this._url = undefined;
3068
+ this._qPos = -2;
3069
+ return this;
3070
+ }
3071
+ get url() {
3072
+ if (this._url === undefined) {
3073
+ this._url = this.req.url;
3074
+ }
3075
+ return this._url;
3076
+ }
3077
+ get pathname() {
3078
+ if (this._pathname === undefined) {
3079
+ this._pathname = scanPathname(this.url);
3080
+ }
3081
+ return this._pathname;
3082
+ }
3083
+ queryParam(name) {
3084
+ let u = this._url;
3085
+ if (u === undefined) {
3086
+ u = this.req.url;
3087
+ this._url = u;
3088
+ }
3089
+ let q = this._qPos;
3090
+ if (q === -2)
3091
+ this._qPos = q = u.indexOf("?");
3092
+ return findQueryParam(u, name, q);
3093
+ }
3094
+ queryParamAll(name) {
3095
+ return findQueryParamAll(this.url, name);
3096
+ }
3097
+ get cookies() {
3098
+ throw new Error("LightweightContext does not support cookies.");
3099
+ }
3100
+ get state() {
3101
+ let state = this._state;
3102
+ if (state === undefined) {
3103
+ state = Object.create(null);
3104
+ this._state = state;
3105
+ }
3106
+ return state;
3107
+ }
3108
+ stream() {
3109
+ return this.req.body;
3110
+ }
3111
+ get bodyStream() {
3112
+ return this.req.body;
3113
+ }
3114
+ }
3115
+ var lightContextPool = [];
3116
+ function acquireLightContext(req, params) {
3117
+ const popped = lightContextPool.pop();
3118
+ if (popped !== undefined) {
3119
+ return popped.init(req, params);
3120
+ }
3121
+ return new FastLightContext(req, params);
3122
+ }
3123
+ function releaseLightContext(ctx) {
3124
+ if (lightContextPool.length < 128) {
3125
+ lightContextPool.push(ctx);
3126
+ }
3127
+ }
3128
+ function reportWebSocketError(handler, ws, error) {
3129
+ if (!handler) {
3130
+ console.error("Unhandled WebSocket callback error:", error);
3131
+ return;
3132
+ }
3133
+ try {
3134
+ const result = handler(ws, error);
3135
+ if (isThenable(result)) {
3136
+ Promise.resolve(result).catch((handlerError) => console.error("WebSocket error handler failed:", handlerError));
3137
+ }
3138
+ } catch (handlerError) {
3139
+ console.error("WebSocket error handler failed:", handlerError);
3140
+ }
3141
+ }
3142
+ function dispatchWebSocketCallback(callback, args, onError) {
3143
+ if (!callback)
3144
+ return;
3145
+ try {
3146
+ const len = args.length;
3147
+ let result;
3148
+ if (len === 1) {
3149
+ result = callback(args[0]);
3150
+ } else if (len === 2) {
3151
+ result = callback(args[0], args[1]);
3152
+ } else if (len === 3) {
3153
+ result = callback(args[0], args[1], args[2]);
3154
+ } else {
3155
+ result = Reflect.apply(callback, undefined, args);
3156
+ }
3157
+ if (isThenable(result)) {
3158
+ Promise.resolve(result).catch(onError);
3159
+ }
3160
+ } catch (error) {
3161
+ onError(error);
3162
+ }
3163
+ }
3164
+ function getInternalWebSocketHandlers(ws) {
3165
+ const data = ws.data;
3166
+ return data?._barqInternal === true ? data.handlers : undefined;
3167
+ }
3168
+ function parseRouteArgs(args) {
3169
+ if (args.length === 0) {
3170
+ throw new Error("Route requires a handler function");
3171
+ }
3172
+ const last = args[args.length - 1];
3173
+ if (typeof last !== "function") {
3174
+ throw new Error("The final argument in route definition must be a Handler function");
3175
+ }
3176
+ const handler = last;
3177
+ if (args.length === 1) {
3178
+ return { middlewares: [], handler };
3179
+ }
3180
+ const middlewares = [];
3181
+ for (let i = 0;i < args.length - 1; i++) {
3182
+ const item = args[i];
3183
+ if (Array.isArray(item)) {
3184
+ for (let j = 0;j < item.length; j++) {
3185
+ middlewares.push(item[j]);
3186
+ }
3187
+ } else if (item && typeof item === "object") {
3188
+ middlewares.push(item);
3189
+ } else {
3190
+ throw new TypeError("Route middleware must be a Middleware object or array of Middleware");
3191
+ }
3192
+ }
3193
+ return { middlewares, handler };
3194
+ }
3195
+ function normalizePrefix(prefix) {
3196
+ let p = prefix.trim();
3197
+ if (p.length === 0 || p === "/")
3198
+ return "";
3199
+ if (p.charCodeAt(0) !== 47)
3200
+ p = `/${p}`;
3201
+ if (p.charCodeAt(p.length - 1) === 47)
3202
+ p = p.slice(0, -1);
3203
+ return p;
3204
+ }
3205
+ function joinPrefix(prefix, pattern) {
3206
+ if (!prefix)
3207
+ return pattern;
3208
+ let p = pattern.trim();
3209
+ if (p.length === 0 || p === "/")
3210
+ return prefix;
3211
+ if (p.charCodeAt(0) !== 47)
3212
+ p = `/${p}`;
3213
+ return prefix + p;
3214
+ }
3215
+ function canonicalizeRoutePattern(pattern) {
3216
+ let p = pattern.trim();
3217
+ if (p.length === 0)
3218
+ p = "/";
3219
+ if (p.charCodeAt(0) !== 47)
3220
+ p = `/${p}`;
3221
+ if (p.length > 1 && p.charCodeAt(p.length - 1) === 47) {
3222
+ p = p.slice(0, -1);
3223
+ }
3224
+ return p;
3225
+ }
3226
+ function validateRoutePattern(pattern) {
3227
+ if (pattern.length === 0 || pattern.charCodeAt(0) !== 47) {
3228
+ throw new Error(`Invalid route pattern "${pattern}": must start with /`);
3229
+ }
3230
+ if (pattern === "/")
3231
+ return;
3232
+ if (pattern.indexOf("#") !== -1) {
3233
+ throw new Error(`Invalid route pattern "${pattern}": must not contain #`);
3234
+ }
3235
+ const segments = pattern.split("/");
3236
+ if (segments.length - 1 > MAX_ROUTE_SEGMENTS) {
3237
+ throw new RangeError(`Route pattern exceeds the limit of ${MAX_ROUTE_SEGMENTS} segments`);
3238
+ }
3239
+ for (let i = 1;i < segments.length; i++) {
3240
+ const seg = segments[i];
3241
+ if (seg.length === 0) {
3242
+ throw new Error(`Invalid route pattern "${pattern}": empty segment (//)`);
3243
+ }
3244
+ const decoded = decodeSegment2(seg);
3245
+ if (decoded === "." || decoded === "..") {
3246
+ throw new Error(`Invalid route pattern "${pattern}": dot segments ., .. not allowed in route patterns`);
3247
+ }
3248
+ }
3249
+ }
3250
+ function decodeSegment2(seg) {
3251
+ if (seg.indexOf("%") === -1)
3252
+ return seg;
3253
+ try {
3254
+ return decodeURIComponent(seg);
3255
+ } catch {
3256
+ return seg;
3257
+ }
3258
+ }
3259
+ function toResponse(value) {
3260
+ if (value instanceof Response)
3261
+ return value;
3262
+ if (isThenable(value)) {
3263
+ return Promise.resolve(value).then((resolved) => toResponse(resolved));
3264
+ }
3265
+ return finalizeValue(value);
3266
+ }
3267
+ function finalizeValue(value) {
3268
+ if (typeof value === "object" && value !== null)
3269
+ return new Response(JSON.stringify(value), { headers: FAST_JSON_HEADERS });
3270
+ if (typeof value === "string")
3271
+ return new Response(value, { headers: FAST_TEXT_HEADERS });
3272
+ return new Response(String(value), { headers: FAST_TEXT_HEADERS });
3273
+ }
3274
+ async function stopClusterProcesses(processes, hardTimeoutMs) {
3275
+ const running = processes.filter((process2) => !process2.killed);
3276
+ if (running.length === 0)
3277
+ return false;
3278
+ for (const process2 of running)
3279
+ process2.kill("SIGTERM");
3280
+ const exited = Promise.all(running.map((process2) => process2.exited));
3281
+ let timer;
3282
+ const forced = await Promise.race([
3283
+ exited.then(() => false),
3284
+ new Promise((resolve) => {
3285
+ timer = setTimeout(() => resolve(true), hardTimeoutMs);
3286
+ timer.unref?.();
3287
+ })
3288
+ ]);
3289
+ if (timer !== undefined)
3290
+ clearTimeout(timer);
3291
+ if (forced) {
3292
+ for (const process2 of running) {
3293
+ if (!process2.killed)
3294
+ process2.kill("SIGKILL");
3295
+ }
3296
+ await exited;
3297
+ }
3298
+ return forced;
3299
+ }
3300
+
3301
+ class RouteGroup {
3302
+ app;
3303
+ prefix;
3304
+ middlewares;
3305
+ constructor(app, prefix, middlewares = []) {
3306
+ this.app = app;
3307
+ this.prefix = prefix;
3308
+ this.middlewares = middlewares;
3309
+ }
3310
+ use(...middlewares) {
3311
+ for (let i = 0;i < middlewares.length; i++) {
3312
+ this.middlewares.push(middlewares[i]);
3313
+ }
3314
+ return this;
3315
+ }
3316
+ plugin(pluginFn, options) {
3317
+ pluginFn(this, options);
3318
+ return this;
3319
+ }
3320
+ _register(method, pattern, args) {
3321
+ return this._registerMethods([method], pattern, args);
3322
+ }
3323
+ _registerMethods(methods, pattern, args) {
3324
+ const fullPattern = joinPrefix(this.prefix, pattern);
3325
+ const { middlewares, handler } = parseRouteArgs(args);
3326
+ const allMiddlewares = this.middlewares.length === 0 ? middlewares : [...this.middlewares, ...middlewares];
3327
+ this.app._registerMethods(methods, fullPattern, allMiddlewares.length === 0 ? [handler] : [...allMiddlewares, handler]);
3328
+ return this;
3329
+ }
3330
+ add(method, pattern, ...args) {
3331
+ return this._register(method, pattern, args);
3332
+ }
3333
+ get(pattern, ...args) {
3334
+ return this._register("GET", pattern, args);
3335
+ }
3336
+ post(pattern, ...args) {
3337
+ return this._register("POST", pattern, args);
3338
+ }
3339
+ put(pattern, ...args) {
3340
+ return this._register("PUT", pattern, args);
3341
+ }
3342
+ delete(pattern, ...args) {
3343
+ return this._register("DELETE", pattern, args);
3344
+ }
3345
+ patch(pattern, ...args) {
3346
+ return this._register("PATCH", pattern, args);
3347
+ }
3348
+ head(pattern, ...args) {
3349
+ return this._register("HEAD", pattern, args);
3350
+ }
3351
+ options(pattern, ...args) {
3352
+ return this._register("OPTIONS", pattern, args);
3353
+ }
3354
+ all(pattern, ...args) {
3355
+ return this._registerMethods(METHODS, pattern, args);
3356
+ }
3357
+ ws(pattern, handlers, beforeUpgrade) {
3358
+ this.app.ws(joinPrefix(this.prefix, pattern), handlers, beforeUpgrade ? (ctx) => beforeUpgrade(ctx) : undefined);
3359
+ return this;
3360
+ }
3361
+ group(prefix, ...args) {
3362
+ const nestedPrefix = joinPrefix(this.prefix, prefix);
3363
+ const last = args[args.length - 1];
3364
+ if (typeof last !== "function") {
3365
+ throw new Error("Route group callback must be a function");
3366
+ }
3367
+ const callback = last;
3368
+ const groupMws = [...this.middlewares];
3369
+ for (let i = 0;i < args.length - 1; i++) {
3370
+ const item = args[i];
3371
+ if (Array.isArray(item)) {
3372
+ for (let j = 0;j < item.length; j++)
3373
+ groupMws.push(item[j]);
3374
+ } else if (item && typeof item === "object") {
3375
+ groupMws.push(item);
3376
+ }
3377
+ }
3378
+ const nestedGroup = new RouteGroup(this.app, nestedPrefix, groupMws);
3379
+ callback(nestedGroup);
3380
+ return this;
3381
+ }
3382
+ }
3383
+
3384
+ class App {
3385
+ fetchHandler = (req, srv) => this.handle(req, srv);
3386
+ trie = new SegmentTrie;
3387
+ middlewares = [];
3388
+ nativeRoutes = [];
3389
+ server = null;
3390
+ clusterProcesses = null;
3391
+ _options;
3392
+ redirectHosts;
3393
+ trustProxy;
3394
+ trustedProxyChecker;
3395
+ stopPromise = null;
3396
+ notFoundHandler = null;
3397
+ errorHandler = null;
3398
+ errorResolver = undefined;
3399
+ globalPipeline = composeMiddlewareDispatcher([]);
3400
+ hasMiddlewares = false;
3401
+ hasWebSockets = false;
3402
+ development;
3403
+ cookieSecret;
3404
+ constructor(options = {}) {
3405
+ if (options.port !== undefined && (!Number.isInteger(options.port) || options.port < 0 || options.port > 65535)) {
3406
+ throw new RangeError("port must be an integer between 0 and 65535");
3407
+ }
3408
+ if (options.maxRequestBodySize !== undefined && (!Number.isSafeInteger(options.maxRequestBodySize) || options.maxRequestBodySize < 0)) {
3409
+ throw new RangeError("maxRequestBodySize must be a non-negative safe integer");
3410
+ }
3411
+ if (options.idleTimeout !== undefined && (!Number.isFinite(options.idleTimeout) || options.idleTimeout < 0 || options.idleTimeout > 255)) {
3412
+ throw new RangeError("idleTimeout must be between 0 and 255 seconds");
3413
+ }
3414
+ for (const [name, value] of [
3415
+ ["websocket.maxPayloadLength", options.websocket?.maxPayloadLength],
3416
+ ["websocket.backpressureLimit", options.websocket?.backpressureLimit]
3417
+ ]) {
3418
+ if (value !== undefined && (!Number.isSafeInteger(value) || value < 1)) {
3419
+ throw new RangeError(`${name} must be a positive safe integer`);
3420
+ }
3421
+ }
3422
+ if (options.websocket?.idleTimeout !== undefined && (!Number.isFinite(options.websocket.idleTimeout) || options.websocket.idleTimeout < 0 || options.websocket.idleTimeout > 255)) {
3423
+ throw new RangeError("websocket.idleTimeout must be between 0 and 255 seconds");
3424
+ }
3425
+ const trustedProxyRanges = Array.isArray(options.trustProxy) ? options.trustProxy : typeof options.trustProxy === "string" ? [options.trustProxy] : [];
3426
+ for (const range of trustedProxyRanges) {
3427
+ if (!isIpRange(range)) {
3428
+ throw new TypeError(`Invalid trustProxy IP range: ${range}`);
3429
+ }
3430
+ }
3431
+ if (options.cookieSecret !== undefined && !options.cookieSecret.trim()) {
3432
+ throw new TypeError("cookieSecret must be non-empty when provided");
3433
+ }
3434
+ this._options = options;
3435
+ this.development = options.development ?? true;
3436
+ this.trustProxy = Array.isArray(options.trustProxy) ? Object.freeze([...options.trustProxy]) : options.trustProxy ?? false;
3437
+ this.trustedProxyChecker = compileTrustProxy(options.trustProxy);
3438
+ this.cookieSecret = options.cookieSecret;
3439
+ this.redirectHosts = options.allowedRedirectHosts ? createReadonlySet(new Set(options.allowedRedirectHosts.map((h) => h.toLowerCase()))) : EMPTY_REDIRECT_HOSTS;
3440
+ }
3441
+ plugin(pluginFn, options) {
3442
+ pluginFn(this, options);
3443
+ return this;
3444
+ }
3445
+ notFound(handler) {
3446
+ this.notFoundHandler = handler;
3447
+ return this;
3448
+ }
3449
+ onError(handler) {
3450
+ this.errorHandler = handler;
3451
+ this.errorResolver = (err, ctx) => handler(err, ctx);
3452
+ if (this.server !== null) {
3453
+ this.globalPipeline = composeMiddlewareDispatcher(this.middlewares, this.errorResolver);
3454
+ }
3455
+ return this;
3456
+ }
3457
+ _register(method, pattern, args) {
3458
+ return this._registerMethods([method], pattern, args);
3459
+ }
3460
+ _registerMethods(methods, pattern, args) {
3461
+ const { middlewares, handler } = parseRouteArgs(args);
3462
+ const responseHandler = (ctx) => toResponse(handler(ctx));
3463
+ const finalHandler = middlewares.length === 0 ? responseHandler : composeMiddlewares(middlewares, responseHandler);
3464
+ const canonicalPattern = canonicalizeRoutePattern(pattern);
3465
+ validateRoutePattern(canonicalPattern);
3466
+ const routes = methods.map((method) => ({
3467
+ method,
3468
+ pattern: canonicalPattern,
3469
+ handler: finalHandler
3470
+ }));
3471
+ this.trie.addBatch(routes);
3472
+ const needs = detectHandlerNeeds(handler);
3473
+ const hasRouteMws = middlewares.length > 0;
3474
+ for (const r of routes) {
3475
+ const variants = expandOptionalPatterns(r.pattern);
3476
+ for (const variant of variants) {
3477
+ this.nativeRoutes.push({
3478
+ method: r.method,
3479
+ pattern: variant,
3480
+ handler: r.handler,
3481
+ rawHandler: handler,
3482
+ isDynamic: variant.includes(":") || variant.includes("*"),
3483
+ isContextFree: needs.isContextFree && !hasRouteMws,
3484
+ isLightweight: needs.isLightweight && !hasRouteMws,
3485
+ isParamsOnly: needs.isParamsOnly && !hasRouteMws,
3486
+ isJsonBodyOnly: needs.isJsonBodyOnly && !hasRouteMws,
3487
+ hasRouteMiddlewares: hasRouteMws
3488
+ });
3489
+ }
3490
+ }
3491
+ return this;
3492
+ }
3493
+ add(method, pattern, ...args) {
3494
+ return this._register(method, pattern, args);
3495
+ }
3496
+ get(pattern, ...args) {
3497
+ return this._register("GET", pattern, args);
3498
+ }
3499
+ post(pattern, ...args) {
3500
+ return this._register("POST", pattern, args);
3501
+ }
3502
+ put(pattern, ...args) {
3503
+ return this._register("PUT", pattern, args);
3504
+ }
3505
+ delete(pattern, ...args) {
3506
+ return this._register("DELETE", pattern, args);
3507
+ }
3508
+ patch(pattern, ...args) {
3509
+ return this._register("PATCH", pattern, args);
3510
+ }
3511
+ head(pattern, ...args) {
3512
+ return this._register("HEAD", pattern, args);
3513
+ }
3514
+ options(pattern, ...args) {
3515
+ return this._register("OPTIONS", pattern, args);
3516
+ }
3517
+ all(pattern, ...args) {
3518
+ return this._registerMethods(METHODS, pattern, args);
3519
+ }
3520
+ ws(pattern, handlers, beforeUpgrade) {
3521
+ this.hasWebSockets = true;
3522
+ return this._registerMethods(["GET"], pattern, [
3523
+ async (ctx) => {
3524
+ if (ctx.req.headers.get("upgrade")?.toLowerCase() !== "websocket") {
3525
+ return new Response("Upgrade Required", { status: 426 });
3526
+ }
3527
+ let customData;
3528
+ if (beforeUpgrade) {
3529
+ const check = await beforeUpgrade(ctx);
3530
+ if (!check)
3531
+ return new Response("Unauthorized", { status: 401 });
3532
+ if (typeof check === "object" && check !== null && "data" in check) {
3533
+ customData = check.data;
3534
+ }
3535
+ }
3536
+ const upgradeData = customData !== undefined && typeof customData === "object" && customData !== null ? { ...customData, handlers, _barqInternal: true } : { handlers, _barqInternal: true, data: customData };
3537
+ const upgraded = ctx.upgrade(upgradeData);
3538
+ return upgraded ? new Response(null) : new Response("WebSocket upgrade failed", { status: 400 });
3539
+ }
3540
+ ]);
3541
+ }
3542
+ group(prefix, ...args) {
3543
+ const last = args[args.length - 1];
3544
+ if (typeof last !== "function") {
3545
+ throw new Error("Route group callback must be a function");
3546
+ }
3547
+ const callback = last;
3548
+ const groupMws = [];
3549
+ for (let i = 0;i < args.length - 1; i++) {
3550
+ const item = args[i];
3551
+ if (Array.isArray(item)) {
3552
+ for (let j = 0;j < item.length; j++)
3553
+ groupMws.push(item[j]);
3554
+ } else if (item && typeof item === "object") {
3555
+ groupMws.push(item);
3556
+ }
3557
+ }
3558
+ const normalizedPrefix = normalizePrefix(prefix);
3559
+ const group = new RouteGroup(this, normalizedPrefix, groupMws);
3560
+ callback(group);
3561
+ return this;
3562
+ }
3563
+ use(...middlewares) {
3564
+ for (let i = 0;i < middlewares.length; i++) {
3565
+ this.middlewares.push(middlewares[i]);
3566
+ }
3567
+ this.hasMiddlewares = this.middlewares.length > 0;
3568
+ if (this.server !== null) {
3569
+ this.globalPipeline = composeMiddlewareDispatcher(this.middlewares, this.errorResolver);
3570
+ }
3571
+ return this;
3572
+ }
3573
+ listen(port) {
3574
+ const listenPort = port ?? this._options.port ?? 0;
3575
+ if (!Number.isInteger(listenPort) || listenPort < 0 || listenPort > 65535) {
3576
+ throw new RangeError("port must be an integer between 0 and 65535");
3577
+ }
3578
+ if (this.stopPromise !== null) {
3579
+ throw new Error("App cannot listen while shutdown is in progress");
3580
+ }
3581
+ if (this.server !== null) {
3582
+ throw new Error("App is already listening");
3583
+ }
3584
+ const userWs = this._options.websocket;
3585
+ this.globalPipeline = composeMiddlewareDispatcher(this.middlewares, this.errorResolver);
3586
+ const contextApplication = this;
3587
+ const opts = {
3588
+ fetch: this.fetchHandler,
3589
+ development: this.development
3590
+ };
3591
+ if (this._options.idleTimeout !== undefined) {
3592
+ opts.idleTimeout = this._options.idleTimeout;
3593
+ }
3594
+ if (this._options.maxRequestBodySize !== undefined) {
3595
+ opts.maxRequestBodySize = this._options.maxRequestBodySize;
3596
+ }
3597
+ opts.error = (err) => errorToResponse(err, this.development);
3598
+ if (Bun.env.BARQ_IS_WORKER === "true")
3599
+ opts.reusePort = true;
3600
+ if (this.hasWebSockets || userWs !== undefined) {
3601
+ opts.websocket = {
3602
+ ...userWs,
3603
+ message: (ws, message) => {
3604
+ const internal = getInternalWebSocketHandlers(ws);
3605
+ dispatchWebSocketCallback(internal?.message, [ws, message], (err) => reportWebSocketError(internal?.error, ws, err));
3606
+ dispatchWebSocketCallback(userWs?.message, [ws, message], (err) => reportWebSocketError(userWs?.error, ws, err));
3607
+ },
3608
+ open: (ws) => {
3609
+ const internal = getInternalWebSocketHandlers(ws);
3610
+ dispatchWebSocketCallback(internal?.open, [ws], (err) => reportWebSocketError(internal?.error, ws, err));
3611
+ dispatchWebSocketCallback(userWs?.open, [ws], (err) => reportWebSocketError(userWs?.error, ws, err));
3612
+ },
3613
+ close: (ws, code, reason) => {
3614
+ const internal = getInternalWebSocketHandlers(ws);
3615
+ dispatchWebSocketCallback(internal?.close, [ws, code, reason], (err) => reportWebSocketError(internal?.error, ws, err));
3616
+ dispatchWebSocketCallback(userWs?.close, [ws, code, reason], (err) => reportWebSocketError(userWs?.error, ws, err));
3617
+ },
3618
+ drain: (ws) => {
3619
+ const internal = getInternalWebSocketHandlers(ws);
3620
+ dispatchWebSocketCallback(internal?.drain, [ws], (err) => reportWebSocketError(internal?.error, ws, err));
3621
+ dispatchWebSocketCallback(userWs?.drain, [ws], (err) => reportWebSocketError(userWs?.error, ws, err));
3622
+ },
3623
+ error: (ws, err) => {
3624
+ const internal = getInternalWebSocketHandlers(ws);
3625
+ if (internal?.error === undefined && userWs?.error === undefined) {
3626
+ console.error("Unhandled WebSocket error:", err);
3627
+ return;
3628
+ }
3629
+ if (internal?.error)
3630
+ reportWebSocketError(internal.error, ws, err);
3631
+ if (userWs?.error)
3632
+ reportWebSocketError(userWs.error, ws, err);
3633
+ }
3634
+ };
3635
+ }
3636
+ if (this.nativeRoutes.length > 0) {
3637
+ const systemRoutes = Object.create(null);
3638
+ const hasGlobalPipeline = this.hasMiddlewares || this.errorResolver !== undefined;
3639
+ const routesByPattern = new Map;
3640
+ for (const nr of this.nativeRoutes) {
3641
+ let list = routesByPattern.get(nr.pattern);
3642
+ if (!list) {
3643
+ list = [];
3644
+ routesByPattern.set(nr.pattern, list);
3645
+ }
3646
+ list.push(nr);
3647
+ }
3648
+ for (const [pattern, list] of routesByPattern) {
3649
+ const isDynamic = pattern.includes(":") || pattern.includes("*");
3650
+ const methodMap = Object.create(null);
3651
+ for (const nr of list) {
3652
+ const h = nr.handler;
3653
+ const isDyn = nr.isDynamic;
3654
+ const raw = nr.rawHandler;
3655
+ if (hasGlobalPipeline || nr.hasRouteMiddlewares) {
3656
+ methodMap[nr.method] = (req) => {
3657
+ try {
3658
+ const params = isDyn ? req.params ?? EMPTY_PARAMS : EMPTY_PARAMS;
3659
+ const ctx = new Context(req, this.server, params, contextApplication);
3660
+ const result = this.globalPipeline(ctx, h);
3661
+ return finalizeResponse(ctx, result, req.method === "HEAD");
3662
+ } catch (err) {
3663
+ return errorToResponse(err, this.development);
3664
+ }
3665
+ };
3666
+ } else if (nr.isContextFree && raw) {
3667
+ const analysis = analyzeHandler(raw);
3668
+ const literal = analysis.literal;
3669
+ if (literal !== null) {
3670
+ if (literal.kind === "string") {
3671
+ methodMap[nr.method] = new Response(literal.value);
3672
+ if (nr.method === "GET" && !isDyn)
3673
+ methodMap.HEAD = new Response(null);
3674
+ } else {
3675
+ methodMap[nr.method] = new Response(literal.value, {
3676
+ headers: FAST_JSON_HEADERS
3677
+ });
3678
+ if (nr.method === "GET" && !isDyn)
3679
+ methodMap.HEAD = new Response(null, {
3680
+ headers: FAST_JSON_HEADERS
3681
+ });
3682
+ }
3683
+ } else {
3684
+ methodMap[nr.method] = () => {
3685
+ const res = raw();
3686
+ if (res instanceof Response)
3687
+ return res;
3688
+ if (isThenable(res)) {
3689
+ return Promise.resolve(res).then((r) => {
3690
+ if (r instanceof Response)
3691
+ return r;
3692
+ if (typeof r === "object" && r !== null)
3693
+ return Response.json(r);
3694
+ if (typeof r === "string")
3695
+ return new Response(r, { headers: FAST_TEXT_HEADERS });
3696
+ return finalizeValue(r);
3697
+ });
3698
+ }
3699
+ if (typeof res === "object" && res !== null)
3700
+ return Response.json(res);
3701
+ if (typeof res === "string")
3702
+ return new Response(res, { headers: FAST_TEXT_HEADERS });
3703
+ return Response.json(res);
3704
+ };
3705
+ if (nr.method === "GET" && !isDyn) {
3706
+ methodMap.HEAD = () => {
3707
+ const res = raw();
3708
+ const r = res instanceof Response ? res : finalizeValue(res);
3709
+ return stripBody(r);
3710
+ };
3711
+ }
3712
+ }
3713
+ } else if (nr.isJsonBodyOnly && raw) {
3714
+ methodMap[nr.method] = (req) => new Response(req.body, { headers: FAST_JSON_HEADERS });
3715
+ if (nr.method === "GET" && !isDyn) {
3716
+ methodMap.HEAD = (req) => req.json().then(() => new Response(null, { headers: FAST_JSON_HEADERS }), (err) => errorToResponse(err, this.development));
3717
+ }
3718
+ } else if (nr.isParamsOnly && raw) {
3719
+ const analysis = analyzeHandler(raw);
3720
+ if (analysis.paramSerializer) {
3721
+ const serializer = analysis.paramSerializer;
3722
+ const responseInit = { headers: FAST_JSON_HEADERS };
3723
+ methodMap[nr.method] = (req) => {
3724
+ const params = req.params ?? EMPTY_PARAMS;
3725
+ const syncRes = raw({ params });
3726
+ if (isThenable(syncRes)) {
3727
+ return Promise.resolve(syncRes).then((val) => val instanceof Response ? val : typeof val === "object" && val !== null ? Response.json(val) : new Response(String(val)));
3728
+ }
3729
+ return new Response(serializer(params), responseInit);
3730
+ };
3731
+ } else {
3732
+ methodMap[nr.method] = (req) => {
3733
+ const p = req.params;
3734
+ const res = raw(p ? req : { params: EMPTY_PARAMS, req });
3735
+ if (typeof res === "object" && res !== null) {
3736
+ if (res instanceof Response)
3737
+ return res;
3738
+ return Response.json(res);
3739
+ }
3740
+ if (typeof res === "string")
3741
+ return new Response(res, { headers: FAST_TEXT_HEADERS });
3742
+ if (isThenable(res)) {
3743
+ return Promise.resolve(res).then((r) => {
3744
+ if (r instanceof Response)
3745
+ return r;
3746
+ if (typeof r === "object" && r !== null)
3747
+ return new Response(JSON.stringify(r), {
3748
+ headers: FAST_JSON_HEADERS
3749
+ });
3750
+ if (typeof r === "string")
3751
+ return new Response(r, { headers: FAST_TEXT_HEADERS });
3752
+ return finalizeValue(r);
3753
+ });
3754
+ }
3755
+ return new Response(JSON.stringify(res), {
3756
+ headers: FAST_JSON_HEADERS
3757
+ });
3758
+ };
3759
+ if (nr.method === "GET" && !isDyn)
3760
+ methodMap.HEAD = () => new Response(null, { headers: FAST_JSON_HEADERS });
3761
+ }
3762
+ } else if (nr.isLightweight && raw) {
3763
+ methodMap[nr.method] = (req) => {
3764
+ const params = isDyn ? req.params ?? EMPTY_PARAMS : EMPTY_PARAMS;
3765
+ const ctx = acquireLightContext(req, params);
3766
+ let res;
3767
+ try {
3768
+ res = raw(ctx);
3769
+ } catch (err) {
3770
+ releaseLightContext(ctx);
3771
+ return errorToResponse(err, this.development);
3772
+ }
3773
+ if (typeof res === "object" && res !== null) {
3774
+ if (res instanceof Response) {
3775
+ releaseLightContext(ctx);
3776
+ return res;
3777
+ }
3778
+ if (!isThenable(res)) {
3779
+ releaseLightContext(ctx);
3780
+ return Response.json(res);
3781
+ }
3782
+ } else if (typeof res === "string") {
3783
+ releaseLightContext(ctx);
3784
+ return new Response(res, { headers: FAST_TEXT_HEADERS });
3785
+ } else if (!isThenable(res)) {
3786
+ releaseLightContext(ctx);
3787
+ return new Response(JSON.stringify(res), {
3788
+ headers: FAST_JSON_HEADERS
3789
+ });
3790
+ }
3791
+ return Promise.resolve(res).then((r) => {
3792
+ releaseLightContext(ctx);
3793
+ if (r instanceof Response)
3794
+ return r;
3795
+ if (typeof r === "object" && r !== null)
3796
+ return new Response(JSON.stringify(r), {
3797
+ headers: FAST_JSON_HEADERS
3798
+ });
3799
+ if (typeof r === "string")
3800
+ return new Response(r, { headers: FAST_TEXT_HEADERS });
3801
+ return finalizeValue(r);
3802
+ }).catch((err) => {
3803
+ releaseLightContext(ctx);
3804
+ return errorToResponse(err, this.development);
3805
+ });
3806
+ };
3807
+ if (nr.method === "GET" && !isDyn)
3808
+ methodMap.HEAD = () => new Response(null, { headers: FAST_JSON_HEADERS });
3809
+ } else {
3810
+ methodMap[nr.method] = (req) => {
3811
+ const isHead = nr.method === "GET" && req.method === "HEAD";
3812
+ try {
3813
+ const params = isDyn ? req.params ?? EMPTY_PARAMS : EMPTY_PARAMS;
3814
+ const ctx = new Context(req, this.server, params, contextApplication);
3815
+ const res = raw ? raw(ctx) : h(ctx);
3816
+ if (res instanceof Response) {
3817
+ if (!isHead && !ctx._hasPendingCookies)
3818
+ return res;
3819
+ return finalizeResponse(ctx, res, isHead);
3820
+ }
3821
+ if (!isThenable(res))
3822
+ return finalizeResponse(ctx, toResponse(res), isHead);
3823
+ return Promise.resolve(res).then((value) => finalizeResponse(ctx, toResponse(value), isHead)).catch((err) => finalizeResponse(ctx, errorToResponse(err, this.development), isHead));
3824
+ } catch (err) {
3825
+ return errorToResponse(err, this.development);
3826
+ }
3827
+ };
3828
+ }
3829
+ }
3830
+ const allowMethods = Object.keys(methodMap);
3831
+ const allowHeader = allowMethods.includes("GET") && !allowMethods.includes("HEAD") ? [...allowMethods, "HEAD"].join(", ") : allowMethods.join(", ");
3832
+ if (isDynamic) {
3833
+ const getFn = methodMap.GET;
3834
+ if (allowMethods.length === 1 && typeof getFn === "function" && allowMethods[0] === "GET") {
3835
+ systemRoutes[pattern] = methodMap;
3836
+ } else {
3837
+ systemRoutes[pattern] = (req) => {
3838
+ const matched = methodMap[req.method];
3839
+ if (typeof matched === "function")
3840
+ return matched(req);
3841
+ if (matched instanceof Response)
3842
+ return req.method === "HEAD" ? stripBody(matched) : matched;
3843
+ if (req.method === "HEAD") {
3844
+ const gh = methodMap.GET;
3845
+ if (typeof gh === "function") {
3846
+ const res = gh(req);
3847
+ return isThenable(res) ? res.then(stripBody) : stripBody(res);
3848
+ }
3849
+ }
3850
+ return new Response('{"error":"Method Not Allowed"}', {
3851
+ status: 405,
3852
+ headers: {
3853
+ "content-type": "application/json; charset=utf-8",
3854
+ Allow: allowHeader
3855
+ }
3856
+ });
3857
+ };
3858
+ }
3859
+ } else {
3860
+ systemRoutes[pattern] = methodMap;
3861
+ }
3862
+ }
3863
+ opts.routes = systemRoutes;
3864
+ }
3865
+ opts.port = listenPort;
3866
+ if (this._options.hostname !== undefined)
3867
+ opts.hostname = this._options.hostname;
3868
+ if (this._options.tls !== undefined)
3869
+ opts.tls = this._options.tls;
3870
+ this.server = Bun.serve(opts);
3871
+ return this.server;
3872
+ }
3873
+ handle(req, srv) {
3874
+ const isHead = req.method === "HEAD";
3875
+ const serverInstance = srv ?? this.server;
3876
+ const contextApplication = this;
3877
+ let currentCtx = null;
3878
+ let pathname;
3879
+ try {
3880
+ pathname = scanPathname(req.url);
3881
+ const matched = this.trie.match(req.method, pathname);
3882
+ if (matched === null) {
3883
+ if (this.notFoundHandler === null && !this.hasMiddlewares && this.errorResolver === undefined) {
3884
+ return new Response('{"error":"Not Found"}', {
3885
+ status: 404,
3886
+ headers: { "content-type": "application/json; charset=utf-8" }
3887
+ });
3888
+ }
3889
+ currentCtx = new Context(req, serverInstance, EMPTY_PARAMS, contextApplication, pathname);
3890
+ const notFoundHandler = this.notFoundHandler !== null ? this.notFoundHandler : () => new Response('{"error":"Not Found"}', {
3891
+ status: 404,
3892
+ headers: {
3893
+ "content-type": "application/json; charset=utf-8"
3894
+ }
3895
+ });
3896
+ const result = this.globalPipeline(currentCtx, notFoundHandler);
3897
+ return finalizeResponse(currentCtx, result, isHead);
3898
+ }
3899
+ if (!this.hasMiddlewares && this.errorResolver === undefined) {
3900
+ if (typeof matched === "function") {
3901
+ if (matched.length === 0) {
3902
+ const res = matched();
3903
+ if (!isHead && !isThenable(res))
3904
+ return res;
3905
+ if (isThenable(res)) {
3906
+ return res.then((r) => isHead ? stripBody(r) : r, (err) => errorToResponse(err, this.development));
3907
+ }
3908
+ return isHead ? stripBody(res) : res;
3909
+ }
3910
+ currentCtx = new Context(req, serverInstance, EMPTY_PARAMS, contextApplication, pathname);
3911
+ const res = matched(currentCtx);
3912
+ if (!isHead && !isThenable(res)) {
3913
+ if (typeof res === "object" && res !== null && !(res instanceof Response)) {
3914
+ return new Response(JSON.stringify(res), {
3915
+ headers: FAST_JSON_HEADERS
3916
+ });
3917
+ }
3918
+ if (!currentCtx._hasPendingCookies)
3919
+ return res;
3920
+ }
3921
+ return finalizeResponse(currentCtx, guardRejections(res, this.development), isHead);
3922
+ }
3923
+ const handler = typeof matched === "object" && MATCH_HANDLER in matched ? matched[MATCH_HANDLER] : undefined;
3924
+ if (handler !== undefined) {
3925
+ const params = matched;
3926
+ currentCtx = new Context(req, serverInstance, params, contextApplication, pathname);
3927
+ const res = handler(currentCtx);
3928
+ if (!isHead && !isThenable(res)) {
3929
+ if (!currentCtx._hasPendingCookies)
3930
+ return res;
3931
+ }
3932
+ return finalizeResponse(currentCtx, guardRejections(res, this.development), isHead);
3933
+ }
3934
+ }
3935
+ if (typeof matched === "function") {
3936
+ currentCtx = new Context(req, serverInstance, EMPTY_PARAMS, contextApplication, pathname);
3937
+ const result = this.globalPipeline(currentCtx, matched);
3938
+ return finalizeResponse(currentCtx, result, isHead);
3939
+ }
3940
+ if (MATCH_NOT_ALLOWED in matched) {
3941
+ const allow = matched[MATCH_NOT_ALLOWED];
3942
+ if (this.errorHandler === null && !this.hasMiddlewares && this.errorResolver === undefined) {
3943
+ return new Response('{"error":"Method Not Allowed"}', {
3944
+ status: 405,
3945
+ headers: {
3946
+ "content-type": "application/json; charset=utf-8",
3947
+ Allow: allow
3948
+ }
3949
+ });
3950
+ }
3951
+ currentCtx = new Context(req, serverInstance, EMPTY_PARAMS, contextApplication, pathname);
3952
+ const notAllowedHandler = () => errorToResponse(new HttpError(405, { error: "Method Not Allowed" }, { Allow: allow }), this.development);
3953
+ const result = this.globalPipeline(currentCtx, notAllowedHandler);
3954
+ return finalizeResponse(currentCtx, result, isHead);
3955
+ }
3956
+ const params = matched;
3957
+ const handler = params[MATCH_HANDLER];
3958
+ currentCtx = new Context(req, serverInstance, params, contextApplication, pathname);
3959
+ const result = this.globalPipeline(currentCtx, handler);
3960
+ return finalizeResponse(currentCtx, result, isHead);
3961
+ } catch (err) {
3962
+ const activeCtx = currentCtx ?? new Context(req, serverInstance, EMPTY_PARAMS, contextApplication, pathname);
3963
+ if (this.errorHandler !== null) {
3964
+ try {
3965
+ const custom = this.errorHandler(err, activeCtx);
3966
+ const result = isThenable(custom) ? custom.then((r) => unwindAfter(this.middlewares, activeCtx, r, 0, this.errorResolver)) : unwindAfter(this.middlewares, activeCtx, custom, 0, this.errorResolver);
3967
+ return finalizeResponse(activeCtx, result, isHead);
3968
+ } catch (e2) {
3969
+ const fallback = errorToResponse(e2, this.development);
3970
+ const result = unwindAfter(this.middlewares, activeCtx, fallback, 0, this.errorResolver);
3971
+ return finalizeResponse(activeCtx, result, isHead);
3972
+ }
3973
+ }
3974
+ const routingErr = errorToResponse(err, this.development);
3975
+ const result = unwindAfter(this.middlewares, activeCtx, routingErr, 0, this.errorResolver);
3976
+ return finalizeResponse(activeCtx, result, isHead);
3977
+ }
3978
+ }
3979
+ cluster(port) {
3980
+ const listenPort = port ?? this._options.port ?? 3000;
3981
+ const isWorker = Bun.env.BARQ_IS_WORKER === "true";
3982
+ if (!Number.isInteger(listenPort) || listenPort < 0 || listenPort > 65535) {
3983
+ throw new RangeError("port must be an integer between 0 and 65535");
3984
+ }
3985
+ if (isWorker || process.platform !== "linux") {
3986
+ return this.listen(listenPort);
3987
+ }
3988
+ if (listenPort === 0) {
3989
+ throw new RangeError("cluster requires a fixed, non-zero port");
3990
+ }
3991
+ if (this.clusterProcesses !== null || this.server !== null) {
3992
+ throw new Error("App is already listening or clustering");
3993
+ }
3994
+ const entry = process.argv[1];
3995
+ if (!entry) {
3996
+ throw new Error("Cannot start cluster without an application entry file");
3997
+ }
3998
+ const processes = [];
3999
+ let crashCount = 0;
4000
+ let lastReset = Date.now();
4001
+ const spawnWorker = () => {
4002
+ const proc = Bun.spawn([process.execPath, "run", entry], {
4003
+ env: {
4004
+ ...process.env,
4005
+ BARQ_IS_WORKER: "true",
4006
+ PORT: String(listenPort)
4007
+ },
4008
+ stdio: ["inherit", "inherit", "inherit"]
4009
+ });
4010
+ proc.exited.then((_code) => {
4011
+ if (this.stopPromise === null && this.clusterProcesses !== null) {
4012
+ const now = Date.now();
4013
+ if (now - lastReset > 5000) {
4014
+ crashCount = 0;
4015
+ lastReset = now;
4016
+ }
4017
+ crashCount++;
4018
+ const idx = processes.indexOf(proc);
4019
+ if (idx !== -1) {
4020
+ processes.splice(idx, 1);
4021
+ }
4022
+ if (crashCount > 15) {
4023
+ console.error("[Barq Cluster] Workers restarting too fast. Throttling respawn.");
4024
+ setTimeout(() => {
4025
+ if (this.stopPromise === null && this.clusterProcesses !== null) {
4026
+ processes.push(spawnWorker());
4027
+ }
4028
+ }, 2000);
4029
+ return;
4030
+ }
4031
+ processes.push(spawnWorker());
4032
+ }
4033
+ });
4034
+ return proc;
4035
+ };
4036
+ try {
4037
+ for (let i = 0;i < cpus().length; i++) {
4038
+ processes.push(spawnWorker());
4039
+ }
4040
+ } catch (error) {
4041
+ for (const process2 of processes)
4042
+ process2.kill("SIGTERM");
4043
+ throw error;
4044
+ }
4045
+ this.clusterProcesses = processes;
4046
+ return;
4047
+ }
4048
+ async stop(hardTimeoutMs = 5000) {
4049
+ if (!Number.isFinite(hardTimeoutMs) || hardTimeoutMs < 0) {
4050
+ throw new RangeError("hardTimeoutMs must be a finite non-negative number");
4051
+ }
4052
+ if (this.stopPromise !== null) {
4053
+ return this.stopPromise;
4054
+ }
4055
+ const server = this.server;
4056
+ const clusterProcesses = this.clusterProcesses;
4057
+ this.server = null;
4058
+ this.clusterProcesses = null;
4059
+ if (server === null && clusterProcesses === null) {
4060
+ return { forced: false, pending: 0 };
4061
+ }
4062
+ this.stopPromise = (async () => {
4063
+ let serverResult = { forced: false, pending: 0 };
4064
+ let workersForced = false;
4065
+ try {
4066
+ if (server !== null) {
4067
+ serverResult = await stopServer(server, hardTimeoutMs);
4068
+ }
4069
+ } finally {
4070
+ if (clusterProcesses !== null) {
4071
+ workersForced = await stopClusterProcesses(clusterProcesses, hardTimeoutMs);
4072
+ }
4073
+ }
4074
+ return {
4075
+ forced: serverResult.forced || workersForced,
4076
+ pending: serverResult.pending
4077
+ };
4078
+ })();
4079
+ try {
4080
+ return await this.stopPromise;
4081
+ } finally {
4082
+ this.stopPromise = null;
4083
+ }
4084
+ }
4085
+ }
4086
+ function guardRejections(res, development) {
4087
+ return isThenable(res) ? res.catch((err) => errorToResponse(err, development)) : res;
4088
+ }
4089
+ function applyCookies(ctx, res) {
4090
+ if (!ctx._hasPendingCookies)
4091
+ return res;
4092
+ const cookies = ctx._cookieJarIfCreated();
4093
+ if (cookies === null)
4094
+ return res;
4095
+ const headers = new Headers(res.headers);
4096
+ applyPendingCookies(cookies, headers);
4097
+ ctx._hasPendingCookies = false;
4098
+ return new Response(res.body, {
4099
+ status: res.status,
4100
+ statusText: res.statusText,
4101
+ headers
4102
+ });
4103
+ }
4104
+ function finalizeResponse(ctx, res, isHead) {
4105
+ if (res instanceof Response) {
4106
+ if (!isHead && !ctx._hasPendingCookies)
4107
+ return res;
4108
+ const withCookies = applyCookies(ctx, res);
4109
+ return isHead ? stripBody(withCookies) : withCookies;
4110
+ }
4111
+ if (isThenable(res)) {
4112
+ return res.then((response) => {
4113
+ const withCookies = applyCookies(ctx, response);
4114
+ return isHead ? stripBody(withCookies) : withCookies;
4115
+ });
4116
+ }
4117
+ if (!isHead) {
4118
+ if (!ctx._hasPendingCookies)
4119
+ return res;
4120
+ return applyCookies(ctx, res);
4121
+ }
4122
+ return stripBody(applyCookies(ctx, res));
4123
+ }
4124
+ function stripBody(res) {
4125
+ if (res.body === null)
4126
+ return res;
4127
+ try {
4128
+ res.body.cancel?.().catch?.(() => {});
4129
+ } catch {}
4130
+ return new Response(null, {
4131
+ status: res.status,
4132
+ statusText: res.statusText,
4133
+ headers: res.headers
4134
+ });
4135
+ }
4136
+
4137
+ // src/internal/node-compat.ts
4138
+ var isNode = typeof Bun === "undefined";
4139
+ var WS_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
4140
+ var nodeTopics = new Map;
4141
+
4142
+ class NodeServerWebSocket {
4143
+ socket;
4144
+ data;
4145
+ readyState = 1;
4146
+ remoteAddress;
4147
+ topics = new Set;
4148
+ buffer = Buffer.alloc(0);
4149
+ fragments = [];
4150
+ fragmentOpcode = 0;
4151
+ maxPayloadLength;
4152
+ handlers;
4153
+ appHandlers;
4154
+ constructor(socket, data, wsOptions) {
4155
+ this.socket = socket;
4156
+ this.data = data;
4157
+ this.remoteAddress = ("remoteAddress" in socket ? socket.remoteAddress : "") || "";
4158
+ this.maxPayloadLength = wsOptions?.maxPayloadLength ?? 16 * 1024 * 1024;
4159
+ this.appHandlers = wsOptions;
4160
+ const internal = data?._barqInternal ? data.handlers : undefined;
4161
+ this.handlers = internal;
4162
+ socket.on("data", (chunk) => this.onData(chunk));
4163
+ socket.on("close", () => this.onClose(1006, ""));
4164
+ socket.on("error", (err) => this.onError(err));
4165
+ socket.on("drain", () => this.onDrain());
4166
+ }
4167
+ send(data) {
4168
+ if (this.readyState !== 1)
4169
+ return -1;
4170
+ let payload;
4171
+ let isText = true;
4172
+ if (typeof data === "string") {
4173
+ payload = Buffer.from(data, "utf8");
4174
+ isText = true;
4175
+ } else if (Buffer.isBuffer(data)) {
4176
+ payload = data;
4177
+ isText = false;
4178
+ } else if (ArrayBuffer.isView(data)) {
4179
+ payload = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
4180
+ isText = false;
4181
+ } else {
4182
+ payload = Buffer.from(String(data), "utf8");
4183
+ isText = true;
4184
+ }
4185
+ this.sendFrame(isText ? 1 : 2, payload);
4186
+ return payload.length;
4187
+ }
4188
+ subscribe(room) {
4189
+ let set = nodeTopics.get(room);
4190
+ if (!set) {
4191
+ set = new Set;
4192
+ nodeTopics.set(room, set);
4193
+ }
4194
+ set.add(this);
4195
+ this.topics.add(room);
4196
+ }
4197
+ unsubscribe(room) {
4198
+ const set = nodeTopics.get(room);
4199
+ if (set) {
4200
+ set.delete(this);
4201
+ if (set.size === 0)
4202
+ nodeTopics.delete(room);
4203
+ }
4204
+ this.topics.delete(room);
4205
+ }
4206
+ isSubscribed(room) {
4207
+ return this.topics.has(room);
4208
+ }
4209
+ publish(room, message, _compress) {
4210
+ const set = nodeTopics.get(room);
4211
+ if (!set || set.size === 0)
4212
+ return 0;
4213
+ let sent = 0;
4214
+ for (const client of set) {
4215
+ if (client !== this && client.readyState === 1) {
4216
+ client.send(message);
4217
+ sent++;
4218
+ }
4219
+ }
4220
+ return sent;
4221
+ }
4222
+ ping(data = "") {
4223
+ if (this.readyState !== 1)
4224
+ return;
4225
+ const buf = typeof data === "string" ? Buffer.from(data, "utf8") : data;
4226
+ this.sendFrame(9, buf);
4227
+ }
4228
+ pong(data = "") {
4229
+ if (this.readyState !== 1)
4230
+ return;
4231
+ const buf = typeof data === "string" ? Buffer.from(data, "utf8") : data;
4232
+ this.sendFrame(10, buf);
4233
+ }
4234
+ cork(callback) {
4235
+ return callback(this);
4236
+ }
4237
+ close(code = 1000, reason = "") {
4238
+ if (this.readyState >= 2)
4239
+ return;
4240
+ this.readyState = 2;
4241
+ const reasonBuf = Buffer.from(reason, "utf8");
4242
+ const payload = Buffer.allocUnsafe(2 + reasonBuf.length);
4243
+ payload.writeUInt16BE(code, 0);
4244
+ reasonBuf.copy(payload, 2);
4245
+ this.sendFrame(8, payload);
4246
+ this.socket.end();
4247
+ }
4248
+ terminate() {
4249
+ this.readyState = 3;
4250
+ this.socket.destroy();
4251
+ }
4252
+ sendFrame(opcode, payload) {
4253
+ if (this.socket.destroyed)
4254
+ return;
4255
+ const len = payload.length;
4256
+ let header;
4257
+ if (len <= 125) {
4258
+ header = Buffer.allocUnsafe(2);
4259
+ header[0] = 128 | opcode & 15;
4260
+ header[1] = len;
4261
+ } else if (len <= 65535) {
4262
+ header = Buffer.allocUnsafe(4);
4263
+ header[0] = 128 | opcode & 15;
4264
+ header[1] = 126;
4265
+ header.writeUInt16BE(len, 2);
4266
+ } else {
4267
+ header = Buffer.allocUnsafe(10);
4268
+ header[0] = 128 | opcode & 15;
4269
+ header[1] = 127;
4270
+ header.writeBigUInt64BE(BigInt(len), 2);
4271
+ }
4272
+ this.socket.write(Buffer.concat([header, payload]));
4273
+ }
4274
+ onData(chunk) {
4275
+ this.buffer = this.buffer.length === 0 ? chunk : Buffer.concat([this.buffer, chunk]);
4276
+ while (this.buffer.length >= 2) {
4277
+ const byte0 = this.buffer[0];
4278
+ const byte1 = this.buffer[1];
4279
+ const fin = (byte0 & 128) !== 0;
4280
+ const opcode = byte0 & 15;
4281
+ const masked = (byte1 & 128) !== 0;
4282
+ if (!masked) {
4283
+ this.close(1002, "Protocol error: unmasked client frame");
4284
+ this.onClose(1002, "Protocol error: unmasked client frame");
4285
+ return;
4286
+ }
4287
+ let payloadLen = byte1 & 127;
4288
+ let offset = 2;
4289
+ if (payloadLen === 126) {
4290
+ if (this.buffer.length < 4)
4291
+ return;
4292
+ payloadLen = this.buffer.readUInt16BE(2);
4293
+ offset = 4;
4294
+ } else if (payloadLen === 127) {
4295
+ if (this.buffer.length < 10)
4296
+ return;
4297
+ const high = this.buffer.readUInt32BE(2);
4298
+ const low = this.buffer.readUInt32BE(6);
4299
+ payloadLen = high * 4294967296 + low;
4300
+ offset = 10;
4301
+ }
4302
+ if (payloadLen > this.maxPayloadLength) {
4303
+ this.close(1009, "Message Too Big");
4304
+ return;
4305
+ }
4306
+ const maskLen = 4;
4307
+ const totalLen = offset + maskLen + payloadLen;
4308
+ if (this.buffer.length < totalLen)
4309
+ return;
4310
+ const maskKey = this.buffer.subarray(offset, offset + 4);
4311
+ const rawPayload = this.buffer.subarray(offset + maskLen, totalLen);
4312
+ const payload = Buffer.allocUnsafe(payloadLen);
4313
+ for (let i = 0;i < payloadLen; i++) {
4314
+ payload[i] = rawPayload[i] ^ maskKey[i & 3];
4315
+ }
4316
+ this.buffer = this.buffer.subarray(totalLen);
4317
+ if (opcode === 8) {
4318
+ let code = 1000;
4319
+ let reason = "";
4320
+ if (payload.length >= 2) {
4321
+ code = payload.readUInt16BE(0);
4322
+ if (payload.length > 2) {
4323
+ reason = payload.subarray(2).toString("utf8");
4324
+ }
4325
+ }
4326
+ if (this.readyState === 1) {
4327
+ this.close(code, reason);
4328
+ }
4329
+ this.onClose(code, reason);
4330
+ return;
4331
+ }
4332
+ if (opcode === 9) {
4333
+ this.sendFrame(10, payload);
4334
+ continue;
4335
+ }
4336
+ if (opcode === 10) {
4337
+ continue;
4338
+ }
4339
+ if (!fin) {
4340
+ if (opcode !== 0) {
4341
+ this.fragmentOpcode = opcode;
4342
+ this.fragments = [payload];
4343
+ } else {
4344
+ this.fragments.push(payload);
4345
+ }
4346
+ continue;
4347
+ }
4348
+ let fullPayload = payload;
4349
+ let effectiveOpcode = opcode;
4350
+ if (opcode === 0) {
4351
+ this.fragments.push(payload);
4352
+ fullPayload = Buffer.concat(this.fragments);
4353
+ effectiveOpcode = this.fragmentOpcode;
4354
+ this.fragments = [];
4355
+ this.fragmentOpcode = 0;
4356
+ }
4357
+ const message = effectiveOpcode === 1 ? fullPayload.toString("utf8") : fullPayload;
4358
+ this.onMessage(message);
4359
+ }
4360
+ }
4361
+ dispatchOpen() {
4362
+ try {
4363
+ this.handlers?.open?.(this);
4364
+ this.appHandlers?.open?.(this);
4365
+ } catch (err) {
4366
+ this.onError(err);
4367
+ }
4368
+ }
4369
+ onMessage(msg) {
4370
+ try {
4371
+ this.handlers?.message?.(this, msg);
4372
+ this.appHandlers?.message?.(this, msg);
4373
+ } catch (err) {
4374
+ this.onError(err);
4375
+ }
4376
+ }
4377
+ onClose(code, reason) {
4378
+ if (this.readyState === 3)
4379
+ return;
4380
+ this.readyState = 3;
4381
+ for (const room of this.topics) {
4382
+ const set = nodeTopics.get(room);
4383
+ if (set) {
4384
+ set.delete(this);
4385
+ if (set.size === 0)
4386
+ nodeTopics.delete(room);
4387
+ }
4388
+ }
4389
+ this.topics.clear();
4390
+ try {
4391
+ this.handlers?.close?.(this, code, reason);
4392
+ this.appHandlers?.close?.(this, code, reason);
4393
+ } catch (err) {
4394
+ this.onError(err);
4395
+ }
4396
+ }
4397
+ onError(err) {
4398
+ try {
4399
+ if (this.handlers?.error) {
4400
+ this.handlers.error(this, err);
4401
+ } else if (this.appHandlers?.error) {
4402
+ this.appHandlers.error(this, err);
4403
+ }
4404
+ } catch (e) {
4405
+ console.error("Unhandled WebSocket error:", e);
4406
+ }
4407
+ }
4408
+ onDrain() {
4409
+ try {
4410
+ this.handlers?.drain?.(this);
4411
+ this.appHandlers?.drain?.(this);
4412
+ } catch (err) {
4413
+ this.onError(err);
4414
+ }
4415
+ }
4416
+ }
4417
+ function resolveTlsData(input) {
4418
+ if (!input)
4419
+ return;
4420
+ if (Buffer.isBuffer(input) || typeof input === "string") {
4421
+ if (typeof input === "string" && !input.includes(`
4422
+ `) && (input.startsWith("./") || input.startsWith("/") || input.includes("."))) {
4423
+ try {
4424
+ if (fs.existsSync(input)) {
4425
+ return fs.readFileSync(input);
4426
+ }
4427
+ } catch {}
4428
+ }
4429
+ return input;
4430
+ }
4431
+ return;
4432
+ }
4433
+ if (isNode) {
4434
+ if (typeof globalThis.Bun === "undefined") {
4435
+ Object.defineProperty(globalThis, "Bun", {
4436
+ configurable: true,
4437
+ value: {
4438
+ env: process.env,
4439
+ CryptoHasher: class {
4440
+ hmac;
4441
+ constructor(_algo, secret) {
4442
+ this.hmac = crypto.createHmac("sha256", secret);
4443
+ }
4444
+ update(data) {
4445
+ this.hmac.update(data);
4446
+ return this;
4447
+ }
4448
+ digest(encoding) {
4449
+ return this.hmac.digest(encoding);
4450
+ }
4451
+ }
4452
+ }
4453
+ });
4454
+ }
4455
+ App.prototype.listen = function(port) {
4456
+ const app = this;
4457
+ const rawPort = port ?? app._options?.port ?? 3000;
4458
+ const hostname = app._options?.hostname ?? "0.0.0.0";
4459
+ const activeSockets = new Set;
4460
+ let inFlightRequests = 0;
4461
+ let isDraining = false;
4462
+ const fastRoutes = new Map;
4463
+ if (app.nativeRoutes && !app.hasMiddlewares && app.errorResolver === undefined) {
4464
+ for (const nr of app.nativeRoutes) {
4465
+ if (!nr.isDynamic && nr.isContextFree && nr.rawHandler) {
4466
+ fastRoutes.set(`${nr.method}:${nr.pattern}`, nr.rawHandler);
4467
+ }
4468
+ }
4469
+ }
4470
+ const requestListener = async (req, res) => {
4471
+ inFlightRequests++;
4472
+ if (isDraining) {
4473
+ res.setHeader("Connection", "close");
4474
+ }
4475
+ const onFinished = () => {
4476
+ inFlightRequests--;
4477
+ res.removeListener("finish", onFinished);
4478
+ res.removeListener("close", onFinished);
4479
+ };
4480
+ res.on("finish", onFinished);
4481
+ res.on("close", onFinished);
4482
+ const method = req.method || "GET";
4483
+ const rawUrl = req.url || "/";
4484
+ const pathname = scanPathname(rawUrl);
4485
+ const fastHandler = fastRoutes.get(`${method}:${pathname}`);
4486
+ if (fastHandler) {
4487
+ try {
4488
+ const val = fastHandler();
4489
+ if (typeof val === "string") {
4490
+ res.writeHead(200, {
4491
+ "content-type": "text/plain; charset=utf-8"
4492
+ });
4493
+ res.end(val);
4494
+ return;
4495
+ }
4496
+ if (typeof val === "object" && val !== null && !(val instanceof Response)) {
4497
+ res.writeHead(200, {
4498
+ "content-type": "application/json; charset=utf-8"
4499
+ });
4500
+ res.end(JSON.stringify(val));
4501
+ return;
4502
+ }
4503
+ } catch {}
4504
+ }
4505
+ try {
4506
+ const protocol = req.socket?.encrypted ? "https" : "http";
4507
+ const host = req.headers.host || "localhost";
4508
+ const url = `${protocol}://${host}${rawUrl}`;
4509
+ let reqBody;
4510
+ if (method !== "GET" && method !== "HEAD") {
4511
+ reqBody = Readable.toWeb(req);
4512
+ }
4513
+ const webReq = new Request(url, {
4514
+ method,
4515
+ headers: req.headers,
4516
+ body: reqBody,
4517
+ duplex: "half"
4518
+ });
4519
+ const remoteIp = req.socket.remoteAddress || "";
4520
+ let upgraded = false;
4521
+ const serverShim = {
4522
+ requestIP: () => remoteIp ? { address: remoteIp } : null,
4523
+ upgrade: (_request, options) => {
4524
+ const secKey = req.headers["sec-websocket-key"];
4525
+ if (!secKey || typeof secKey !== "string")
4526
+ return false;
4527
+ const acceptKey = crypto.createHash("sha1").update(secKey + WS_GUID).digest("base64");
4528
+ req.socket.write(`HTTP/1.1 101 Switching Protocols\r
4529
+ ` + `Upgrade: websocket\r
4530
+ ` + `Connection: Upgrade\r
4531
+ ` + `Sec-WebSocket-Accept: ${acceptKey}\r
4532
+ \r
4533
+ `);
4534
+ const ws = new NodeServerWebSocket(req.socket, options?.data, app._options?.websocket);
4535
+ upgraded = true;
4536
+ ws.dispatchOpen();
4537
+ return true;
4538
+ }
4539
+ };
4540
+ const webRes = await app.handle(webReq, serverShim);
4541
+ if (upgraded)
4542
+ return;
4543
+ const resHeaders = {};
4544
+ webRes.headers.forEach((val, key) => {
4545
+ resHeaders[key] = val;
4546
+ });
4547
+ const getSetCookie = webRes.headers.getSetCookie;
4548
+ if (typeof getSetCookie === "function") {
4549
+ const cookies = getSetCookie.call(webRes.headers);
4550
+ if (cookies && cookies.length > 0) {
4551
+ resHeaders["set-cookie"] = cookies;
4552
+ }
4553
+ }
4554
+ res.writeHead(webRes.status, webRes.statusText || undefined, resHeaders);
4555
+ if (webRes.body) {
4556
+ const nodeStream = Readable.fromWeb(webRes.body);
4557
+ nodeStream.pipe(res);
4558
+ } else {
4559
+ res.end();
4560
+ }
4561
+ } catch (err) {
4562
+ console.error("Barq Node Adapter Error:", err);
4563
+ if (!res.headersSent) {
4564
+ res.writeHead(500, {
4565
+ "content-type": "application/json; charset=utf-8"
4566
+ });
4567
+ res.end('{"error":"Internal Server Error"}');
4568
+ }
4569
+ }
4570
+ };
4571
+ const tlsConfig = app._options?.tls;
4572
+ const hasTls = Boolean(tlsConfig && (tlsConfig.key || tlsConfig.cert));
4573
+ const server = hasTls ? https.createServer({
4574
+ key: resolveTlsData(tlsConfig?.key),
4575
+ cert: resolveTlsData(tlsConfig?.cert),
4576
+ ca: resolveTlsData(tlsConfig?.ca),
4577
+ passphrase: tlsConfig?.passphrase
4578
+ }, requestListener) : http.createServer(requestListener);
4579
+ server.on("connection", (socket) => {
4580
+ activeSockets.add(socket);
4581
+ socket.on("close", () => activeSockets.delete(socket));
4582
+ });
4583
+ server.on("upgrade", async (req, socket, head) => {
4584
+ activeSockets.add(socket);
4585
+ socket.on("close", () => activeSockets.delete(socket));
4586
+ const protocol = socket?.encrypted ? "https" : "http";
4587
+ const host = req.headers.host || "localhost";
4588
+ const fullUrl = `${protocol}://${host}${req.url || "/"}`;
4589
+ let upgradedSocket = null;
4590
+ const serverShim = {
4591
+ requestIP: () => ({
4592
+ address: ("remoteAddress" in socket ? socket.remoteAddress : "") || ""
4593
+ }),
4594
+ upgrade: (_request, options) => {
4595
+ const secKey = req.headers["sec-websocket-key"];
4596
+ if (!secKey || typeof secKey !== "string")
4597
+ return false;
4598
+ const acceptKey = crypto.createHash("sha1").update(secKey + WS_GUID).digest("base64");
4599
+ socket.write(`HTTP/1.1 101 Switching Protocols\r
4600
+ ` + `Upgrade: websocket\r
4601
+ ` + `Connection: Upgrade\r
4602
+ ` + `Sec-WebSocket-Accept: ${acceptKey}\r
4603
+ \r
4604
+ `);
4605
+ const ws = new NodeServerWebSocket(socket, options?.data, app._options?.websocket);
4606
+ upgradedSocket = ws;
4607
+ if (head && head.length > 0) {
4608
+ socket.unshift(head);
4609
+ }
4610
+ ws.dispatchOpen();
4611
+ return true;
4612
+ }
4613
+ };
4614
+ const webReq = new Request(fullUrl, {
4615
+ method: "GET",
4616
+ headers: req.headers
4617
+ });
4618
+ try {
4619
+ const webRes = await app.handle(webReq, serverShim);
4620
+ if (!upgradedSocket) {
4621
+ const status = webRes.status || 400;
4622
+ const statusText = webRes.statusText || "Bad Request";
4623
+ socket.write(`HTTP/1.1 ${status} ${statusText}\r
4624
+ Connection: close\r
4625
+ \r
4626
+ `);
4627
+ socket.destroy();
4628
+ }
4629
+ } catch {
4630
+ if (!upgradedSocket) {
4631
+ socket.write(`HTTP/1.1 500 Internal Server Error\r
4632
+ Connection: close\r
4633
+ \r
4634
+ `);
4635
+ socket.destroy();
4636
+ }
4637
+ }
4638
+ });
4639
+ server.listen(rawPort, hostname);
4640
+ const serverHandle = {
4641
+ get port() {
4642
+ const addr = server.address();
4643
+ return addr && typeof addr === "object" ? addr.port : rawPort;
4644
+ },
4645
+ hostname,
4646
+ stop: (hardTimeoutMs) => new Promise((resolve) => {
4647
+ if (hardTimeoutMs === true) {
4648
+ for (const socket of activeSockets) {
4649
+ socket.destroy();
4650
+ }
4651
+ activeSockets.clear();
4652
+ server.close(() => resolve({ forced: true, pending: 0 }));
4653
+ return;
4654
+ }
4655
+ isDraining = true;
4656
+ const timeout = typeof hardTimeoutMs === "number" ? hardTimeoutMs : 5000;
4657
+ let timer;
4658
+ let resolved = false;
4659
+ const done = (forced) => {
4660
+ if (resolved)
4661
+ return;
4662
+ resolved = true;
4663
+ if (timer !== undefined)
4664
+ clearTimeout(timer);
4665
+ const pending = activeSockets.size;
4666
+ if (forced) {
4667
+ for (const socket of activeSockets) {
4668
+ socket.destroy();
4669
+ }
4670
+ activeSockets.clear();
4671
+ }
4672
+ server.close(() => resolve({ forced, pending: forced ? pending : 0 }));
4673
+ };
4674
+ timer = setTimeout(() => done(true), timeout);
4675
+ if (typeof timer.unref === "function")
4676
+ timer.unref();
4677
+ server.close(() => {
4678
+ if (!resolved) {
4679
+ resolved = true;
4680
+ if (timer !== undefined)
4681
+ clearTimeout(timer);
4682
+ resolve({ forced: false, pending: 0 });
4683
+ }
4684
+ });
4685
+ if (inFlightRequests === 0) {
4686
+ done(false);
4687
+ }
4688
+ })
4689
+ };
4690
+ return serverHandle;
4691
+ };
4692
+ App.prototype.cluster = function(port) {
4693
+ const app = this;
4694
+ const rawPort = port ?? app._options?.port ?? 3000;
4695
+ const hostname = app._options?.hostname ?? "0.0.0.0";
4696
+ const listenPort = rawPort === 0 ? 3000 : rawPort;
4697
+ if (cluster.isPrimary) {
4698
+ const numCPUs = cpus2().length;
4699
+ const workers = [];
4700
+ let crashCount = 0;
4701
+ let lastReset = Date.now();
4702
+ const spawnWorker = () => {
4703
+ const worker = cluster.fork({
4704
+ ...process.env,
4705
+ PORT: String(listenPort)
4706
+ });
4707
+ worker.on("exit", () => {
4708
+ const now = Date.now();
4709
+ if (now - lastReset > 5000) {
4710
+ crashCount = 0;
4711
+ lastReset = now;
4712
+ }
4713
+ crashCount++;
4714
+ const idx = workers.indexOf(worker);
4715
+ if (idx !== -1)
4716
+ workers.splice(idx, 1);
4717
+ if (crashCount > 15) {
4718
+ console.error("[Barq Cluster] Node workers restarting too fast. Throttling respawn.");
4719
+ setTimeout(() => {
4720
+ workers.push(spawnWorker());
4721
+ }, 2000);
4722
+ return;
4723
+ }
4724
+ workers.push(spawnWorker());
4725
+ });
4726
+ return worker;
4727
+ };
4728
+ for (let i = 0;i < numCPUs; i++) {
4729
+ workers.push(spawnWorker());
4730
+ }
4731
+ return {
4732
+ port: listenPort,
4733
+ hostname,
4734
+ stop: async () => {
4735
+ for (const w of workers) {
4736
+ w.kill("SIGTERM");
4737
+ }
4738
+ }
4739
+ };
4740
+ }
4741
+ return this.listen(listenPort);
4742
+ };
4743
+ }
4744
+ // src/cors.ts
4745
+ function cors(options = {}) {
4746
+ const methods = (options.methods ?? ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH"]).join(", ");
4747
+ const allowedHeaders = options.allowedHeaders?.join(", ");
4748
+ const exposedHeaders = options.exposedHeaders?.join(", ");
4749
+ const maxAge = options.maxAge !== undefined ? String(options.maxAge) : null;
4750
+ const credentials = options.credentials === true;
4751
+ function resolveOrigin(reqOrigin) {
4752
+ if (!options.origin || options.origin === "*") {
4753
+ return credentials ? reqOrigin ?? "*" : "*";
4754
+ }
4755
+ if (!reqOrigin)
4756
+ return null;
4757
+ if (typeof options.origin === "string") {
4758
+ return options.origin === reqOrigin ? reqOrigin : null;
4759
+ }
4760
+ if (Array.isArray(options.origin)) {
4761
+ return options.origin.includes(reqOrigin) ? reqOrigin : null;
4762
+ }
4763
+ if (typeof options.origin === "function") {
4764
+ const result = options.origin(reqOrigin);
4765
+ if (typeof result === "string")
4766
+ return result;
4767
+ return result ? reqOrigin : null;
4768
+ }
4769
+ return null;
4770
+ }
4771
+ function setCorsHeaders(headers, matchedOrigin) {
4772
+ if (matchedOrigin) {
4773
+ headers.set("access-control-allow-origin", matchedOrigin);
4774
+ if (matchedOrigin !== "*") {
4775
+ headers.append("vary", "Origin");
4776
+ }
4777
+ }
4778
+ if (credentials) {
4779
+ headers.set("access-control-allow-credentials", "true");
4780
+ }
4781
+ if (exposedHeaders) {
4782
+ headers.set("access-control-expose-headers", exposedHeaders);
4783
+ }
4784
+ }
4785
+ return {
4786
+ before(ctx) {
4787
+ const reqOrigin = ctx.req.headers.get("origin");
4788
+ const matchedOrigin = resolveOrigin(reqOrigin);
4789
+ if (ctx.req.method === "OPTIONS") {
4790
+ const headers = new Headers;
4791
+ setCorsHeaders(headers, matchedOrigin);
4792
+ headers.set("access-control-allow-methods", methods);
4793
+ if (allowedHeaders) {
4794
+ headers.set("access-control-allow-headers", allowedHeaders);
4795
+ } else {
4796
+ const reqHeaders = ctx.req.headers.get("access-control-request-headers");
4797
+ if (reqHeaders) {
4798
+ headers.set("access-control-allow-headers", reqHeaders);
4799
+ }
4800
+ }
4801
+ if (maxAge) {
4802
+ headers.set("access-control-max-age", maxAge);
4803
+ }
4804
+ headers.set("content-length", "0");
4805
+ return new Response(null, { status: 204, headers });
4806
+ }
4807
+ ctx.state._corsOrigin = matchedOrigin;
4808
+ },
4809
+ after(ctx, res) {
4810
+ const matchedOrigin = ctx.state._corsOrigin;
4811
+ if (matchedOrigin !== undefined) {
4812
+ const headers = new Headers(res.headers);
4813
+ setCorsHeaders(headers, matchedOrigin);
4814
+ return new Response(res.body, {
4815
+ status: res.status,
4816
+ statusText: res.statusText,
4817
+ headers
4818
+ });
4819
+ }
4820
+ return res;
4821
+ }
4822
+ };
4823
+ }
4824
+ // src/validation.ts
4825
+ function validateJson(validator, handler) {
4826
+ return async (ctx) => {
4827
+ const raw = await ctx.json();
4828
+ let body;
4829
+ if (typeof validator === "object" && validator !== null && "~standard" in validator) {
4830
+ const res = await validator["~standard"].validate(raw);
4831
+ if (res.issues) {
4832
+ throw new HttpError(422, {
4833
+ error: "Validation Failed",
4834
+ issues: res.issues
4835
+ });
4836
+ }
4837
+ body = res.value;
4838
+ } else if (typeof validator === "function") {
4839
+ body = await validator(raw);
4840
+ } else if (typeof validator === "object" && validator !== null && "parse" in validator) {
4841
+ body = validator.parse(raw);
4842
+ } else {
4843
+ throw new TypeError("Invalid validator provided to validateJson");
4844
+ }
4845
+ return handler(ctx, body);
4846
+ };
4847
+ }
4848
+ export {
4849
+ App,
4850
+ Context,
4851
+ HttpError,
4852
+ RouteGroup,
4853
+ composeMiddlewareDispatcher,
4854
+ composeMiddlewares,
4855
+ cors,
4856
+ createCookieJar,
4857
+ createErrorResponse,
4858
+ empty,
4859
+ errorToResponse,
4860
+ isThenable,
4861
+ json,
4862
+ parseRequestTarget,
4863
+ redirect,
4864
+ runPipeline,
4865
+ text,
4866
+ unwindAfter,
4867
+ validateJson
4868
+ };
4869
+
4870
+ //# debugId=9C2F2B32771A43B764756E2164756E21