@adonix.org/cloud-spark 0.0.99 → 0.0.100

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,2 +1,10 @@
1
1
  # ⚡️ cloud-spark
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@adonix.org/cloud-spark.svg?color=blue)](https://www.npmjs.com/package/@adonix.org/cloud-spark)
4
+ [![Apache 2.0 License](/img/badge-license.svg)](https://github.com/adonix-org/cloud-spark/blob/main/LICENSE)
5
+ [![Build](https://github.com/adonix-org/cloud-spark/actions/workflows/build.yml/badge.svg)](https://github.com/adonix-org/postrise/actions/workflows/build.yml)
6
+ [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=adonix-org_cloud-spark&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=adonix-org_cloud-spark)
7
+ [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=adonix-org_cloud-spark&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=adonix-org_cloud-spark)
8
+ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=adonix-org_cloud-spark&metric=coverage)](https://sonarcloud.io/summary/new_code?id=adonix-org_cloud-spark)
9
+
2
10
  Ignite your Cloudflare Workers with a type-safe library for rapid development.
package/dist/index.d.ts CHANGED
@@ -157,6 +157,15 @@ declare function mergeHeader(headers: Headers, key: string, value: string | stri
157
157
  * @returns A normalized URL string suitable for hashing or direct cache key use.
158
158
  */
159
159
  declare function normalizeUrl(url: string): URL;
160
+ /**
161
+ * Deterministic ASCII comparison of HTTP token strings.
162
+ *
163
+ * Use this for header names, header values, or query parameter keys
164
+ * that are restricted to ASCII per the HTTP spec (RFC 9110 / RFC 3986).
165
+ *
166
+ * Note: This comparator is NOT for natural language strings.
167
+ */
168
+ declare function httpTokenCompare(a: string, b: string): number;
160
169
  /**
161
170
  * Extracts the `Origin` header value from a request.
162
171
  *
@@ -169,7 +178,7 @@ declare function normalizeUrl(url: string): URL;
169
178
  declare function getOrigin(request: Request): string | null;
170
179
 
171
180
  /**
172
- * Provides information about the CORS policy for the current request.
181
+ * Implementations will provide a specific CORS policy.
173
182
  */
174
183
  interface CorsProvider {
175
184
  /** Returns a list of allowed origins. */
@@ -221,7 +230,7 @@ declare function addCorsHeaders(origin: string | null, cors: CorsProvider, heade
221
230
  * @param ctx - The `ExecutionContext` for the worker invocation.
222
231
  * @returns An instance of the worker type `T`.
223
232
  */
224
- type WorkerConstructor<T extends Worker = Worker> = new (req: Request, env: Env, ctx: ExecutionContext) => T;
233
+ type WorkerConstructor<T extends Worker = Worker> = new (request: Request, env: Env, ctx: ExecutionContext) => T;
225
234
  /**
226
235
  * Defines the contract for a Cloudflare-compatible Worker.
227
236
  *
@@ -251,63 +260,57 @@ interface Worker {
251
260
  get ctx(): ExecutionContext;
252
261
  }
253
262
 
254
- /**
255
- * A {@link Worker} that also implements {@link CorsProvider}.
256
- *
257
- * Used by response builders that require both Worker
258
- * and CORS functionality.
259
- */
260
- type CorsWorker$1 = Worker & CorsProvider;
263
+ type CorsWorker = Worker & CorsProvider;
261
264
  declare abstract class BaseResponse {
262
- readonly worker: CorsWorker$1;
263
265
  headers: Headers;
264
- body: BodyInit | null;
265
266
  status: StatusCodes;
266
267
  statusText?: string;
267
268
  mediaType?: MediaType;
268
- constructor(worker: CorsWorker$1, content?: BodyInit | null);
269
269
  protected get responseInit(): ResponseInit;
270
270
  setHeader(key: string, value: string | string[]): void;
271
271
  mergeHeader(key: string, value: string | string[]): void;
272
272
  addContentType(): void;
273
273
  }
274
274
  declare abstract class CorsResponse extends BaseResponse {
275
- constructor(worker: CorsWorker$1, content?: BodyInit | null);
275
+ readonly worker: CorsWorker;
276
+ constructor(worker: CorsWorker);
276
277
  protected addCorsHeaders(): void;
277
278
  protected getOrigin(): string | null;
278
279
  }
279
280
  declare abstract class CacheResponse extends CorsResponse {
280
281
  cache?: CacheControl | undefined;
281
- constructor(worker: CorsWorker$1, body?: BodyInit | null, cache?: CacheControl | undefined);
282
- protected addCacheHeaders(): void;
282
+ constructor(worker: CorsWorker, cache?: CacheControl | undefined);
283
+ protected addCacheHeader(): void;
283
284
  }
284
285
  declare abstract class WorkerResponse extends CacheResponse {
285
- createResponse(): Response;
286
+ private readonly body;
287
+ constructor(worker: CorsWorker, body?: BodyInit | null, cache?: CacheControl);
288
+ getResponse(): Response;
286
289
  protected addSecurityHeaders(): void;
287
290
  }
288
291
  declare class ClonedResponse extends WorkerResponse {
289
- constructor(worker: CorsWorker$1, response: Response, cache?: CacheControl);
292
+ constructor(worker: CorsWorker, response: Response, cache?: CacheControl);
290
293
  }
291
294
  declare class SuccessResponse extends WorkerResponse {
292
- constructor(worker: CorsWorker$1, body?: BodyInit | null, cache?: CacheControl, status?: StatusCodes);
295
+ constructor(worker: CorsWorker, body?: BodyInit | null, cache?: CacheControl, status?: StatusCodes);
293
296
  }
294
297
  declare class JsonResponse extends SuccessResponse {
295
- constructor(worker: CorsWorker$1, json?: unknown, cache?: CacheControl, status?: StatusCodes);
298
+ constructor(worker: CorsWorker, json?: unknown, cache?: CacheControl, status?: StatusCodes);
296
299
  }
297
300
  declare class HtmlResponse extends SuccessResponse {
298
- constructor(worker: CorsWorker$1, body: string, cache?: CacheControl, status?: StatusCodes);
301
+ constructor(worker: CorsWorker, body: string, cache?: CacheControl, status?: StatusCodes);
299
302
  }
300
303
  declare class TextResponse extends SuccessResponse {
301
- constructor(worker: CorsWorker$1, content: string, cache?: CacheControl, status?: StatusCodes);
304
+ constructor(worker: CorsWorker, content: string, cache?: CacheControl, status?: StatusCodes);
302
305
  }
303
306
  /**
304
307
  * Removes the body from a GET response.
305
308
  */
306
309
  declare class Head extends WorkerResponse {
307
- constructor(worker: CorsWorker$1, get: Response);
310
+ constructor(worker: CorsWorker, get: Response);
308
311
  }
309
312
  declare class Options extends SuccessResponse {
310
- constructor(worker: CorsWorker$1);
313
+ constructor(worker: CorsWorker);
311
314
  }
312
315
 
313
316
  interface ErrorJson {
@@ -317,39 +320,34 @@ interface ErrorJson {
317
320
  }
318
321
  declare class HttpError extends JsonResponse {
319
322
  protected readonly details?: string | undefined;
320
- constructor(worker: CorsWorker$1, status: StatusCodes, details?: string | undefined);
321
- get json(): ErrorJson;
322
- createResponse(): Response;
323
+ constructor(worker: CorsWorker, status: StatusCodes, details?: string | undefined);
323
324
  }
324
325
  declare class BadRequest extends HttpError {
325
- constructor(worker: CorsWorker$1, details?: string);
326
+ constructor(worker: CorsWorker, details?: string);
326
327
  }
327
328
  declare class Unauthorized extends HttpError {
328
- constructor(worker: CorsWorker$1, details?: string);
329
+ constructor(worker: CorsWorker, details?: string);
329
330
  }
330
331
  declare class Forbidden extends HttpError {
331
- constructor(worker: CorsWorker$1, details?: string);
332
+ constructor(worker: CorsWorker, details?: string);
332
333
  }
333
334
  declare class NotFound extends HttpError {
334
- constructor(worker: CorsWorker$1, details?: string);
335
+ constructor(worker: CorsWorker, details?: string);
335
336
  }
336
337
  declare class MethodNotAllowed extends HttpError {
337
- constructor(worker: CorsWorker$1);
338
- get json(): ErrorJson & {
339
- allowed: Method[];
340
- };
338
+ constructor(worker: CorsWorker);
341
339
  }
342
340
  declare class InternalServerError extends HttpError {
343
- constructor(worker: CorsWorker$1, details?: string);
341
+ constructor(worker: CorsWorker, details?: string);
344
342
  }
345
343
  declare class NotImplemented extends HttpError {
346
- constructor(worker: CorsWorker$1, details?: string);
344
+ constructor(worker: CorsWorker, details?: string);
347
345
  }
348
346
  declare class MethodNotImplemented extends NotImplemented {
349
- constructor(worker: CorsWorker$1);
347
+ constructor(worker: CorsWorker);
350
348
  }
351
349
  declare class ServiceUnavailable extends HttpError {
352
- constructor(worker: CorsWorker$1, details?: string);
350
+ constructor(worker: CorsWorker, details?: string);
353
351
  }
354
352
 
355
353
  /**
@@ -483,7 +481,7 @@ declare abstract class BaseWorker implements Worker {
483
481
  * @param request - The {@link Request} to pass to the new worker instance.
484
482
  * @returns A new worker instance of the same subclass as `this`.
485
483
  */
486
- protected createWorker(request: Request): this;
484
+ protected create(request: Request): this;
487
485
  /**
488
486
  * Process the {@link Request} and produce a {@link Response}.
489
487
  *
@@ -515,7 +513,7 @@ declare abstract class BaseWorker implements Worker {
515
513
  *
516
514
  * Subclasses can override any of the methods to customize the CORS behavior.
517
515
  */
518
- declare abstract class CorsWorker extends BaseWorker implements CorsProvider {
516
+ declare abstract class BaseCorsWorker extends BaseWorker implements CorsProvider {
519
517
  getAllowOrigins(): string[];
520
518
  allowAnyOrigin(): boolean;
521
519
  getAllowMethods(): Method[];
@@ -534,7 +532,7 @@ declare abstract class CorsWorker extends BaseWorker implements CorsProvider {
534
532
  *
535
533
  * Subclasses should override `getCacheKey()` to customize cache key generation if needed.
536
534
  */
537
- declare abstract class CacheWorker extends CorsWorker {
535
+ declare abstract class CacheWorker extends BaseCorsWorker {
538
536
  /**
539
537
  * Returns the cache key for the current request.
540
538
  *
@@ -586,7 +584,7 @@ declare abstract class CacheWorker extends CorsWorker {
586
584
  * @returns {Response} A new Response with dynamic CORS headers applied.
587
585
  * @see {@link removeCacheHeaders}
588
586
  */
589
- private addCacheHeaders;
587
+ protected addCacheHeaders(cached: Response): Response;
590
588
  /**
591
589
  * Removes headers that should not be stored in the cache (currently only CORS headers).
592
590
  *
@@ -616,7 +614,7 @@ declare abstract class BasicWorker extends CacheWorker {
616
614
  protected delete(): Promise<Response>;
617
615
  protected options(): Promise<Response>;
618
616
  protected head(): Promise<Response>;
619
- protected getResponse<T extends WorkerResponse, Ctor extends new (worker: CorsWorker$1, ...args: any[]) => T>(ResponseClass: Ctor, ...args: ConstructorParameters<Ctor> extends [CorsWorker$1, ...infer R] ? R : never): Promise<Response>;
617
+ protected getResponse<T extends WorkerResponse, Ctor extends new (worker: CorsWorker, ...args: any[]) => T>(ResponseClass: Ctor, ...args: ConstructorParameters<Ctor> extends [CorsWorker, ...infer R] ? R : never): Promise<Response>;
620
618
  }
621
619
 
622
620
  declare abstract class RouteWorker extends BasicWorker {
@@ -631,4 +629,4 @@ declare abstract class RouteWorker extends BasicWorker {
631
629
  protected delete(): Promise<Response>;
632
630
  }
633
631
 
634
- export { BadRequest, BasicWorker, CacheControl, ClonedResponse, Cors, type CorsProvider, type CorsWorker$1 as CorsWorker, type ErrorJson, Forbidden, Head, HtmlResponse, HttpError, HttpHeader, InternalServerError, JsonResponse, MediaType, Method, MethodNotAllowed, MethodNotImplemented, NotFound, NotImplemented, Options, Route, type RouteCallback, type RouteTable, type RouteTuple, RouteWorker, Routes, ServiceUnavailable, SuccessResponse, TextResponse, Time, Unauthorized, type Worker, type WorkerConstructor, WorkerResponse, addCorsHeaders, getContentType, getOrigin, isMethod, mergeHeader, normalizeUrl, setHeader };
632
+ export { BadRequest, BasicWorker, CacheControl, ClonedResponse, Cors, type CorsProvider, type CorsWorker, type ErrorJson, Forbidden, Head, HtmlResponse, HttpError, HttpHeader, InternalServerError, JsonResponse, MediaType, Method, MethodNotAllowed, MethodNotImplemented, NotFound, NotImplemented, Options, Route, type RouteCallback, type RouteTable, type RouteTuple, RouteWorker, Routes, ServiceUnavailable, SuccessResponse, TextResponse, Time, Unauthorized, type Worker, type WorkerConstructor, WorkerResponse, addCorsHeaders, getContentType, getOrigin, httpTokenCompare, isMethod, mergeHeader, normalizeUrl, setHeader };
package/dist/index.js CHANGED
@@ -41,15 +41,15 @@ var Time = {
41
41
  Year: 31536e3
42
42
  // 60 * 60 * 24 * 365
43
43
  };
44
- var Method = /* @__PURE__ */ ((Method4) => {
45
- Method4["GET"] = "GET";
46
- Method4["PUT"] = "PUT";
47
- Method4["HEAD"] = "HEAD";
48
- Method4["POST"] = "POST";
49
- Method4["PATCH"] = "PATCH";
50
- Method4["DELETE"] = "DELETE";
51
- Method4["OPTIONS"] = "OPTIONS";
52
- return Method4;
44
+ var Method = /* @__PURE__ */ ((Method3) => {
45
+ Method3["GET"] = "GET";
46
+ Method3["PUT"] = "PUT";
47
+ Method3["HEAD"] = "HEAD";
48
+ Method3["POST"] = "POST";
49
+ Method3["PATCH"] = "PATCH";
50
+ Method3["DELETE"] = "DELETE";
51
+ Method3["OPTIONS"] = "OPTIONS";
52
+ return Method3;
53
53
  })(Method || {});
54
54
  var METHOD_SET = new Set(Object.values(Method));
55
55
  function isMethod(value) {
@@ -123,7 +123,7 @@ var ADD_CHARSET = /* @__PURE__ */ new Set([
123
123
  ]);
124
124
  function setHeader(headers, key, value) {
125
125
  const raw = Array.isArray(value) ? value : [value];
126
- const values = Array.from(new Set(raw.map((v) => v.trim()))).filter((v) => v.length).sort();
126
+ const values = Array.from(new Set(raw.map((v) => v.trim()))).filter((v) => v.length).sort(httpTokenCompare);
127
127
  if (!values.length) {
128
128
  headers.delete(key);
129
129
  return;
@@ -145,11 +145,16 @@ function mergeHeader(headers, key, value) {
145
145
  function normalizeUrl(url) {
146
146
  const u = new URL(url);
147
147
  const params = [...u.searchParams.entries()];
148
- params.sort(([a], [b]) => a.localeCompare(b));
148
+ params.sort(([a], [b]) => httpTokenCompare(a, b));
149
149
  u.search = params.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&");
150
150
  u.hash = "";
151
151
  return u;
152
152
  }
153
+ function httpTokenCompare(a, b) {
154
+ if (a < b) return -1;
155
+ if (a > b) return 1;
156
+ return 0;
157
+ }
153
158
  function getOrigin(request) {
154
159
  return request.headers.get(HttpHeader.ORIGIN);
155
160
  }
@@ -194,12 +199,7 @@ import { getReasonPhrase as getReasonPhrase2 } from "http-status-codes";
194
199
  // src/response.ts
195
200
  import { getReasonPhrase, StatusCodes as StatusCodes2 } from "http-status-codes";
196
201
  var BaseResponse = class {
197
- constructor(worker, content = null) {
198
- this.worker = worker;
199
- this.body = this.status === StatusCodes2.NO_CONTENT ? null : content;
200
- }
201
202
  headers = new Headers();
202
- body;
203
203
  status = StatusCodes2.OK;
204
204
  statusText;
205
205
  mediaType;
@@ -223,13 +223,14 @@ var BaseResponse = class {
223
223
  }
224
224
  };
225
225
  var CorsResponse = class extends BaseResponse {
226
- constructor(worker, content = null) {
227
- super(worker, content);
226
+ constructor(worker) {
227
+ super();
228
+ this.worker = worker;
228
229
  }
229
230
  addCorsHeaders() {
230
231
  addCorsHeaders(this.getOrigin(), this.worker, this.headers);
231
232
  if (!this.worker.allowAnyOrigin()) {
232
- mergeHeader(this.headers, HttpHeader.VARY, HttpHeader.ORIGIN);
233
+ this.mergeHeader(HttpHeader.VARY, HttpHeader.ORIGIN);
233
234
  }
234
235
  }
235
236
  getOrigin() {
@@ -237,20 +238,24 @@ var CorsResponse = class extends BaseResponse {
237
238
  }
238
239
  };
239
240
  var CacheResponse = class extends CorsResponse {
240
- constructor(worker, body = null, cache) {
241
- super(worker, body);
241
+ constructor(worker, cache) {
242
+ super(worker);
242
243
  this.cache = cache;
243
244
  }
244
- addCacheHeaders() {
245
+ addCacheHeader() {
245
246
  if (this.cache) {
246
247
  this.headers.set(HttpHeader.CACHE_CONTROL, CacheControl.stringify(this.cache));
247
248
  }
248
249
  }
249
250
  };
250
251
  var WorkerResponse = class extends CacheResponse {
251
- createResponse() {
252
+ constructor(worker, body = null, cache) {
253
+ super(worker, cache);
254
+ this.body = body;
255
+ }
256
+ getResponse() {
252
257
  this.addCorsHeaders();
253
- this.addCacheHeaders();
258
+ this.addCacheHeader();
254
259
  this.addSecurityHeaders();
255
260
  const body = this.status === StatusCodes2.NO_CONTENT ? null : this.body;
256
261
  if (body) this.addContentType();
@@ -309,19 +314,13 @@ var Options = class extends SuccessResponse {
309
314
  // src/errors.ts
310
315
  var HttpError = class extends JsonResponse {
311
316
  constructor(worker, status, details) {
312
- super(worker, void 0, CacheControl.DISABLE, status);
313
- this.details = details;
314
- }
315
- get json() {
316
- return {
317
- status: this.status,
318
- error: getReasonPhrase2(this.status),
319
- details: this.details ?? getReasonPhrase2(this.status)
317
+ const json = {
318
+ status,
319
+ error: getReasonPhrase2(status),
320
+ details: details ?? getReasonPhrase2(status)
320
321
  };
321
- }
322
- createResponse() {
323
- this.body = JSON.stringify(this.json);
324
- return super.createResponse();
322
+ super(worker, json, CacheControl.DISABLE, status);
323
+ this.details = details;
325
324
  }
326
325
  };
327
326
  var BadRequest = class extends HttpError {
@@ -353,12 +352,6 @@ var MethodNotAllowed = class extends HttpError {
353
352
  );
354
353
  this.setHeader(HttpHeader.ALLOW, this.worker.getAllowMethods());
355
354
  }
356
- get json() {
357
- return {
358
- ...super.json,
359
- allowed: this.worker.getAllowMethods()
360
- };
361
- }
362
355
  };
363
356
  var InternalServerError = class extends HttpError {
364
357
  constructor(worker, details) {
@@ -429,10 +422,9 @@ var Routes = class {
429
422
  match(method, url) {
430
423
  const pathname = new URL(url).pathname;
431
424
  for (const route of this) {
432
- if (route.method !== method) continue;
433
- const match = route.pattern.exec(pathname);
434
- if (match) {
435
- return { route, match };
425
+ if (route.method === method) {
426
+ const match = route.pattern.exec(pathname);
427
+ if (match) return { route, match };
436
428
  }
437
429
  }
438
430
  return void 0;
@@ -468,7 +460,7 @@ var BaseWorker = class {
468
460
  * @param request - The {@link Request} to pass to the new worker instance.
469
461
  * @returns A new worker instance of the same subclass as `this`.
470
462
  */
471
- createWorker(request) {
463
+ create(request) {
472
464
  const ctor = this.constructor;
473
465
  return new ctor(request, this.env, this.ctx);
474
466
  }
@@ -484,13 +476,13 @@ var BaseWorker = class {
484
476
  */
485
477
  static ignite() {
486
478
  return {
487
- fetch: (req, env, ctx) => new this(req, env, ctx).fetch()
479
+ fetch: (request, env, ctx) => new this(request, env, ctx).fetch()
488
480
  };
489
481
  }
490
482
  };
491
483
 
492
- // src/cors-worker.ts
493
- var CorsWorker2 = class extends BaseWorker {
484
+ // src/base-cors-worker.ts
485
+ var BaseCorsWorker = class extends BaseWorker {
494
486
  getAllowOrigins() {
495
487
  return ["*"];
496
488
  }
@@ -512,7 +504,7 @@ var CorsWorker2 = class extends BaseWorker {
512
504
  };
513
505
 
514
506
  // src/cache-worker.ts
515
- var CacheWorker = class extends CorsWorker2 {
507
+ var CacheWorker = class extends BaseCorsWorker {
516
508
  /**
517
509
  * Returns the cache key for the current request.
518
510
  *
@@ -621,6 +613,7 @@ var CacheWorker = class extends CorsWorker2 {
621
613
  Cors.ALLOW_CREDENTIALS,
622
614
  Cors.EXPOSE_HEADERS,
623
615
  Cors.ALLOW_METHODS,
616
+ Cors.ALLOW_HEADERS,
624
617
  Cors.MAX_AGE
625
618
  ];
626
619
  }
@@ -673,11 +666,11 @@ var BasicWorker = class extends CacheWorker {
673
666
  return this.getResponse(Options);
674
667
  }
675
668
  async head() {
676
- const worker = this.createWorker(new Request(this.request, { method: "GET" /* GET */ }));
669
+ const worker = this.create(new Request(this.request, { method: "GET" /* GET */ }));
677
670
  return this.getResponse(Head, await worker.fetch());
678
671
  }
679
672
  async getResponse(ResponseClass, ...args) {
680
- const response = new ResponseClass(this, ...args).createResponse();
673
+ const response = new ResponseClass(this, ...args).getResponse();
681
674
  this.setCachedResponse(response);
682
675
  return response;
683
676
  }
@@ -747,6 +740,7 @@ export {
747
740
  addCorsHeaders,
748
741
  getContentType,
749
742
  getOrigin,
743
+ httpTokenCompare,
750
744
  isMethod,
751
745
  mergeHeader,
752
746
  normalizeUrl,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/common.ts","../src/cors.ts","../src/errors.ts","../src/response.ts","../src/routes.ts","../src/base-worker.ts","../src/cors-worker.ts","../src/cache-worker.ts","../src/basic-worker.ts","../src/route-worker.ts"],"sourcesContent":["/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport CacheLib from \"cache-control-parser\";\n\n/**\n * @see {@link https://github.com/etienne-martin/cache-control-parser | cache-control-parser}\n */\nexport type CacheControl = CacheLib.CacheControl;\nexport const CacheControl = {\n parse: CacheLib.parse,\n stringify: CacheLib.stringify,\n\n /** A Cache-Control directive that disables all caching. */\n DISABLE: Object.freeze({\n \"no-cache\": true,\n \"no-store\": true,\n \"must-revalidate\": true,\n \"max-age\": 0,\n }) satisfies CacheControl,\n};\n\n/**\n * https://github.com/prettymuchbryce/http-status-codes\n */\nexport { StatusCodes } from \"http-status-codes\";\n\n/**\n * Standard HTTP header names and common values.\n */\nexport namespace HttpHeader {\n export const VARY = \"Vary\";\n export const ALLOW = \"Allow\";\n export const CONTENT_TYPE = \"Content-Type\";\n export const CACHE_CONTROL = \"Cache-Control\";\n\n // Security Headers\n export const X_FRAME_OPTIONS = \"X-Frame-Options\"; // e.g. \"DENY\" or \"SAMEORIGIN\"\n export const X_CONTENT_TYPE_OPTIONS = \"X-Content-Type-Options\"; // usually \"nosniff\"\n export const REFERRER_POLICY = \"Referrer-Policy\"; // e.g. \"no-referrer\", \"strict-origin-when-cross-origin\"\n export const PERMISSIONS_POLICY = \"Permissions-Policy\"; // formerly Feature-Policy, controls APIs like geolocation/camera\n export const CONTENT_SECURITY_POLICY = \"Content-Security-Policy\"; // fine-grained script/style/image restrictions\n export const STRICT_TRANSPORT_SECURITY = \"Strict-Transport-Security\"; // e.g. \"max-age=63072000; includeSubDomains; preload\"\n\n // Values\n export const NOSNIFF = \"nosniff\";\n export const ORIGIN = \"Origin\";\n}\n\n/**\n * Time constants in seconds. Month is approximated as 30 days.\n */\nexport const Time = {\n Second: 1,\n Minute: 60,\n Hour: 3600, // 60 * 60\n Day: 86400, // 60 * 60 * 24\n Week: 604800, // 60 * 60 * 24 * 7\n Month: 2592000, // 60 * 60 * 24 * 30\n Year: 31536000, // 60 * 60 * 24 * 365\n} as const;\n\n/**\n * Standard HTTP request methods.\n */\nexport enum Method {\n GET = \"GET\",\n PUT = \"PUT\",\n HEAD = \"HEAD\",\n POST = \"POST\",\n PATCH = \"PATCH\",\n DELETE = \"DELETE\",\n OPTIONS = \"OPTIONS\",\n}\nconst METHOD_SET: Set<string> = new Set(Object.values(Method));\n\n/**\n * Type guard that checks if a string is a valid HTTP method.\n *\n * @param value - The string to test.\n * @returns True if `value` is a recognized HTTP method.\n */\nexport function isMethod(value: string): value is Method {\n return METHOD_SET.has(value);\n}\n\n/**\n * Returns the proper Content-Type string for a given media type.\n * Appends `charset=utf-8` for text-based types that require it.\n *\n * @param type - The media type.\n * @returns A string suitable for the `Content-Type` header.\n */\nexport function getContentType(type: MediaType): string {\n if (ADD_CHARSET.has(type)) {\n return `${type}; charset=utf-8`;\n }\n return type;\n}\n\n/**\n * Common media types types used for HTTP headers.\n */\nexport enum MediaType {\n PLAIN_TEXT = \"text/plain\",\n HTML = \"text/html\",\n CSS = \"text/css\",\n CSV = \"text/csv\",\n XML = \"text/xml\",\n MARKDOWN = \"text/markdown\",\n RICH_TEXT = \"text/richtext\",\n JSON = \"application/json\",\n XML_APP = \"application/xml\",\n YAML = \"application/x-yaml\",\n FORM_URLENCODED = \"application/x-www-form-urlencoded\",\n NDJSON = \"application/x-ndjson\",\n MSGPACK = \"application/x-msgpack\",\n PROTOBUF = \"application/x-protobuf\",\n MULTIPART_FORM_DATA = \"multipart/form-data\",\n MULTIPART_MIXED = \"multipart/mixed\",\n MULTIPART_ALTERNATIVE = \"multipart/alternative\",\n MULTIPART_DIGEST = \"multipart/digest\",\n MULTIPART_RELATED = \"multipart/related\",\n MULTIPART_SIGNED = \"multipart/signed\",\n MULTIPART_ENCRYPTED = \"multipart/encrypted\",\n OCTET_STREAM = \"application/octet-stream\",\n PDF = \"application/pdf\",\n ZIP = \"application/zip\",\n GZIP = \"application/gzip\",\n MSWORD = \"application/msword\",\n DOCX = \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n EXCEL = \"application/vnd.ms-excel\",\n XLSX = \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n POWERPOINT = \"application/vnd.ms-powerpoint\",\n PPTX = \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n ICO = \"image/x-icon\",\n ICO_MS = \"image/vnd.microsoft.icon\",\n GIF = \"image/gif\",\n PNG = \"image/png\",\n JPEG = \"image/jpeg\",\n WEBP = \"image/webp\",\n SVG = \"image/svg+xml\",\n HEIF = \"image/heif\",\n AVIF = \"image/avif\",\n EVENT_STREAM = \"text/event-stream\",\n TAR = \"application/x-tar\",\n BZIP2 = \"application/x-bzip2\",\n}\n\n/**\n * A set of media types that require a `charset` parameter when setting\n * the `Content-Type` header.\n *\n * This includes common text-based media types such as HTML, CSS, JSON,\n * XML, CSV, Markdown, and others.\n */\nconst ADD_CHARSET: Set<MediaType> = new Set([\n MediaType.CSS,\n MediaType.CSV,\n MediaType.XML,\n MediaType.SVG,\n MediaType.HTML,\n MediaType.JSON,\n MediaType.NDJSON,\n MediaType.XML_APP,\n MediaType.MARKDOWN,\n MediaType.RICH_TEXT,\n MediaType.PLAIN_TEXT,\n MediaType.FORM_URLENCODED,\n]);\n\n/**\n * Sets a header on the given Headers object.\n *\n * - If `value` is an array, duplicates and empty strings are removed.\n * - If the resulting value array is empty, the header is deleted.\n * - Otherwise, values are joined with `\", \"` and set as the header value.\n *\n * @param headers - The Headers object to modify.\n * @param key - The header name to set.\n * @param value - The header value(s) to set. Can be a string or array of strings.\n */\nexport function setHeader(headers: Headers, key: string, value: string | string[]): void {\n const raw = Array.isArray(value) ? value : [value];\n const values = Array.from(new Set(raw.map((v) => v.trim())))\n .filter((v) => v.length)\n .sort();\n\n if (!values.length) {\n headers.delete(key);\n return;\n }\n\n headers.set(key, values.join(\", \"));\n}\n\n/**\n * Merges new value(s) into an existing header on the given Headers object.\n *\n * - Preserves any existing values and adds new ones.\n * - Removes duplicates and trims all values.\n * - If the header does not exist, it is created.\n *\n * @param headers - The Headers object to modify.\n * @param key - The header name to merge into.\n * @param value - The new header value(s) to add. Can be a string or array of strings.\n */\nexport function mergeHeader(headers: Headers, key: string, value: string | string[]): void {\n const values = Array.isArray(value) ? value : [value];\n if (!values.length) return;\n\n const existing = headers.get(key);\n if (existing) {\n const merged = existing.split(\",\").map((v) => v.trim());\n values.forEach((v) => merged.push(v.trim()));\n setHeader(headers, key, merged);\n } else {\n setHeader(headers, key, values);\n }\n}\n\n/**\n * Normalizes a URL string for use as a consistent cache key.\n *\n * - Sorts query parameters alphabetically so `?b=2&a=1` and `?a=1&b=2` are treated the same.\n * - Strips fragment identifiers (`#...`) since they are not sent in HTTP requests.\n * - Leaves protocol, host, path, and query values intact.\n *\n * @param url The original URL string to normalize.\n * @returns A normalized URL string suitable for hashing or direct cache key use.\n */\nexport function normalizeUrl(url: string): URL {\n const u = new URL(url);\n\n const params = [...u.searchParams.entries()];\n params.sort(([a], [b]) => a.localeCompare(b));\n\n u.search = params\n .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)\n .join(\"&\");\n u.hash = \"\";\n\n return u;\n}\n\n/**\n * Extracts the `Origin` header value from a request.\n *\n * The `Origin` header identifies the origin (scheme, host, and port)\n * of the request initiator. It is commonly used for CORS checks.\n *\n * @param request - The incoming {@link Request} object.\n * @returns The origin string if present, otherwise `null`.\n */\nexport function getOrigin(request: Request): string | null {\n return request.headers.get(HttpHeader.ORIGIN);\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { mergeHeader, Method, setHeader } from \"./common\";\n\n/**\n * Provides information about the CORS policy for the current request.\n */\nexport interface CorsProvider {\n /** Returns a list of allowed origins. */\n getAllowOrigins(): string[];\n\n /** Returns true if any origin is allowed (`*`). */\n allowAnyOrigin(): boolean;\n\n /** Returns the HTTP methods allowed by CORS. */\n getAllowMethods(): Method[];\n\n /** Returns the HTTP headers allowed by CORS. */\n getAllowHeaders(): string[];\n\n /** Returns the HTTP headers that should be exposed to the browser. */\n getExposeHeaders(): string[];\n\n /** Returns the max age (in seconds) for CORS preflight caching. */\n getMaxAge(): number;\n}\n\n/**\n * Constants for common CORS headers.\n */\nexport namespace Cors {\n export const MAX_AGE = \"Access-Control-Max-Age\";\n export const ALLOW_ORIGIN = \"Access-Control-Allow-Origin\";\n export const ALLOW_HEADERS = \"Access-Control-Allow-Headers\";\n export const ALLOW_METHODS = \"Access-Control-Allow-Methods\";\n export const EXPOSE_HEADERS = \"Access-Control-Expose-Headers\";\n export const ALLOW_CREDENTIALS = \"Access-Control-Allow-Credentials\";\n export const ALLOW_ALL_ORIGINS = \"*\";\n}\n\n/**\n * Adds or updates CORS headers on a Headers object according to the provided policy.\n *\n * Behavior:\n * - Removes any existing CORS headers to avoid stale values.\n * - If the request has no origin, the function exits early.\n * - If wildcard `*` is allowed, sets Access-Control-Allow-Origin to `*`.\n * - If the origin is explicitly allowed, sets the correct headers including credentials and Vary: Origin.\n * - Optional headers (Expose-Headers, Allow-Headers, Allow-Methods, Max-Age) are always applied.\n *\n * @param cors The CorsProvider instance that determines allowed origins and headers\n * @param headers The Headers object to update\n */\nexport function addCorsHeaders(origin: string | null, cors: CorsProvider, headers: Headers): void {\n deleteCorsHeaders(headers);\n\n // CORS is not required.\n if (!origin || origin.trim() === \"\") return;\n\n if (cors.allowAnyOrigin()) {\n setHeader(headers, Cors.ALLOW_ORIGIN, Cors.ALLOW_ALL_ORIGINS);\n } else if (cors.getAllowOrigins().includes(origin)) {\n setHeader(headers, Cors.ALLOW_ORIGIN, origin);\n setHeader(headers, Cors.ALLOW_CREDENTIALS, \"true\");\n }\n\n // Optional headers always applied if CORS.\n setHeader(headers, Cors.MAX_AGE, String(cors.getMaxAge()));\n setHeader(headers, Cors.ALLOW_METHODS, cors.getAllowMethods());\n setHeader(headers, Cors.ALLOW_HEADERS, cors.getAllowHeaders());\n mergeHeader(headers, Cors.EXPOSE_HEADERS, cors.getExposeHeaders());\n}\n\n/**\n * Deletes all standard CORS headers from the given Headers object.\n * Useful for cleaning cached responses or resetting headers before reapplying CORS.\n *\n * @param headers The Headers object to clean\n */\nfunction deleteCorsHeaders(headers: Headers) {\n headers.delete(Cors.MAX_AGE);\n headers.delete(Cors.ALLOW_ORIGIN);\n headers.delete(Cors.ALLOW_HEADERS);\n headers.delete(Cors.ALLOW_METHODS);\n headers.delete(Cors.EXPOSE_HEADERS);\n headers.delete(Cors.ALLOW_CREDENTIALS);\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getReasonPhrase } from \"http-status-codes\";\nimport { CacheControl, HttpHeader, Method, StatusCodes } from \"./common\";\nimport { CorsWorker, JsonResponse } from \"./response\";\n\nexport interface ErrorJson {\n status: number;\n error: string;\n details: string;\n}\n\nexport class HttpError extends JsonResponse {\n constructor(worker: CorsWorker, status: StatusCodes, protected readonly details?: string) {\n super(worker, undefined, CacheControl.DISABLE, status);\n }\n\n public get json(): ErrorJson {\n return {\n status: this.status,\n error: getReasonPhrase(this.status),\n details: this.details ?? getReasonPhrase(this.status),\n };\n }\n\n public override createResponse(): Response {\n this.body = JSON.stringify(this.json);\n return super.createResponse();\n }\n}\n\nexport class BadRequest extends HttpError {\n constructor(worker: CorsWorker, details?: string) {\n super(worker, StatusCodes.BAD_REQUEST, details);\n }\n}\n\nexport class Unauthorized extends HttpError {\n constructor(worker: CorsWorker, details?: string) {\n super(worker, StatusCodes.UNAUTHORIZED, details);\n }\n}\n\nexport class Forbidden extends HttpError {\n constructor(worker: CorsWorker, details?: string) {\n super(worker, StatusCodes.FORBIDDEN, details);\n }\n}\n\nexport class NotFound extends HttpError {\n constructor(worker: CorsWorker, details?: string) {\n super(worker, StatusCodes.NOT_FOUND, details);\n }\n}\n\nexport class MethodNotAllowed extends HttpError {\n constructor(worker: CorsWorker) {\n super(\n worker,\n StatusCodes.METHOD_NOT_ALLOWED,\n `${worker.request.method} method not allowed.`\n );\n this.setHeader(HttpHeader.ALLOW, this.worker.getAllowMethods());\n }\n\n public override get json(): ErrorJson & { allowed: Method[] } {\n return {\n ...super.json,\n allowed: this.worker.getAllowMethods(),\n };\n }\n}\n\nexport class InternalServerError extends HttpError {\n constructor(worker: CorsWorker, details?: string) {\n super(worker, StatusCodes.INTERNAL_SERVER_ERROR, details);\n }\n}\n\nexport class NotImplemented extends HttpError {\n constructor(worker: CorsWorker, details?: string) {\n super(worker, StatusCodes.NOT_IMPLEMENTED, details);\n }\n}\n\nexport class MethodNotImplemented extends NotImplemented {\n constructor(worker: CorsWorker) {\n super(worker, `${worker.request.method} method not implemented.`);\n }\n}\n\nexport class ServiceUnavailable extends HttpError {\n constructor(worker: CorsWorker, details?: string) {\n super(worker, StatusCodes.SERVICE_UNAVAILABLE, details);\n }\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getReasonPhrase, StatusCodes } from \"http-status-codes\";\nimport {\n CacheControl,\n getContentType,\n HttpHeader,\n mergeHeader,\n MediaType,\n setHeader,\n getOrigin,\n} from \"./common\";\nimport { addCorsHeaders, CorsProvider } from \"./cors\";\nimport { Worker } from \"./worker\";\n\n/**\n * A {@link Worker} that also implements {@link CorsProvider}.\n *\n * Used by response builders that require both Worker\n * and CORS functionality.\n */\nexport type CorsWorker = Worker & CorsProvider;\n\nabstract class BaseResponse {\n public headers: Headers = new Headers();\n public body: BodyInit | null;\n public status: StatusCodes = StatusCodes.OK;\n public statusText?: string;\n public mediaType?: MediaType;\n\n constructor(public readonly worker: CorsWorker, content: BodyInit | null = null) {\n this.body = this.status === StatusCodes.NO_CONTENT ? null : content;\n }\n\n protected get responseInit(): ResponseInit {\n return {\n headers: this.headers,\n status: this.status,\n statusText: this.statusText ?? getReasonPhrase(this.status),\n };\n }\n\n public setHeader(key: string, value: string | string[]): void {\n setHeader(this.headers, key, value);\n }\n\n public mergeHeader(key: string, value: string | string[]): void {\n mergeHeader(this.headers, key, value);\n }\n\n public addContentType() {\n if (this.mediaType) {\n this.headers.set(HttpHeader.CONTENT_TYPE, getContentType(this.mediaType));\n }\n }\n}\n\nabstract class CorsResponse extends BaseResponse {\n constructor(worker: CorsWorker, content: BodyInit | null = null) {\n super(worker, content);\n }\n\n protected addCorsHeaders(): void {\n addCorsHeaders(this.getOrigin(), this.worker, this.headers);\n\n if (!this.worker.allowAnyOrigin()) {\n mergeHeader(this.headers, HttpHeader.VARY, HttpHeader.ORIGIN);\n }\n }\n\n protected getOrigin() {\n return getOrigin(this.worker.request);\n }\n}\n\nabstract class CacheResponse extends CorsResponse {\n constructor(worker: CorsWorker, body: BodyInit | null = null, public cache?: CacheControl) {\n super(worker, body);\n }\n\n protected addCacheHeaders(): void {\n if (this.cache) {\n this.headers.set(HttpHeader.CACHE_CONTROL, CacheControl.stringify(this.cache));\n }\n }\n}\n\nexport abstract class WorkerResponse extends CacheResponse {\n public createResponse(): Response {\n this.addCorsHeaders();\n this.addCacheHeaders();\n this.addSecurityHeaders();\n\n const body = this.status === StatusCodes.NO_CONTENT ? null : this.body;\n if (body) this.addContentType();\n return new Response(body, this.responseInit);\n }\n\n protected addSecurityHeaders(): void {\n this.setHeader(HttpHeader.X_CONTENT_TYPE_OPTIONS, HttpHeader.NOSNIFF);\n }\n}\n\nexport class ClonedResponse extends WorkerResponse {\n constructor(worker: CorsWorker, response: Response, cache?: CacheControl) {\n const clone = response.clone();\n super(worker, clone.body, cache);\n this.headers = new Headers(clone.headers);\n this.status = clone.status;\n this.statusText = clone.statusText;\n }\n}\n\nexport class SuccessResponse extends WorkerResponse {\n constructor(\n worker: CorsWorker,\n body: BodyInit | null = null,\n cache?: CacheControl,\n status: StatusCodes = StatusCodes.OK\n ) {\n super(worker, body, cache);\n this.status = status;\n }\n}\n\nexport class JsonResponse extends SuccessResponse {\n constructor(\n worker: CorsWorker,\n json: unknown = {},\n cache?: CacheControl,\n status: StatusCodes = StatusCodes.OK\n ) {\n super(worker, JSON.stringify(json), cache, status);\n this.mediaType = MediaType.JSON;\n }\n}\n\nexport class HtmlResponse extends SuccessResponse {\n constructor(\n worker: CorsWorker,\n body: string,\n cache?: CacheControl,\n status: StatusCodes = StatusCodes.OK\n ) {\n super(worker, body, cache, status);\n this.mediaType = MediaType.HTML;\n }\n}\n\nexport class TextResponse extends SuccessResponse {\n constructor(\n worker: CorsWorker,\n content: string,\n cache?: CacheControl,\n status: StatusCodes = StatusCodes.OK\n ) {\n super(worker, content, cache, status);\n this.mediaType = MediaType.PLAIN_TEXT;\n }\n}\n\n/**\n * Removes the body from a GET response.\n */\nexport class Head extends WorkerResponse {\n constructor(worker: CorsWorker, get: Response) {\n super(worker);\n this.headers = new Headers(get.headers);\n }\n}\n\nexport class Options extends SuccessResponse {\n constructor(worker: CorsWorker) {\n super(worker, null, undefined, StatusCodes.NO_CONTENT);\n this.setHeader(HttpHeader.ALLOW, this.worker.getAllowMethods());\n }\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Method } from \"./common\";\n\n/**\n * A callback function for a route.\n *\n * @param match - Captured groups from the route RegExp, or the full match at index 0\n * @returns A Response object or a Promise that resolves to a Response\n */\nexport type RouteCallback = (match: RegExpExecArray) => Promise<Response>;\n\n/**\n * A single route definition.\n *\n * Tuple of:\n * - HTTP method\n * - Path pattern (string or RegExp)\n * - Callback function\n */\nexport type RouteTuple = [Method, RegExp | string, RouteCallback];\n\n/**\n * A collection of route definitions.\n *\n * Used to initialize the router with multiple routes.\n */\nexport type RouteTable = RouteTuple[];\n\n/**\n * Represents the result of matching a request to a route.\n *\n * Contains the route that was matched and the corresponding\n * capture groups from the match.\n */\ninterface MatchedRoute {\n route: Route;\n match: RegExpExecArray;\n}\n\n/**\n * Represents a route in the application.\n *\n * A route defines an HTTP method, a pattern to match request paths,\n * and a callback to handle requests that match the pattern.\n */\nexport class Route {\n /**\n * Creates a new Route instance.\n *\n * @param method The HTTP method (GET, POST, etc.) this route responds to.\n * @param pattern A RegExp used to match the request path.\n * @param callback The function to execute when a request matches this route.\n */\n constructor(\n public readonly method: Method,\n public readonly pattern: RegExp,\n public readonly callback: RouteCallback\n ) {}\n}\n\n/**\n * A collection of routes grouped by HTTP method.\n *\n * Supports adding routes and retrieving the first matching route for a given method and URL.\n */\nexport class Routes implements Iterable<Route> {\n private readonly routes: Route[] = [];\n\n /**\n * Reset all routes and register the given ones.\n *\n * @param table - Tuples of [method, pattern, callback].\n */\n public initialize(table: RouteTable): void {\n this.routes.length = 0;\n table.forEach(([method, pattern, callback]) => this.add(method, pattern, callback));\n }\n\n /**\n * Adds a route to the collection.\n *\n * @param method - HTTP method (GET, POST, etc.)\n * @param pattern - String or RegExp to match the path\n * @param callback - Function to handle the request\n * @returns The Routes instance (for chaining)\n */\n public add(method: Method, pattern: RegExp | string, callback: RouteCallback): this {\n this.routes.push(new Route(method, new RegExp(pattern), callback));\n return this;\n }\n\n /**\n * Finds the first route that matches the given method and URL.\n *\n * @param method - HTTP method of the request\n * @param url - Full URL string of the request\n * @returns The first matching Route, or undefined if none match\n */\n public match(method: Method, url: string): MatchedRoute | undefined {\n const pathname = new URL(url).pathname;\n\n for (const route of this) {\n if (route.method !== method) continue;\n\n const match = route.pattern.exec(pathname);\n if (match) {\n return { route, match };\n }\n }\n return undefined;\n }\n\n /** Allow iteration over all routes */\n public *[Symbol.iterator](): Iterator<Route> {\n yield* this.routes;\n }\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Worker, WorkerConstructor } from \"./worker\";\n\n/**\n * A type-safe Cloudflare Worker handler.\n *\n * Extends `ExportedHandler` but guarantees that the `fetch` method exists\n * and has the correct signature for Cloudflare Worker invocation.\n *\n * @template E - The type of environment bindings passed to the worker. Defaults to `Env`.\n */\ninterface FetchHandler<E = Env> extends ExportedHandler<E> {\n /**\n * Handles an incoming request and produces a response.\n *\n * @param request - The incoming `Request` object.\n * @param env - Environment bindings (e.g., KV namespaces, secrets, Durable Objects).\n * @param ctx - Execution context for background tasks (`waitUntil`).\n * @returns A `Promise` that resolves to the response.\n */\n fetch: (request: Request, env: E, ctx: ExecutionContext) => Promise<Response>;\n}\n\n/**\n * Provides the foundational structure for handling requests,\n * environment bindings, and the worker execution context.\n *\n * Features:\n * - Holds the current `Request` object (`request` getter).\n * - Provides access to environment bindings (`env` getter).\n * - Provides access to the worker execution context (`ctx` getter).\n * - Subclasses must implement `fetch()` to process the request.\n */\nexport abstract class BaseWorker implements Worker {\n constructor(\n private readonly _request: Request,\n private readonly _env: Env,\n private readonly _ctx: ExecutionContext\n ) {}\n\n /** The Request object associated with this worker invocation */\n public get request(): Request {\n return this._request;\n }\n\n /** Environment bindings (e.g., KV, secrets, or other globals) */\n public get env(): Env {\n return this._env;\n }\n\n /** Execution context for background tasks or `waitUntil` */\n public get ctx(): ExecutionContext {\n return this._ctx;\n }\n\n /**\n * Creates a new instance of the current Worker subclass.\n *\n * @param request - The {@link Request} to pass to the new worker instance.\n * @returns A new worker instance of the same subclass as `this`.\n */\n protected createWorker(request: Request): this {\n const ctor = this.constructor as WorkerConstructor<this>;\n return new ctor(request, this.env, this.ctx);\n }\n\n /**\n * Process the {@link Request} and produce a {@link Response}.\n *\n * @returns A {@link Response} promise for the {@link Request}.\n */\n public abstract fetch(): Promise<Response>;\n\n /**\n * **Ignite** your `Worker` implementation into a Cloudflare handler.\n *\n * @returns A `FetchHandler` that launches a new worker instance for each request.\n *\n * @example\n * ```ts\n * export default MyWorker.ignite();\n * ```\n */\n public static ignite<W extends Worker>(this: WorkerConstructor<W>): FetchHandler {\n return {\n fetch: (req: Request, env: Env, ctx: ExecutionContext) =>\n new this(req, env, ctx).fetch(),\n };\n }\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { BaseWorker } from \"./base-worker\";\nimport { Method, Time } from \"./common\";\nimport { CorsProvider } from \"./cors\";\n\n/**\n * Abstract base class for Workers to provide a default CORS policy.\n *\n * Implements the `CorsProvider` interface and provides a standard policy:\n * - Allows all origins (`*`) by default.\n * - Allows GET, OPTIONS, and HEAD methods.\n * - Allows the `Content-Type` header.\n * - Exposes no additional headers.\n * - Sets CORS preflight max-age to one week.\n *\n * Subclasses can override any of the methods to customize the CORS behavior.\n */\nexport abstract class CorsWorker extends BaseWorker implements CorsProvider {\n public getAllowOrigins(): string[] {\n return [\"*\"];\n }\n\n public allowAnyOrigin(): boolean {\n return this.getAllowOrigins().includes(\"*\");\n }\n\n public getAllowMethods(): Method[] {\n return [Method.GET, Method.HEAD, Method.OPTIONS];\n }\n\n public getAllowHeaders(): string[] {\n return [\"Content-Type\"];\n }\n\n public getExposeHeaders(): string[] {\n return [];\n }\n\n public getMaxAge(): number {\n return Time.Week;\n }\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getOrigin, Method, normalizeUrl } from \"./common\";\nimport { addCorsHeaders, Cors } from \"./cors\";\nimport { CorsWorker } from \"./cors-worker\";\n\n/**\n * Abstract worker class that adds caching support for GET requests.\n *\n * Behavior:\n * - Caches successful GET responses (`response.ok === true`) in the selected cache.\n * - Strips CORS headers from cached responses; all other origin headers are preserved.\n * - Dynamically adds CORS headers to cached responses when returned to the client.\n *\n * Subclasses should override `getCacheKey()` to customize cache key generation if needed.\n */\nexport abstract class CacheWorker extends CorsWorker {\n /**\n * Returns the cache key for the current request.\n *\n * Behavior:\n * - By default, returns the normalized request URL.\n * - Query parameters are normalized so that the order does not affect the cache key.\n * For example, `?a=1&b=2` and `?b=2&a=1` produce the same cache key.\n *\n * Subclasses may override this method to implement custom cache key strategies.\n *\n * @returns {URL | RequestInfo} The URL or RequestInfo used as the cache key.\n */\n protected getCacheKey(): URL | RequestInfo {\n return normalizeUrl(this.request.url);\n }\n\n /**\n * Retrieves a cached Response for the current request, if one exists.\n *\n * Behavior:\n * - Only GET requests are considered.\n * - Returns a new Response with dynamic CORS headers applied via `addCacheHeaders`.\n * - Returns `undefined` if no cached response is found.\n * - Cloudflare dynamic headers (`CF-Cache-Status`, `Age`, `Connection`, etc.) will\n * always be present on the returned response, even though they are not stored in the cache.\n *\n * @param {string} [cacheName] Optional named cache; defaults to `caches.default`.\n * @returns {Promise<Response | undefined>} A Response with CORS headers, or undefined.\n * @see {@link setCachedResponse}\n * @see {@link getCacheKey}\n */\n protected async getCachedResponse(cacheName?: string): Promise<Response | undefined> {\n if (this.request.method !== Method.GET) return;\n\n const cache = cacheName ? await caches.open(cacheName) : caches.default;\n const response = await cache.match(this.getCacheKey());\n return response ? this.addCacheHeaders(response) : undefined;\n }\n\n /**\n * Stores a Response in the cache for the current request.\n *\n * Behavior:\n * - Only caches successful GET responses (`response.ok === true`).\n * - Strips headers via `removeCacheHeaders` before storing.\n * - Uses `ctx.waitUntil` to perform caching asynchronously without blocking the response.\n * - All other origin headers (e.g., Cache-Control, Expires) are preserved.\n *\n * @param {Response} response The Response to cache.\n * @param {string} [cacheName] Optional named cache; defaults to `caches.default`.\n * @see {@link getCachedResponse}\n * @see {@link getCacheKey}\n */\n protected async setCachedResponse(response: Response, cacheName?: string): Promise<void> {\n if (!response.ok) return;\n if (this.request.method !== Method.GET) return;\n\n const cache = cacheName ? await caches.open(cacheName) : caches.default;\n this.ctx.waitUntil(\n cache.put(this.getCacheKey(), this.removeCacheHeaders(response.clone()))\n );\n }\n\n /**\n * Adds headers to a cached response.\n *\n * @param {Response} cached The cached Response.\n * @returns {Response} A new Response with dynamic CORS headers applied.\n * @see {@link removeCacheHeaders}\n */\n private addCacheHeaders(cached: Response): Response {\n const headers = new Headers(cached.headers);\n addCorsHeaders(getOrigin(this.request), this, headers);\n\n return new Response(cached.body, {\n status: cached.status,\n statusText: cached.statusText,\n headers,\n });\n }\n\n /**\n * Removes headers that should not be stored in the cache (currently only CORS headers).\n *\n * @param {Response} response The Response to clean before caching.\n * @returns {Response} A new Response with excluded headers removed.\n * @see {@link addCacheHeaders}\n */\n private removeCacheHeaders(response: Response): Response {\n const excludeSet = new Set(this.excludeCacheHeaders().map((h) => h.toLowerCase()));\n const headers = new Headers();\n\n for (const [key, value] of response.headers) {\n if (!excludeSet.has(key)) {\n headers.set(key, value);\n }\n }\n\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n\n /**\n * Returns the list of headers to exclude from the cached response.\n * By default, excludes only dynamic CORS headers.\n *\n * @returns {string[]} Array of header names to exclude.\n * @see {@link removeCacheHeaders}\n */\n protected excludeCacheHeaders(): string[] {\n return [\n Cors.ALLOW_ORIGIN,\n Cors.ALLOW_CREDENTIALS,\n Cors.EXPOSE_HEADERS,\n Cors.ALLOW_METHODS,\n Cors.MAX_AGE,\n ];\n }\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CacheWorker } from \"./cache-worker\";\nimport { isMethod, Method } from \"./common\";\nimport { MethodNotAllowed, InternalServerError, MethodNotImplemented } from \"./errors\";\nimport { CorsWorker, Head, Options, WorkerResponse } from \"./response\";\n\nexport abstract class BasicWorker extends CacheWorker {\n public async fetch(): Promise<Response> {\n if (!this.isAllowed(this.request.method)) {\n return this.getResponse(MethodNotAllowed);\n }\n\n try {\n return await this.dispatch();\n } catch (error) {\n return this.getResponse(InternalServerError, String(error));\n }\n }\n\n protected async dispatch(): Promise<Response> {\n const method = this.request.method as Method;\n const handler: Record<Method, () => Promise<Response>> = {\n GET: () => this.get(),\n PUT: () => this.put(),\n HEAD: () => this.head(),\n POST: () => this.post(),\n PATCH: () => this.patch(),\n DELETE: () => this.delete(),\n OPTIONS: () => this.options(),\n };\n return (handler[method] ?? (() => this.getResponse(MethodNotAllowed)))();\n }\n\n public isAllowed(method: string): boolean {\n return isMethod(method) && this.getAllowMethods().includes(method);\n }\n\n protected async get(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n protected async put(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n protected async post(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n protected async patch(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n protected async delete(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n protected async options(): Promise<Response> {\n return this.getResponse(Options);\n }\n\n protected async head(): Promise<Response> {\n const worker = this.createWorker(new Request(this.request, { method: Method.GET }));\n return this.getResponse(Head, await worker.fetch());\n }\n\n protected async getResponse<\n T extends WorkerResponse,\n Ctor extends new (worker: CorsWorker, ...args: any[]) => T\n >(\n ResponseClass: Ctor,\n ...args: ConstructorParameters<Ctor> extends [CorsWorker, ...infer R] ? R : never\n ): Promise<Response> {\n const response = new ResponseClass(this, ...args).createResponse();\n this.setCachedResponse(response);\n return response;\n }\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { BasicWorker } from \"./basic-worker\";\nimport { Method } from \"./common\";\nimport { NotFound } from \"./errors\";\nimport { Routes, RouteTable, RouteCallback } from \"./routes\";\n\nexport abstract class RouteWorker extends BasicWorker {\n protected readonly routes: Routes = new Routes();\n\n protected initialize(table: RouteTable) {\n this.routes.initialize(table);\n }\n\n protected add(method: Method, pattern: RegExp | string, callback: RouteCallback) {\n this.routes.add(method, pattern, callback);\n return this;\n }\n\n protected async dispatch(): Promise<Response> {\n const found = this.routes.match(this.request.method as Method, this.request.url);\n if (!found) return super.dispatch();\n\n return found.route.callback.call(this, found.match);\n }\n\n protected override async get(): Promise<Response> {\n return this.getResponse(NotFound);\n }\n\n protected override async put(): Promise<Response> {\n return this.getResponse(NotFound);\n }\n\n protected override async post(): Promise<Response> {\n return this.getResponse(NotFound);\n }\n\n protected override async patch(): Promise<Response> {\n return this.getResponse(NotFound);\n }\n\n protected override async delete(): Promise<Response> {\n return this.getResponse(NotFound);\n }\n}\n"],"mappings":"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","names":["HttpHeader","Method","MediaType","Cors","getReasonPhrase","StatusCodes","StatusCodes","getReasonPhrase","CorsWorker","CorsWorker"]}
1
+ {"version":3,"sources":["../src/common.ts","../src/cors.ts","../src/errors.ts","../src/response.ts","../src/routes.ts","../src/base-worker.ts","../src/base-cors-worker.ts","../src/cache-worker.ts","../src/basic-worker.ts","../src/route-worker.ts"],"sourcesContent":["/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport CacheLib from \"cache-control-parser\";\n\n/**\n * @see {@link https://github.com/etienne-martin/cache-control-parser | cache-control-parser}\n */\nexport type CacheControl = CacheLib.CacheControl;\nexport const CacheControl = {\n parse: CacheLib.parse,\n stringify: CacheLib.stringify,\n\n /** A Cache-Control directive that disables all caching. */\n DISABLE: Object.freeze({\n \"no-cache\": true,\n \"no-store\": true,\n \"must-revalidate\": true,\n \"max-age\": 0,\n }) satisfies CacheControl,\n};\n\n/**\n * https://github.com/prettymuchbryce/http-status-codes\n */\nexport { StatusCodes } from \"http-status-codes\";\n\n/**\n * Standard HTTP header names and common values.\n */\nexport namespace HttpHeader {\n export const VARY = \"Vary\";\n export const ALLOW = \"Allow\";\n export const CONTENT_TYPE = \"Content-Type\";\n export const CACHE_CONTROL = \"Cache-Control\";\n\n // Security Headers\n export const X_FRAME_OPTIONS = \"X-Frame-Options\"; // e.g. \"DENY\" or \"SAMEORIGIN\"\n export const X_CONTENT_TYPE_OPTIONS = \"X-Content-Type-Options\"; // usually \"nosniff\"\n export const REFERRER_POLICY = \"Referrer-Policy\"; // e.g. \"no-referrer\", \"strict-origin-when-cross-origin\"\n export const PERMISSIONS_POLICY = \"Permissions-Policy\"; // formerly Feature-Policy, controls APIs like geolocation/camera\n export const CONTENT_SECURITY_POLICY = \"Content-Security-Policy\"; // fine-grained script/style/image restrictions\n export const STRICT_TRANSPORT_SECURITY = \"Strict-Transport-Security\"; // e.g. \"max-age=63072000; includeSubDomains; preload\"\n\n // Values\n export const NOSNIFF = \"nosniff\";\n export const ORIGIN = \"Origin\";\n}\n\n/**\n * Time constants in seconds. Month is approximated as 30 days.\n */\nexport const Time = {\n Second: 1,\n Minute: 60,\n Hour: 3600, // 60 * 60\n Day: 86400, // 60 * 60 * 24\n Week: 604800, // 60 * 60 * 24 * 7\n Month: 2592000, // 60 * 60 * 24 * 30\n Year: 31536000, // 60 * 60 * 24 * 365\n} as const;\n\n/**\n * Standard HTTP request methods.\n */\nexport enum Method {\n GET = \"GET\",\n PUT = \"PUT\",\n HEAD = \"HEAD\",\n POST = \"POST\",\n PATCH = \"PATCH\",\n DELETE = \"DELETE\",\n OPTIONS = \"OPTIONS\",\n}\nconst METHOD_SET: Set<string> = new Set(Object.values(Method));\n\n/**\n * Type guard that checks if a string is a valid HTTP method.\n *\n * @param value - The string to test.\n * @returns True if `value` is a recognized HTTP method.\n */\nexport function isMethod(value: string): value is Method {\n return METHOD_SET.has(value);\n}\n\n/**\n * Returns the proper Content-Type string for a given media type.\n * Appends `charset=utf-8` for text-based types that require it.\n *\n * @param type - The media type.\n * @returns A string suitable for the `Content-Type` header.\n */\nexport function getContentType(type: MediaType): string {\n if (ADD_CHARSET.has(type)) {\n return `${type}; charset=utf-8`;\n }\n return type;\n}\n\n/**\n * Common media types types used for HTTP headers.\n */\nexport enum MediaType {\n PLAIN_TEXT = \"text/plain\",\n HTML = \"text/html\",\n CSS = \"text/css\",\n CSV = \"text/csv\",\n XML = \"text/xml\",\n MARKDOWN = \"text/markdown\",\n RICH_TEXT = \"text/richtext\",\n JSON = \"application/json\",\n XML_APP = \"application/xml\",\n YAML = \"application/x-yaml\",\n FORM_URLENCODED = \"application/x-www-form-urlencoded\",\n NDJSON = \"application/x-ndjson\",\n MSGPACK = \"application/x-msgpack\",\n PROTOBUF = \"application/x-protobuf\",\n MULTIPART_FORM_DATA = \"multipart/form-data\",\n MULTIPART_MIXED = \"multipart/mixed\",\n MULTIPART_ALTERNATIVE = \"multipart/alternative\",\n MULTIPART_DIGEST = \"multipart/digest\",\n MULTIPART_RELATED = \"multipart/related\",\n MULTIPART_SIGNED = \"multipart/signed\",\n MULTIPART_ENCRYPTED = \"multipart/encrypted\",\n OCTET_STREAM = \"application/octet-stream\",\n PDF = \"application/pdf\",\n ZIP = \"application/zip\",\n GZIP = \"application/gzip\",\n MSWORD = \"application/msword\",\n DOCX = \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n EXCEL = \"application/vnd.ms-excel\",\n XLSX = \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n POWERPOINT = \"application/vnd.ms-powerpoint\",\n PPTX = \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n ICO = \"image/x-icon\",\n ICO_MS = \"image/vnd.microsoft.icon\",\n GIF = \"image/gif\",\n PNG = \"image/png\",\n JPEG = \"image/jpeg\",\n WEBP = \"image/webp\",\n SVG = \"image/svg+xml\",\n HEIF = \"image/heif\",\n AVIF = \"image/avif\",\n EVENT_STREAM = \"text/event-stream\",\n TAR = \"application/x-tar\",\n BZIP2 = \"application/x-bzip2\",\n}\n\n/**\n * A set of media types that require a `charset` parameter when setting\n * the `Content-Type` header.\n *\n * This includes common text-based media types such as HTML, CSS, JSON,\n * XML, CSV, Markdown, and others.\n */\nconst ADD_CHARSET: Set<MediaType> = new Set([\n MediaType.CSS,\n MediaType.CSV,\n MediaType.XML,\n MediaType.SVG,\n MediaType.HTML,\n MediaType.JSON,\n MediaType.NDJSON,\n MediaType.XML_APP,\n MediaType.MARKDOWN,\n MediaType.RICH_TEXT,\n MediaType.PLAIN_TEXT,\n MediaType.FORM_URLENCODED,\n]);\n\n/**\n * Sets a header on the given Headers object.\n *\n * - If `value` is an array, duplicates and empty strings are removed.\n * - If the resulting value array is empty, the header is deleted.\n * - Otherwise, values are joined with `\", \"` and set as the header value.\n *\n * @param headers - The Headers object to modify.\n * @param key - The header name to set.\n * @param value - The header value(s) to set. Can be a string or array of strings.\n */\nexport function setHeader(headers: Headers, key: string, value: string | string[]): void {\n const raw = Array.isArray(value) ? value : [value];\n const values = Array.from(new Set(raw.map((v) => v.trim())))\n .filter((v) => v.length)\n .sort(httpTokenCompare);\n\n if (!values.length) {\n headers.delete(key);\n return;\n }\n\n headers.set(key, values.join(\", \"));\n}\n\n/**\n * Merges new value(s) into an existing header on the given Headers object.\n *\n * - Preserves any existing values and adds new ones.\n * - Removes duplicates and trims all values.\n * - If the header does not exist, it is created.\n *\n * @param headers - The Headers object to modify.\n * @param key - The header name to merge into.\n * @param value - The new header value(s) to add. Can be a string or array of strings.\n */\nexport function mergeHeader(headers: Headers, key: string, value: string | string[]): void {\n const values = Array.isArray(value) ? value : [value];\n if (!values.length) return;\n\n const existing = headers.get(key);\n if (existing) {\n const merged = existing.split(\",\").map((v) => v.trim());\n values.forEach((v) => merged.push(v.trim()));\n setHeader(headers, key, merged);\n } else {\n setHeader(headers, key, values);\n }\n}\n\n/**\n * Normalizes a URL string for use as a consistent cache key.\n *\n * - Sorts query parameters alphabetically so `?b=2&a=1` and `?a=1&b=2` are treated the same.\n * - Strips fragment identifiers (`#...`) since they are not sent in HTTP requests.\n * - Leaves protocol, host, path, and query values intact.\n *\n * @param url The original URL string to normalize.\n * @returns A normalized URL string suitable for hashing or direct cache key use.\n */\nexport function normalizeUrl(url: string): URL {\n const u = new URL(url);\n\n const params = [...u.searchParams.entries()];\n params.sort(([a], [b]) => httpTokenCompare(a, b));\n\n u.search = params\n .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)\n .join(\"&\");\n u.hash = \"\";\n\n return u;\n}\n\n/**\n * Deterministic ASCII comparison of HTTP token strings.\n *\n * Use this for header names, header values, or query parameter keys\n * that are restricted to ASCII per the HTTP spec (RFC 9110 / RFC 3986).\n *\n * Note: This comparator is NOT for natural language strings.\n */\nexport function httpTokenCompare(a: string, b: string): number {\n if (a < b) return -1;\n if (a > b) return 1;\n return 0;\n}\n\n/**\n * Extracts the `Origin` header value from a request.\n *\n * The `Origin` header identifies the origin (scheme, host, and port)\n * of the request initiator. It is commonly used for CORS checks.\n *\n * @param request - The incoming {@link Request} object.\n * @returns The origin string if present, otherwise `null`.\n */\nexport function getOrigin(request: Request): string | null {\n return request.headers.get(HttpHeader.ORIGIN);\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { mergeHeader, Method, setHeader } from \"./common\";\n\n/**\n * Implementations will provide a specific CORS policy.\n */\nexport interface CorsProvider {\n /** Returns a list of allowed origins. */\n getAllowOrigins(): string[];\n\n /** Returns true if any origin is allowed (`*`). */\n allowAnyOrigin(): boolean;\n\n /** Returns the HTTP methods allowed by CORS. */\n getAllowMethods(): Method[];\n\n /** Returns the HTTP headers allowed by CORS. */\n getAllowHeaders(): string[];\n\n /** Returns the HTTP headers that should be exposed to the browser. */\n getExposeHeaders(): string[];\n\n /** Returns the max age (in seconds) for CORS preflight caching. */\n getMaxAge(): number;\n}\n\n/**\n * Constants for common CORS headers.\n */\nexport namespace Cors {\n export const MAX_AGE = \"Access-Control-Max-Age\";\n export const ALLOW_ORIGIN = \"Access-Control-Allow-Origin\";\n export const ALLOW_HEADERS = \"Access-Control-Allow-Headers\";\n export const ALLOW_METHODS = \"Access-Control-Allow-Methods\";\n export const EXPOSE_HEADERS = \"Access-Control-Expose-Headers\";\n export const ALLOW_CREDENTIALS = \"Access-Control-Allow-Credentials\";\n export const ALLOW_ALL_ORIGINS = \"*\";\n}\n\n/**\n * Adds or updates CORS headers on a Headers object according to the provided policy.\n *\n * Behavior:\n * - Removes any existing CORS headers to avoid stale values.\n * - If the request has no origin, the function exits early.\n * - If wildcard `*` is allowed, sets Access-Control-Allow-Origin to `*`.\n * - If the origin is explicitly allowed, sets the correct headers including credentials and Vary: Origin.\n * - Optional headers (Expose-Headers, Allow-Headers, Allow-Methods, Max-Age) are always applied.\n *\n * @param cors The CorsProvider instance that determines allowed origins and headers\n * @param headers The Headers object to update\n */\nexport function addCorsHeaders(origin: string | null, cors: CorsProvider, headers: Headers): void {\n deleteCorsHeaders(headers);\n\n // CORS is not required.\n if (!origin || origin.trim() === \"\") return;\n\n if (cors.allowAnyOrigin()) {\n setHeader(headers, Cors.ALLOW_ORIGIN, Cors.ALLOW_ALL_ORIGINS);\n } else if (cors.getAllowOrigins().includes(origin)) {\n setHeader(headers, Cors.ALLOW_ORIGIN, origin);\n setHeader(headers, Cors.ALLOW_CREDENTIALS, \"true\");\n }\n\n // Optional headers always applied if CORS.\n setHeader(headers, Cors.MAX_AGE, String(cors.getMaxAge()));\n setHeader(headers, Cors.ALLOW_METHODS, cors.getAllowMethods());\n setHeader(headers, Cors.ALLOW_HEADERS, cors.getAllowHeaders());\n mergeHeader(headers, Cors.EXPOSE_HEADERS, cors.getExposeHeaders());\n}\n\n/**\n * Deletes all standard CORS headers from the given Headers object.\n * Useful for cleaning cached responses or resetting headers before reapplying CORS.\n *\n * @param headers The Headers object to clean\n */\nfunction deleteCorsHeaders(headers: Headers) {\n headers.delete(Cors.MAX_AGE);\n headers.delete(Cors.ALLOW_ORIGIN);\n headers.delete(Cors.ALLOW_HEADERS);\n headers.delete(Cors.ALLOW_METHODS);\n headers.delete(Cors.EXPOSE_HEADERS);\n headers.delete(Cors.ALLOW_CREDENTIALS);\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getReasonPhrase } from \"http-status-codes\";\nimport { CacheControl, HttpHeader, StatusCodes } from \"./common\";\nimport { CorsWorker, JsonResponse } from \"./response\";\n\nexport interface ErrorJson {\n status: number;\n error: string;\n details: string;\n}\n\nexport class HttpError extends JsonResponse {\n constructor(worker: CorsWorker, status: StatusCodes, protected readonly details?: string) {\n const json: ErrorJson = {\n status,\n error: getReasonPhrase(status),\n details: details ?? getReasonPhrase(status),\n };\n super(worker, json, CacheControl.DISABLE, status);\n }\n}\n\nexport class BadRequest extends HttpError {\n constructor(worker: CorsWorker, details?: string) {\n super(worker, StatusCodes.BAD_REQUEST, details);\n }\n}\n\nexport class Unauthorized extends HttpError {\n constructor(worker: CorsWorker, details?: string) {\n super(worker, StatusCodes.UNAUTHORIZED, details);\n }\n}\n\nexport class Forbidden extends HttpError {\n constructor(worker: CorsWorker, details?: string) {\n super(worker, StatusCodes.FORBIDDEN, details);\n }\n}\n\nexport class NotFound extends HttpError {\n constructor(worker: CorsWorker, details?: string) {\n super(worker, StatusCodes.NOT_FOUND, details);\n }\n}\n\nexport class MethodNotAllowed extends HttpError {\n constructor(worker: CorsWorker) {\n super(\n worker,\n StatusCodes.METHOD_NOT_ALLOWED,\n `${worker.request.method} method not allowed.`\n );\n this.setHeader(HttpHeader.ALLOW, this.worker.getAllowMethods());\n }\n}\n\nexport class InternalServerError extends HttpError {\n constructor(worker: CorsWorker, details?: string) {\n super(worker, StatusCodes.INTERNAL_SERVER_ERROR, details);\n }\n}\n\nexport class NotImplemented extends HttpError {\n constructor(worker: CorsWorker, details?: string) {\n super(worker, StatusCodes.NOT_IMPLEMENTED, details);\n }\n}\n\nexport class MethodNotImplemented extends NotImplemented {\n constructor(worker: CorsWorker) {\n super(worker, `${worker.request.method} method not implemented.`);\n }\n}\n\nexport class ServiceUnavailable extends HttpError {\n constructor(worker: CorsWorker, details?: string) {\n super(worker, StatusCodes.SERVICE_UNAVAILABLE, details);\n }\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getReasonPhrase, StatusCodes } from \"http-status-codes\";\nimport {\n CacheControl,\n getContentType,\n HttpHeader,\n mergeHeader,\n MediaType,\n setHeader,\n getOrigin,\n} from \"./common\";\nimport { addCorsHeaders, CorsProvider } from \"./cors\";\nimport { Worker } from \"./worker\";\n\nexport type CorsWorker = Worker & CorsProvider;\n\nabstract class BaseResponse {\n public headers: Headers = new Headers();\n public status: StatusCodes = StatusCodes.OK;\n public statusText?: string;\n public mediaType?: MediaType;\n\n protected get responseInit(): ResponseInit {\n return {\n headers: this.headers,\n status: this.status,\n statusText: this.statusText ?? getReasonPhrase(this.status),\n };\n }\n\n public setHeader(key: string, value: string | string[]): void {\n setHeader(this.headers, key, value);\n }\n\n public mergeHeader(key: string, value: string | string[]): void {\n mergeHeader(this.headers, key, value);\n }\n\n public addContentType() {\n if (this.mediaType) {\n this.headers.set(HttpHeader.CONTENT_TYPE, getContentType(this.mediaType));\n }\n }\n}\n\nabstract class CorsResponse extends BaseResponse {\n constructor(public readonly worker: CorsWorker) {\n super();\n }\n\n protected addCorsHeaders(): void {\n addCorsHeaders(this.getOrigin(), this.worker, this.headers);\n\n if (!this.worker.allowAnyOrigin()) {\n this.mergeHeader(HttpHeader.VARY, HttpHeader.ORIGIN);\n }\n }\n\n protected getOrigin() {\n return getOrigin(this.worker.request);\n }\n}\n\nabstract class CacheResponse extends CorsResponse {\n constructor(worker: CorsWorker, public cache?: CacheControl) {\n super(worker);\n }\n\n protected addCacheHeader(): void {\n if (this.cache) {\n this.headers.set(HttpHeader.CACHE_CONTROL, CacheControl.stringify(this.cache));\n }\n }\n}\n\nexport abstract class WorkerResponse extends CacheResponse {\n constructor(\n worker: CorsWorker,\n private readonly body: BodyInit | null = null,\n cache?: CacheControl\n ) {\n super(worker, cache);\n }\n\n public getResponse(): Response {\n this.addCorsHeaders();\n this.addCacheHeader();\n this.addSecurityHeaders();\n\n const body = this.status === StatusCodes.NO_CONTENT ? null : this.body;\n\n if (body) this.addContentType();\n return new Response(body, this.responseInit);\n }\n\n protected addSecurityHeaders(): void {\n this.setHeader(HttpHeader.X_CONTENT_TYPE_OPTIONS, HttpHeader.NOSNIFF);\n }\n}\n\nexport class ClonedResponse extends WorkerResponse {\n constructor(worker: CorsWorker, response: Response, cache?: CacheControl) {\n const clone = response.clone();\n super(worker, clone.body, cache);\n this.headers = new Headers(clone.headers);\n this.status = clone.status;\n this.statusText = clone.statusText;\n }\n}\n\nexport class SuccessResponse extends WorkerResponse {\n constructor(\n worker: CorsWorker,\n body: BodyInit | null = null,\n cache?: CacheControl,\n status: StatusCodes = StatusCodes.OK\n ) {\n super(worker, body, cache);\n this.status = status;\n }\n}\n\nexport class JsonResponse extends SuccessResponse {\n constructor(\n worker: CorsWorker,\n json: unknown = {},\n cache?: CacheControl,\n status: StatusCodes = StatusCodes.OK\n ) {\n super(worker, JSON.stringify(json), cache, status);\n this.mediaType = MediaType.JSON;\n }\n}\n\nexport class HtmlResponse extends SuccessResponse {\n constructor(\n worker: CorsWorker,\n body: string,\n cache?: CacheControl,\n status: StatusCodes = StatusCodes.OK\n ) {\n super(worker, body, cache, status);\n this.mediaType = MediaType.HTML;\n }\n}\n\nexport class TextResponse extends SuccessResponse {\n constructor(\n worker: CorsWorker,\n content: string,\n cache?: CacheControl,\n status: StatusCodes = StatusCodes.OK\n ) {\n super(worker, content, cache, status);\n this.mediaType = MediaType.PLAIN_TEXT;\n }\n}\n\n/**\n * Removes the body from a GET response.\n */\nexport class Head extends WorkerResponse {\n constructor(worker: CorsWorker, get: Response) {\n super(worker);\n this.headers = new Headers(get.headers);\n }\n}\n\nexport class Options extends SuccessResponse {\n constructor(worker: CorsWorker) {\n super(worker, null, undefined, StatusCodes.NO_CONTENT);\n this.setHeader(HttpHeader.ALLOW, this.worker.getAllowMethods());\n }\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Method } from \"./common\";\n\n/**\n * A callback function for a route.\n *\n * @param match - Captured groups from the route RegExp, or the full match at index 0\n * @returns A Response object or a Promise that resolves to a Response\n */\nexport type RouteCallback = (match: RegExpExecArray) => Promise<Response>;\n\n/**\n * A single route definition.\n *\n * Tuple of:\n * - HTTP method\n * - Path pattern (string or RegExp)\n * - Callback function\n */\nexport type RouteTuple = [Method, RegExp | string, RouteCallback];\n\n/**\n * A collection of route definitions.\n *\n * Used to initialize the router with multiple routes.\n */\nexport type RouteTable = RouteTuple[];\n\n/**\n * Represents the result of matching a request to a route.\n *\n * Contains the route that was matched and the corresponding\n * capture groups from the match.\n */\ninterface MatchedRoute {\n route: Route;\n match: RegExpExecArray;\n}\n\n/**\n * Represents a route in the application.\n *\n * A route defines an HTTP method, a pattern to match request paths,\n * and a callback to handle requests that match the pattern.\n */\nexport class Route {\n /**\n * Creates a new Route instance.\n *\n * @param method The HTTP method (GET, POST, etc.) this route responds to.\n * @param pattern A RegExp used to match the request path.\n * @param callback The function to execute when a request matches this route.\n */\n constructor(\n public readonly method: Method,\n public readonly pattern: RegExp,\n public readonly callback: RouteCallback\n ) {}\n}\n\n/**\n * A collection of routes grouped by HTTP method.\n *\n * Supports adding routes and retrieving the first matching route for a given method and URL.\n */\nexport class Routes implements Iterable<Route> {\n private readonly routes: Route[] = [];\n\n /**\n * Reset all routes and register the given ones.\n *\n * @param table - Tuples of [method, pattern, callback].\n */\n public initialize(table: RouteTable): void {\n this.routes.length = 0;\n table.forEach(([method, pattern, callback]) => this.add(method, pattern, callback));\n }\n\n /**\n * Adds a route to the collection.\n *\n * @param method - HTTP method (GET, POST, etc.)\n * @param pattern - String or RegExp to match the path\n * @param callback - Function to handle the request\n * @returns The Routes instance (for chaining)\n */\n public add(method: Method, pattern: RegExp | string, callback: RouteCallback): this {\n this.routes.push(new Route(method, new RegExp(pattern), callback));\n return this;\n }\n\n /**\n * Finds the first route that matches the given method and URL.\n *\n * @param method - HTTP method of the request\n * @param url - Full URL string of the request\n * @returns The first matching Route, or undefined if none match\n */\n public match(method: Method, url: string): MatchedRoute | undefined {\n const pathname = new URL(url).pathname;\n for (const route of this) {\n if (route.method === method) {\n const match = route.pattern.exec(pathname);\n if (match) return { route, match };\n }\n }\n return undefined;\n }\n\n /** Allow iteration over all routes */\n public *[Symbol.iterator](): Iterator<Route> {\n yield* this.routes;\n }\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Worker, WorkerConstructor } from \"./worker\";\n\n/**\n * A type-safe Cloudflare Worker handler.\n *\n * Extends `ExportedHandler` but guarantees that the `fetch` method exists\n * and has the correct signature for Cloudflare Worker invocation.\n *\n * @template E - The type of environment bindings passed to the worker. Defaults to `Env`.\n */\ninterface FetchHandler<E = Env> extends ExportedHandler<E> {\n /**\n * Handles an incoming request and produces a response.\n *\n * @param request - The incoming `Request` object.\n * @param env - Environment bindings (e.g., KV namespaces, secrets, Durable Objects).\n * @param ctx - Execution context for background tasks (`waitUntil`).\n * @returns A `Promise` that resolves to the response.\n */\n fetch: (request: Request, env: E, ctx: ExecutionContext) => Promise<Response>;\n}\n\n/**\n * Provides the foundational structure for handling requests,\n * environment bindings, and the worker execution context.\n *\n * Features:\n * - Holds the current `Request` object (`request` getter).\n * - Provides access to environment bindings (`env` getter).\n * - Provides access to the worker execution context (`ctx` getter).\n * - Subclasses must implement `fetch()` to process the request.\n */\nexport abstract class BaseWorker implements Worker {\n constructor(\n private readonly _request: Request,\n private readonly _env: Env,\n private readonly _ctx: ExecutionContext\n ) {}\n\n /** The Request object associated with this worker invocation */\n public get request(): Request {\n return this._request;\n }\n\n /** Environment bindings (e.g., KV, secrets, or other globals) */\n public get env(): Env {\n return this._env;\n }\n\n /** Execution context for background tasks or `waitUntil` */\n public get ctx(): ExecutionContext {\n return this._ctx;\n }\n\n /**\n * Creates a new instance of the current Worker subclass.\n *\n * @param request - The {@link Request} to pass to the new worker instance.\n * @returns A new worker instance of the same subclass as `this`.\n */\n protected create(request: Request): this {\n const ctor = this.constructor as WorkerConstructor<this>;\n return new ctor(request, this.env, this.ctx);\n }\n\n /**\n * Process the {@link Request} and produce a {@link Response}.\n *\n * @returns A {@link Response} promise for the {@link Request}.\n */\n public abstract fetch(): Promise<Response>;\n\n /**\n * **Ignite** your `Worker` implementation into a Cloudflare handler.\n *\n * @returns A `FetchHandler` that launches a new worker instance for each request.\n *\n * @example\n * ```ts\n * export default MyWorker.ignite();\n * ```\n */\n public static ignite<W extends Worker>(this: WorkerConstructor<W>): FetchHandler {\n return {\n fetch: (request: Request, env: Env, ctx: ExecutionContext) =>\n new this(request, env, ctx).fetch(),\n };\n }\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { BaseWorker } from \"./base-worker\";\nimport { Method, Time } from \"./common\";\nimport { CorsProvider } from \"./cors\";\n\n/**\n * Abstract base class for Workers to provide a default CORS policy.\n *\n * Implements the `CorsProvider` interface and provides a standard policy:\n * - Allows all origins (`*`) by default.\n * - Allows GET, OPTIONS, and HEAD methods.\n * - Allows the `Content-Type` header.\n * - Exposes no additional headers.\n * - Sets CORS preflight max-age to one week.\n *\n * Subclasses can override any of the methods to customize the CORS behavior.\n */\nexport abstract class BaseCorsWorker extends BaseWorker implements CorsProvider {\n public getAllowOrigins(): string[] {\n return [\"*\"];\n }\n\n public allowAnyOrigin(): boolean {\n return this.getAllowOrigins().includes(\"*\");\n }\n\n public getAllowMethods(): Method[] {\n return [Method.GET, Method.HEAD, Method.OPTIONS];\n }\n\n public getAllowHeaders(): string[] {\n return [\"Content-Type\"];\n }\n\n public getExposeHeaders(): string[] {\n return [];\n }\n\n public getMaxAge(): number {\n return Time.Week;\n }\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getOrigin, Method, normalizeUrl } from \"./common\";\nimport { addCorsHeaders, Cors } from \"./cors\";\nimport { BaseCorsWorker } from \"./base-cors-worker\";\n\n/**\n * Abstract worker class that adds caching support for GET requests.\n *\n * Behavior:\n * - Caches successful GET responses (`response.ok === true`) in the selected cache.\n * - Strips CORS headers from cached responses; all other origin headers are preserved.\n * - Dynamically adds CORS headers to cached responses when returned to the client.\n *\n * Subclasses should override `getCacheKey()` to customize cache key generation if needed.\n */\nexport abstract class CacheWorker extends BaseCorsWorker {\n /**\n * Returns the cache key for the current request.\n *\n * Behavior:\n * - By default, returns the normalized request URL.\n * - Query parameters are normalized so that the order does not affect the cache key.\n * For example, `?a=1&b=2` and `?b=2&a=1` produce the same cache key.\n *\n * Subclasses may override this method to implement custom cache key strategies.\n *\n * @returns {URL | RequestInfo} The URL or RequestInfo used as the cache key.\n */\n protected getCacheKey(): URL | RequestInfo {\n return normalizeUrl(this.request.url);\n }\n\n /**\n * Retrieves a cached Response for the current request, if one exists.\n *\n * Behavior:\n * - Only GET requests are considered.\n * - Returns a new Response with dynamic CORS headers applied via `addCacheHeaders`.\n * - Returns `undefined` if no cached response is found.\n * - Cloudflare dynamic headers (`CF-Cache-Status`, `Age`, `Connection`, etc.) will\n * always be present on the returned response, even though they are not stored in the cache.\n *\n * @param {string} [cacheName] Optional named cache; defaults to `caches.default`.\n * @returns {Promise<Response | undefined>} A Response with CORS headers, or undefined.\n * @see {@link setCachedResponse}\n * @see {@link getCacheKey}\n */\n protected async getCachedResponse(cacheName?: string): Promise<Response | undefined> {\n if (this.request.method !== Method.GET) return;\n\n const cache = cacheName ? await caches.open(cacheName) : caches.default;\n const response = await cache.match(this.getCacheKey());\n return response ? this.addCacheHeaders(response) : undefined;\n }\n\n /**\n * Stores a Response in the cache for the current request.\n *\n * Behavior:\n * - Only caches successful GET responses (`response.ok === true`).\n * - Strips headers via `removeCacheHeaders` before storing.\n * - Uses `ctx.waitUntil` to perform caching asynchronously without blocking the response.\n * - All other origin headers (e.g., Cache-Control, Expires) are preserved.\n *\n * @param {Response} response The Response to cache.\n * @param {string} [cacheName] Optional named cache; defaults to `caches.default`.\n * @see {@link getCachedResponse}\n * @see {@link getCacheKey}\n */\n protected async setCachedResponse(response: Response, cacheName?: string): Promise<void> {\n if (!response.ok) return;\n if (this.request.method !== Method.GET) return;\n\n const cache = cacheName ? await caches.open(cacheName) : caches.default;\n this.ctx.waitUntil(\n cache.put(this.getCacheKey(), this.removeCacheHeaders(response.clone()))\n );\n }\n\n /**\n * Adds headers to a cached response.\n *\n * @param {Response} cached The cached Response.\n * @returns {Response} A new Response with dynamic CORS headers applied.\n * @see {@link removeCacheHeaders}\n */\n protected addCacheHeaders(cached: Response): Response {\n const headers = new Headers(cached.headers);\n addCorsHeaders(getOrigin(this.request), this, headers);\n\n return new Response(cached.body, {\n status: cached.status,\n statusText: cached.statusText,\n headers,\n });\n }\n\n /**\n * Removes headers that should not be stored in the cache (currently only CORS headers).\n *\n * @param {Response} response The Response to clean before caching.\n * @returns {Response} A new Response with excluded headers removed.\n * @see {@link addCacheHeaders}\n */\n private removeCacheHeaders(response: Response): Response {\n const excludeSet = new Set(this.excludeCacheHeaders().map((h) => h.toLowerCase()));\n const headers = new Headers();\n\n for (const [key, value] of response.headers) {\n if (!excludeSet.has(key)) {\n headers.set(key, value);\n }\n }\n\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n\n /**\n * Returns the list of headers to exclude from the cached response.\n * By default, excludes only dynamic CORS headers.\n *\n * @returns {string[]} Array of header names to exclude.\n * @see {@link removeCacheHeaders}\n */\n protected excludeCacheHeaders(): string[] {\n return [\n Cors.ALLOW_ORIGIN,\n Cors.ALLOW_CREDENTIALS,\n Cors.EXPOSE_HEADERS,\n Cors.ALLOW_METHODS,\n Cors.ALLOW_HEADERS,\n Cors.MAX_AGE,\n ];\n }\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CacheWorker } from \"./cache-worker\";\nimport { isMethod, Method } from \"./common\";\nimport { MethodNotAllowed, InternalServerError, MethodNotImplemented } from \"./errors\";\nimport { CorsWorker, Head, Options, WorkerResponse } from \"./response\";\n\nexport abstract class BasicWorker extends CacheWorker {\n public async fetch(): Promise<Response> {\n if (!this.isAllowed(this.request.method)) {\n return this.getResponse(MethodNotAllowed);\n }\n\n try {\n return await this.dispatch();\n } catch (error) {\n return this.getResponse(InternalServerError, String(error));\n }\n }\n\n protected async dispatch(): Promise<Response> {\n const method = this.request.method as Method;\n const handler: Record<Method, () => Promise<Response>> = {\n GET: () => this.get(),\n PUT: () => this.put(),\n HEAD: () => this.head(),\n POST: () => this.post(),\n PATCH: () => this.patch(),\n DELETE: () => this.delete(),\n OPTIONS: () => this.options(),\n };\n return (handler[method] ?? (() => this.getResponse(MethodNotAllowed)))();\n }\n\n public isAllowed(method: string): boolean {\n return isMethod(method) && this.getAllowMethods().includes(method);\n }\n\n protected async get(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n protected async put(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n protected async post(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n protected async patch(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n protected async delete(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n protected async options(): Promise<Response> {\n return this.getResponse(Options);\n }\n\n protected async head(): Promise<Response> {\n const worker = this.create(new Request(this.request, { method: Method.GET }));\n return this.getResponse(Head, await worker.fetch());\n }\n\n protected async getResponse<\n T extends WorkerResponse,\n Ctor extends new (worker: CorsWorker, ...args: any[]) => T\n >(\n ResponseClass: Ctor,\n ...args: ConstructorParameters<Ctor> extends [CorsWorker, ...infer R] ? R : never\n ): Promise<Response> {\n const response = new ResponseClass(this, ...args).getResponse();\n this.setCachedResponse(response);\n return response;\n }\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { BasicWorker } from \"./basic-worker\";\nimport { Method } from \"./common\";\nimport { NotFound } from \"./errors\";\nimport { Routes, RouteTable, RouteCallback } from \"./routes\";\n\nexport abstract class RouteWorker extends BasicWorker {\n protected readonly routes: Routes = new Routes();\n\n protected initialize(table: RouteTable) {\n this.routes.initialize(table);\n }\n\n protected add(method: Method, pattern: RegExp | string, callback: RouteCallback) {\n this.routes.add(method, pattern, callback);\n return this;\n }\n\n protected async dispatch(): Promise<Response> {\n const found = this.routes.match(this.request.method as Method, this.request.url);\n if (!found) return super.dispatch();\n\n return found.route.callback.call(this, found.match);\n }\n\n protected override async get(): Promise<Response> {\n return this.getResponse(NotFound);\n }\n\n protected override async put(): Promise<Response> {\n return this.getResponse(NotFound);\n }\n\n protected override async post(): Promise<Response> {\n return this.getResponse(NotFound);\n }\n\n protected override async patch(): Promise<Response> {\n return this.getResponse(NotFound);\n }\n\n protected override async delete(): Promise<Response> {\n return this.getResponse(NotFound);\n }\n}\n"],"mappings":"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","names":["HttpHeader","Method","MediaType","Cors","getReasonPhrase","StatusCodes","StatusCodes","getReasonPhrase"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adonix.org/cloud-spark",
3
- "version": "0.0.99",
3
+ "version": "0.0.100",
4
4
  "description": "Ignite your Cloudflare Workers with a type-safe library for rapid development.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -24,7 +24,11 @@
24
24
  "keywords": [
25
25
  "cloudflare",
26
26
  "workers",
27
- "typescript"
27
+ "typescript",
28
+ "javascript",
29
+ "quickstart",
30
+ "routes",
31
+ "cors"
28
32
  ],
29
33
  "repository": {
30
34
  "type": "git",