@adonix.org/cloud-spark 0.0.139 → 0.0.141

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -66,7 +66,8 @@ declare enum Method {
66
66
  HEAD = "HEAD",
67
67
  POST = "POST",
68
68
  PATCH = "PATCH",
69
- DELETE = "DELETE"
69
+ DELETE = "DELETE",
70
+ OPTIONS = "OPTIONS"
70
71
  }
71
72
  /**
72
73
  * Shorthand constants for each HTTP method.
@@ -80,6 +81,7 @@ declare const HEAD: Method;
80
81
  declare const POST: Method;
81
82
  declare const PATCH: Method;
82
83
  declare const DELETE: Method;
84
+ declare const OPTIONS: Method;
83
85
  /**
84
86
  * Type guard that checks if a string is a valid HTTP method.
85
87
  *
@@ -248,23 +250,22 @@ interface Worker {
248
250
  * Manages headers, status, and media type.
249
251
  */
250
252
  declare abstract class BaseResponse {
251
- readonly worker: Worker;
252
- constructor(worker: Worker);
253
+ constructor();
253
254
  /** HTTP headers for the response. */
254
255
  headers: Headers;
255
256
  /** HTTP status code (default 200 OK). */
256
257
  status: StatusCodes;
257
258
  /** Optional status text. Defaults to standard reason phrase. */
258
259
  statusText?: string;
259
- /** Optional media type of the response body. */
260
- mediaType?: MediaType;
260
+ /** Default media type of the response body. */
261
+ mediaType: MediaType;
261
262
  /** Converts current state to ResponseInit for constructing a Response. */
262
263
  protected get responseInit(): ResponseInit;
263
264
  /** Sets a header, overwriting any existing value. */
264
265
  setHeader(key: string, value: string | string[]): void;
265
266
  /** Merges a header with existing values (does not overwrite). */
266
267
  mergeHeader(key: string, value: string | string[]): void;
267
- /** Adds a Content-Type header based on the media type if set. */
268
+ /** Adds a Content-Type header if not already existing (does not overwrite). */
268
269
  addContentType(): void;
269
270
  }
270
271
  /**
@@ -272,7 +273,7 @@ declare abstract class BaseResponse {
272
273
  */
273
274
  declare abstract class CacheResponse extends BaseResponse {
274
275
  cache?: CacheControl | undefined;
275
- constructor(worker: Worker, cache?: CacheControl | undefined);
276
+ constructor(cache?: CacheControl | undefined);
276
277
  /** Adds Cache-Control header if caching is configured. */
277
278
  protected addCacheHeader(): void;
278
279
  }
@@ -280,6 +281,7 @@ declare abstract class CacheResponse extends BaseResponse {
280
281
  * Core worker response. Combines caching, and security headers.
281
282
  */
282
283
  declare abstract class WorkerResponse extends CacheResponse {
284
+ readonly worker: Worker;
283
285
  private readonly body;
284
286
  constructor(worker: Worker, body?: BodyInit | null, cache?: CacheControl);
285
287
  /** Builds the Response object with body, headers, and status. */
@@ -321,6 +323,13 @@ declare class TextResponse extends SuccessResponse {
321
323
  declare class Head extends WorkerResponse {
322
324
  constructor(worker: Worker, get: Response);
323
325
  }
326
+ /**
327
+ * Response for OPTIONS preflight requests.
328
+ * Sets CORS headers and returns 204 No Content.
329
+ */
330
+ declare class Options extends SuccessResponse {
331
+ constructor(worker: Worker);
332
+ }
324
333
 
325
334
  /**
326
335
  * Generic HTTP error response.
@@ -553,94 +562,9 @@ declare abstract class Middleware {
553
562
  abstract handle(worker: Worker, next: () => Promise<Response>): Promise<Response>;
554
563
  }
555
564
 
556
- /**
557
- * Middleware that applies Cross-Origin Resource Sharing (CORS) headers to responses.
558
- *
559
- * Merges the initialization config (if provided), with {@link defaultCorsConfig}.
560
- *
561
- * ⚠️ **Important:** This middleware needs to run **after any caching**.
562
- * Otherwise, CORS headers can end up cached and cause unexpected errors.
563
- *
564
- * Example Worker:
565
- * ```ts
566
- * // Request → [CorsHandler] → [CacheHandler] → [Worker Handler]
567
- * // Response ← [CorsHandler] ← [CacheHandler] ↙
568
- * protected override init(): void {
569
- * worker.use(new CorsHandler());
570
- * worker.use(new CacheHandler());
571
- * }
572
- * ```
573
- */
574
- declare class CorsHandler extends Middleware {
575
- /** The configuration used for this instance, with all defaults applied. */
576
- private readonly config;
577
- /**
578
- * Create a new CORS middleware instance.
579
- *
580
- * @param init - Partial configuration to override the defaults. Any values
581
- * not provided will use `defaultCorsConfig`.
582
- */
583
- constructor(init?: CorsInit);
584
- /**
585
- * Handle a request by applying CORS headers to the response.
586
- *
587
- * @param worker - The Worker instance containing the request context.
588
- * @param next - Function to invoke the next middleware in the chain.
589
- * @returns A Response object with CORS headers applied.
590
- *
591
- * This middleware does not short-circuit the request; it always calls `next()`
592
- * and modifies the resulting response.
593
- */
594
- handle(worker: Worker, next: () => Promise<Response>): Promise<Response>;
595
- }
565
+ declare function cors(init?: CorsInit): Middleware;
596
566
 
597
- /**
598
- * Middleware for caching GET requests.
599
- *
600
- * This middleware checks a cache (either a named cache or the default)
601
- * before passing the request down the middleware chain. Responses for
602
- * successful GET requests are automatically stored in the cache.
603
- *
604
- * Non-GET requests are never cached. The cache key can be customized
605
- * via the `getKey` function; otherwise, the URL is normalized and used.
606
- *
607
- * ```ts
608
- * worker.use(new CacheHandler());
609
- * ```
610
- */
611
- declare class CacheHandler extends Middleware {
612
- protected readonly cacheName?: string | undefined;
613
- protected readonly getKey?: ((request: Request) => URL | RequestInfo) | undefined;
614
- /**
615
- * @param cacheName - Optional name of the cache to use. If omitted,
616
- * `caches.default` is used.
617
- * @param getKey - Optional function to generate a cache key from a request.
618
- * Defaults to using the normalized request URL.
619
- */
620
- constructor(cacheName?: string | undefined, getKey?: ((request: Request) => URL | RequestInfo) | undefined);
621
- /**
622
- * Handle a request in the caching middleware.
623
- *
624
- * Checks the cache for GET requests and returns the cached response if available.
625
- * Otherwise, calls `next()` to continue the middleware chain and caches
626
- * the response if successful.
627
- *
628
- * @param worker - The Worker instance containing the request context.
629
- * @param next - Function to invoke the next middleware in the chain.
630
- * @returns A Response object, either from cache or the next middleware.
631
- */
632
- handle(worker: Worker, next: () => Promise<Response>): Promise<Response>;
633
- /**
634
- * Generate the cache key for a request.
635
- *
636
- * @param request - The Request object to generate a cache key for.
637
- * @returns A URL or RequestInfo used as the cache key.
638
- *
639
- * If a custom `getKey` function was provided in the constructor, it is used.
640
- * Otherwise, the request URL is normalized.
641
- */
642
- private getCacheKey;
643
- }
567
+ declare function cache(cacheName?: string, getKey?: (request: Request) => URL | RequestInfo): Middleware;
644
568
 
645
569
  /**
646
570
  * A type-safe Cloudflare Worker handler.
@@ -694,6 +618,9 @@ declare abstract class BaseWorker implements Worker {
694
618
  protected abstract dispatch(): Promise<Response>;
695
619
  /**
696
620
  * DEFAULT allowed HTTP methods for subclasses.
621
+ *
622
+ * These defaults were selected for getting started quickly and should be
623
+ * overridden for the specific worker.
697
624
  */
698
625
  getAllowedMethods(): Method[];
699
626
  /**
@@ -775,11 +702,13 @@ declare abstract class BasicWorker extends MiddlewareWorker {
775
702
  protected patch(): Promise<Response>;
776
703
  /** Override and implement this method for DELETE requests. */
777
704
  protected delete(): Promise<Response>;
705
+ /** Override and implement this method for OPTIONS requests. */
706
+ protected options(): Promise<Response>;
778
707
  /**
779
708
  * Default handler for HEAD requests.
780
709
  * Performs a GET request and removes the body for HEAD semantics.
781
710
  *
782
- * Usually does not need to be overridden, as this behavior covers
711
+ * Usually does not need to be overridden as this behavior covers
783
712
  * standard HEAD requirements.
784
713
  */
785
714
  protected head(): Promise<Response>;
@@ -863,6 +792,7 @@ declare abstract class RouteWorker extends BasicWorker {
863
792
  protected post(): Promise<Response>;
864
793
  protected patch(): Promise<Response>;
865
794
  protected delete(): Promise<Response>;
795
+ protected options(): Promise<Response>;
866
796
  }
867
797
 
868
- export { BadRequest, BasicWorker, CacheControl, CacheHandler, ClonedResponse, type CorsConfig, CorsHandler, type CorsInit, DELETE, type ErrorJson, Forbidden, GET, HEAD, Head, HtmlResponse, HttpError, HttpHeader, InternalServerError, JsonResponse, type MatchedRoute, MediaType, Method, MethodNotAllowed, MethodNotImplemented, Middleware, NotFound, NotImplemented, PATCH, POST, PUT, type PathParams, type Route, type RouteCallback, type RouteHandler, type RouteTable, type RouteTuple, RouteWorker, ServiceUnavailable, SuccessResponse, TextResponse, Time, Unauthorized, type Worker, type WorkerClass, WorkerResponse, getContentType, getOrigin, isMethod, lexCompare, mergeHeader, normalizeUrl, setHeader };
798
+ export { BadRequest, BasicWorker, CacheControl, ClonedResponse, type CorsConfig, type CorsInit, DELETE, type ErrorJson, Forbidden, GET, HEAD, Head, HtmlResponse, HttpError, HttpHeader, InternalServerError, JsonResponse, type MatchedRoute, MediaType, Method, MethodNotAllowed, MethodNotImplemented, Middleware, NotFound, NotImplemented, OPTIONS, Options, PATCH, POST, PUT, type PathParams, type Route, type RouteCallback, type RouteHandler, type RouteTable, type RouteTuple, RouteWorker, ServiceUnavailable, SuccessResponse, TextResponse, Time, Unauthorized, type Worker, type WorkerClass, WorkerResponse, cache, cors, getContentType, getOrigin, isMethod, lexCompare, mergeHeader, normalizeUrl, setHeader };
package/dist/index.js CHANGED
@@ -57,9 +57,10 @@ var Method = /* @__PURE__ */ ((Method4) => {
57
57
  Method4["POST"] = "POST";
58
58
  Method4["PATCH"] = "PATCH";
59
59
  Method4["DELETE"] = "DELETE";
60
+ Method4["OPTIONS"] = "OPTIONS";
60
61
  return Method4;
61
62
  })(Method || {});
62
- var { GET, PUT, HEAD, POST, PATCH, DELETE } = Method;
63
+ var { GET, PUT, HEAD, POST, PATCH, DELETE, OPTIONS } = Method;
63
64
  var METHOD_SET = new Set(Object.values(Method));
64
65
  function isMethod(value) {
65
66
  return METHOD_SET.has(value);
@@ -165,7 +166,8 @@ function lexCompare(a, b) {
165
166
  return 0;
166
167
  }
167
168
  function getOrigin(request) {
168
- return request.headers.get(HttpHeader.ORIGIN);
169
+ const origin = request.headers.get(HttpHeader.ORIGIN);
170
+ return origin ? origin.trim() : null;
169
171
  }
170
172
 
171
173
  // src/errors.ts
@@ -174,8 +176,7 @@ import { getReasonPhrase as getReasonPhrase2 } from "http-status-codes";
174
176
  // src/responses.ts
175
177
  import { getReasonPhrase, StatusCodes as StatusCodes2 } from "http-status-codes";
176
178
  var BaseResponse = class {
177
- constructor(worker) {
178
- this.worker = worker;
179
+ constructor() {
179
180
  }
180
181
  /** HTTP headers for the response. */
181
182
  headers = new Headers();
@@ -183,8 +184,8 @@ var BaseResponse = class {
183
184
  status = StatusCodes2.OK;
184
185
  /** Optional status text. Defaults to standard reason phrase. */
185
186
  statusText;
186
- /** Optional media type of the response body. */
187
- mediaType;
187
+ /** Default media type of the response body. */
188
+ mediaType = "text/plain" /* PLAIN_TEXT */;
188
189
  /** Converts current state to ResponseInit for constructing a Response. */
189
190
  get responseInit() {
190
191
  return {
@@ -201,17 +202,17 @@ var BaseResponse = class {
201
202
  mergeHeader(key, value) {
202
203
  mergeHeader(this.headers, key, value);
203
204
  }
204
- /** Adds a Content-Type header based on the media type if set. */
205
+ /** Adds a Content-Type header if not already existing (does not overwrite). */
205
206
  addContentType() {
206
- if (this.mediaType) {
207
+ if (!this.headers.get(HttpHeader.CONTENT_TYPE)) {
207
208
  this.headers.set(HttpHeader.CONTENT_TYPE, getContentType(this.mediaType));
208
209
  }
209
210
  }
210
211
  };
211
212
  var CacheResponse = class extends BaseResponse {
212
- constructor(worker, cache) {
213
- super(worker);
214
- this.cache = cache;
213
+ constructor(cache2) {
214
+ super();
215
+ this.cache = cache2;
215
216
  }
216
217
  /** Adds Cache-Control header if caching is configured. */
217
218
  addCacheHeader() {
@@ -221,8 +222,9 @@ var CacheResponse = class extends BaseResponse {
221
222
  }
222
223
  };
223
224
  var WorkerResponse = class extends CacheResponse {
224
- constructor(worker, body = null, cache) {
225
- super(worker, cache);
225
+ constructor(worker, body = null, cache2) {
226
+ super(cache2);
227
+ this.worker = worker;
226
228
  this.body = body;
227
229
  }
228
230
  /** Builds the Response object with body, headers, and status. */
@@ -234,35 +236,35 @@ var WorkerResponse = class extends CacheResponse {
234
236
  }
235
237
  };
236
238
  var ClonedResponse = class extends WorkerResponse {
237
- constructor(worker, response, cache) {
239
+ constructor(worker, response, cache2) {
238
240
  const clone = response.clone();
239
- super(worker, clone.body, cache);
241
+ super(worker, clone.body, cache2);
240
242
  this.headers = new Headers(clone.headers);
241
243
  this.status = clone.status;
242
244
  this.statusText = clone.statusText;
243
245
  }
244
246
  };
245
247
  var SuccessResponse = class extends WorkerResponse {
246
- constructor(worker, body = null, cache, status = StatusCodes2.OK) {
247
- super(worker, body, cache);
248
+ constructor(worker, body = null, cache2, status = StatusCodes2.OK) {
249
+ super(worker, body, cache2);
248
250
  this.status = status;
249
251
  }
250
252
  };
251
253
  var JsonResponse = class extends SuccessResponse {
252
- constructor(worker, json = {}, cache, status = StatusCodes2.OK) {
253
- super(worker, JSON.stringify(json), cache, status);
254
+ constructor(worker, json = {}, cache2, status = StatusCodes2.OK) {
255
+ super(worker, JSON.stringify(json), cache2, status);
254
256
  this.mediaType = "application/json" /* JSON */;
255
257
  }
256
258
  };
257
259
  var HtmlResponse = class extends SuccessResponse {
258
- constructor(worker, body, cache, status = StatusCodes2.OK) {
259
- super(worker, body, cache, status);
260
+ constructor(worker, body, cache2, status = StatusCodes2.OK) {
261
+ super(worker, body, cache2, status);
260
262
  this.mediaType = "text/html" /* HTML */;
261
263
  }
262
264
  };
263
265
  var TextResponse = class extends SuccessResponse {
264
- constructor(worker, content, cache, status = StatusCodes2.OK) {
265
- super(worker, content, cache, status);
266
+ constructor(worker, content, cache2, status = StatusCodes2.OK) {
267
+ super(worker, content, cache2, status);
266
268
  this.mediaType = "text/plain" /* PLAIN_TEXT */;
267
269
  }
268
270
  };
@@ -272,6 +274,11 @@ var Head = class extends WorkerResponse {
272
274
  this.headers = new Headers(get.headers);
273
275
  }
274
276
  };
277
+ var Options = class extends SuccessResponse {
278
+ constructor(worker) {
279
+ super(worker, null, void 0, StatusCodes2.NO_CONTENT);
280
+ }
281
+ };
275
282
 
276
283
  // src/errors.ts
277
284
  var HttpError = class extends JsonResponse {
@@ -341,44 +348,27 @@ var ServiceUnavailable = class extends HttpError {
341
348
  }
342
349
  };
343
350
 
344
- // src/middleware/cors/constants.ts
345
- var OPTIONS = "OPTIONS";
346
- var defaultCorsConfig = {
347
- allowedOrigins: ["*"],
348
- // Origins allowed for CORS requests
349
- allowedHeaders: ["Content-Type"],
350
- // HTTP headers allowed in requests
351
- exposedHeaders: [],
352
- // Headers exposed to the client
353
- maxAge: Time.Week
354
- // Max age in seconds for preflight caching
355
- };
356
-
357
351
  // src/middleware/cors/utils.ts
358
- function addCorsHeaders(worker, cors, headers) {
352
+ function addCorsHeaders(worker, cors2, headers) {
359
353
  deleteCorsHeaders(headers);
360
354
  const origin = getOrigin(worker.request);
361
- if (!origin || !isCors(worker.request)) return;
362
- if (allowAnyOrigin(cors)) {
355
+ if (!origin) return;
356
+ if (allowAnyOrigin(cors2)) {
363
357
  setHeader(headers, HttpHeader.ALLOW_ORIGIN, HttpHeader.ALLOW_ALL_ORIGINS);
364
358
  } else {
365
359
  mergeHeader(headers, HttpHeader.VARY, HttpHeader.ORIGIN);
366
- if (cors.allowedOrigins.includes(origin)) {
360
+ if (cors2.allowedOrigins.includes(origin)) {
367
361
  setHeader(headers, HttpHeader.ALLOW_ORIGIN, origin);
368
362
  setHeader(headers, HttpHeader.ALLOW_CREDENTIALS, "true");
369
363
  }
370
364
  }
371
- setHeader(headers, HttpHeader.MAX_AGE, String(cors.maxAge));
372
- setHeader(headers, HttpHeader.ALLOW_HEADERS, cors.allowedHeaders);
373
- mergeHeader(headers, HttpHeader.ALLOW_METHODS, [...worker.getAllowedMethods(), OPTIONS]);
374
- mergeHeader(headers, HttpHeader.EXPOSE_HEADERS, cors.exposedHeaders);
365
+ setHeader(headers, HttpHeader.MAX_AGE, String(cors2.maxAge));
366
+ setHeader(headers, HttpHeader.ALLOW_HEADERS, cors2.allowedHeaders);
367
+ mergeHeader(headers, HttpHeader.ALLOW_METHODS, worker.getAllowedMethods());
368
+ mergeHeader(headers, HttpHeader.EXPOSE_HEADERS, cors2.exposedHeaders);
375
369
  }
376
- function allowAnyOrigin(cors) {
377
- return cors.allowedOrigins.includes("*");
378
- }
379
- function isCors(request) {
380
- const site = request.headers.get(HttpHeader.SEC_FETCH_SITE);
381
- return site === HttpHeader.CROSS_SITE;
370
+ function allowAnyOrigin(cors2) {
371
+ return cors2.allowedOrigins.includes("*");
382
372
  }
383
373
  function deleteCorsHeaders(headers) {
384
374
  headers.delete(HttpHeader.MAX_AGE);
@@ -393,7 +383,22 @@ function deleteCorsHeaders(headers) {
393
383
  var Middleware = class {
394
384
  };
395
385
 
386
+ // src/middleware/cors/constants.ts
387
+ var defaultCorsConfig = {
388
+ allowedOrigins: ["*"],
389
+ // Origins allowed for CORS requests
390
+ allowedHeaders: ["Content-Type"],
391
+ // HTTP headers allowed in requests
392
+ exposedHeaders: [],
393
+ // Headers exposed to the client
394
+ maxAge: Time.Week
395
+ // Max age in seconds for preflight caching
396
+ };
397
+
396
398
  // src/middleware/cors/handler.ts
399
+ function cors(init) {
400
+ return new CorsHandler(init);
401
+ }
397
402
  var CorsHandler = class extends Middleware {
398
403
  /** The configuration used for this instance, with all defaults applied. */
399
404
  config;
@@ -413,9 +418,6 @@ var CorsHandler = class extends Middleware {
413
418
  * @param worker - The Worker instance containing the request context.
414
419
  * @param next - Function to invoke the next middleware in the chain.
415
420
  * @returns A Response object with CORS headers applied.
416
- *
417
- * This middleware does not short-circuit the request; it always calls `next()`
418
- * and modifies the resulting response.
419
421
  */
420
422
  async handle(worker, next) {
421
423
  if (worker.request.method === OPTIONS) {
@@ -424,18 +426,16 @@ var CorsHandler = class extends Middleware {
424
426
  return options.getResponse();
425
427
  }
426
428
  const response = await next();
427
- const mutable = new Response(response.body, response);
428
- addCorsHeaders(worker, this.config, mutable.headers);
429
- return mutable;
430
- }
431
- };
432
- var Options = class extends SuccessResponse {
433
- constructor(worker) {
434
- super(worker, null, void 0, StatusCodes.NO_CONTENT);
429
+ const clone = new ClonedResponse(worker, response);
430
+ addCorsHeaders(worker, this.config, clone.headers);
431
+ return clone.getResponse();
435
432
  }
436
433
  };
437
434
 
438
435
  // src/middleware/cache/handler.ts
436
+ function cache(cacheName, getKey) {
437
+ return new CacheHandler(cacheName, getKey);
438
+ }
439
439
  var CacheHandler = class extends Middleware {
440
440
  /**
441
441
  * @param cacheName - Optional name of the cache to use. If omitted,
@@ -460,14 +460,14 @@ var CacheHandler = class extends Middleware {
460
460
  * @returns A Response object, either from cache or the next middleware.
461
461
  */
462
462
  async handle(worker, next) {
463
- const cache = this.cacheName ? await caches.open(this.cacheName) : caches.default;
463
+ const cache2 = this.cacheName ? await caches.open(this.cacheName) : caches.default;
464
464
  if (worker.request.method === GET) {
465
- const cached = await cache.match(this.getCacheKey(worker.request));
465
+ const cached = await cache2.match(this.getCacheKey(worker.request));
466
466
  if (cached) return cached;
467
467
  }
468
468
  const response = await next();
469
469
  if (worker.request.method === GET && response.ok) {
470
- worker.ctx.waitUntil(cache.put(this.getCacheKey(worker.request), response.clone()));
470
+ worker.ctx.waitUntil(cache2.put(this.getCacheKey(worker.request), response.clone()));
471
471
  }
472
472
  return response;
473
473
  }
@@ -506,9 +506,12 @@ var BaseWorker = class {
506
506
  }
507
507
  /**
508
508
  * DEFAULT allowed HTTP methods for subclasses.
509
+ *
510
+ * These defaults were selected for getting started quickly and should be
511
+ * overridden for the specific worker.
509
512
  */
510
513
  getAllowedMethods() {
511
- return [GET, HEAD];
514
+ return [GET, HEAD, OPTIONS];
512
515
  }
513
516
  /**
514
517
  * Creates a new instance of the current Worker subclass.
@@ -595,7 +598,8 @@ var BasicWorker = class extends MiddlewareWorker {
595
598
  HEAD: () => this.head(),
596
599
  POST: () => this.post(),
597
600
  PATCH: () => this.patch(),
598
- DELETE: () => this.delete()
601
+ DELETE: () => this.delete(),
602
+ OPTIONS: () => this.options()
599
603
  };
600
604
  return (handler[method] ?? (() => this.getResponse(MethodNotAllowed)))();
601
605
  }
@@ -633,11 +637,15 @@ var BasicWorker = class extends MiddlewareWorker {
633
637
  async delete() {
634
638
  return this.getResponse(MethodNotImplemented);
635
639
  }
640
+ /** Override and implement this method for OPTIONS requests. */
641
+ async options() {
642
+ return this.getResponse(MethodNotImplemented);
643
+ }
636
644
  /**
637
645
  * Default handler for HEAD requests.
638
646
  * Performs a GET request and removes the body for HEAD semantics.
639
647
  *
640
- * Usually does not need to be overridden, as this behavior covers
648
+ * Usually does not need to be overridden as this behavior covers
641
649
  * standard HEAD requirements.
642
650
  */
643
651
  async head() {
@@ -789,14 +797,15 @@ var RouteWorker = class _RouteWorker extends BasicWorker {
789
797
  async delete() {
790
798
  return this.getResponse(NotFound);
791
799
  }
800
+ async options() {
801
+ return this.getResponse(NotFound);
802
+ }
792
803
  };
793
804
  export {
794
805
  BadRequest,
795
806
  BasicWorker,
796
807
  CacheControl,
797
- CacheHandler,
798
808
  ClonedResponse,
799
- CorsHandler,
800
809
  DELETE,
801
810
  Forbidden,
802
811
  GET,
@@ -814,6 +823,8 @@ export {
814
823
  Middleware,
815
824
  NotFound,
816
825
  NotImplemented,
826
+ OPTIONS,
827
+ Options,
817
828
  PATCH,
818
829
  POST,
819
830
  PUT,
@@ -825,6 +836,8 @@ export {
825
836
  Time,
826
837
  Unauthorized,
827
838
  WorkerResponse,
839
+ cache,
840
+ cors,
828
841
  getContentType,
829
842
  getOrigin,
830
843
  isMethod,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/common.ts","../src/errors.ts","../src/responses.ts","../src/middleware/cors/constants.ts","../src/middleware/cors/utils.ts","../src/middleware/middleware.ts","../src/middleware/cors/handler.ts","../src/middleware/cache/handler.ts","../src/workers/base-worker.ts","../src/workers/middleware-worker.ts","../src/workers/basic-worker.ts","../src/routes.ts","../src/workers/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 USER_AGENT = \"User-Agent\";\n export const CONTENT_TYPE = \"Content-Type\";\n export const CACHE_CONTROL = \"Cache-Control\";\n export const SEC_FETCH_SITE = \"Sec-Fetch-Site\";\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 // Cors Headers\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\n // Values\n export const ORIGIN = \"Origin\";\n export const ALLOW_ALL_ORIGINS = \"*\";\n export const CROSS_SITE = \"cross-site\";\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}\n\n/**\n * Shorthand constants for each HTTP method.\n *\n * These are equivalent to the corresponding enum members in `Method`.\n * For example, `GET === Method.GET`.\n */\nexport const { GET, PUT, HEAD, POST, PATCH, DELETE } = Method;\n\n/**\n * A set containing all supported HTTP methods.\n *\n * Useful for runtime checks like validating request methods.\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 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, any 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(lexCompare);\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]) => lexCompare(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 * Lexicographically compares two strings.\n *\n * This comparator can be used in `Array.prototype.sort()` to produce a\n * consistent, stable ordering of string arrays.\n *\n * @param a - The first string to compare.\n * @param b - The second string to compare.\n * @returns A number indicating the relative order of `a` and `b`.\n */\nexport function lexCompare(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 { getReasonPhrase } from \"http-status-codes\";\nimport { CacheControl, HttpHeader, StatusCodes } from \"./common\";\nimport { JsonResponse } from \"./responses\";\nimport { Worker } from \"./interfaces/worker\";\nimport { ErrorJson } from \"./interfaces/error-json\";\n\n/**\n * Generic HTTP error response.\n * Sends a JSON body with status, error message, and details.\n */\nexport class HttpError extends JsonResponse {\n /**\n * @param worker The worker handling the request.\n * @param status HTTP status code.\n * @param details Optional detailed error message.\n */\n constructor(\n worker: Worker,\n status: StatusCodes,\n protected readonly details?: string,\n ) {\n const json: ErrorJson = {\n status,\n error: getReasonPhrase(status),\n details: details ?? \"\",\n };\n super(worker, json, CacheControl.DISABLE, status);\n }\n}\n\n/** 400 Bad Request error response. */\nexport class BadRequest extends HttpError {\n constructor(worker: Worker, details?: string) {\n super(worker, StatusCodes.BAD_REQUEST, details);\n }\n}\n\n/** 401 Unauthorized error response. */\nexport class Unauthorized extends HttpError {\n constructor(worker: Worker, details?: string) {\n super(worker, StatusCodes.UNAUTHORIZED, details);\n }\n}\n\n/** 403 Forbidden error response. */\nexport class Forbidden extends HttpError {\n constructor(worker: Worker, details?: string) {\n super(worker, StatusCodes.FORBIDDEN, details);\n }\n}\n\n/** 404 Not Found error response. */\nexport class NotFound extends HttpError {\n constructor(worker: Worker, details?: string) {\n super(worker, StatusCodes.NOT_FOUND, details);\n }\n}\n\n/** 405 Method Not Allowed error response. */\nexport class MethodNotAllowed extends HttpError {\n constructor(worker: Worker) {\n super(\n worker,\n StatusCodes.METHOD_NOT_ALLOWED,\n `${worker.request.method} method not allowed.`,\n );\n this.setHeader(HttpHeader.ALLOW, this.worker.getAllowedMethods());\n }\n}\n\n/** 500 Internal Server Error response. */\nexport class InternalServerError extends HttpError {\n constructor(worker: Worker, details?: string) {\n super(worker, StatusCodes.INTERNAL_SERVER_ERROR, details);\n }\n}\n\n/** 501 Not Implemented error response. */\nexport class NotImplemented extends HttpError {\n constructor(worker: Worker, details?: string) {\n super(worker, StatusCodes.NOT_IMPLEMENTED, details);\n }\n}\n\n/** 501 Method Not Implemented error response for unsupported HTTP methods. */\nexport class MethodNotImplemented extends NotImplemented {\n constructor(worker: Worker) {\n super(worker, `${worker.request.method} method not implemented.`);\n }\n}\n\n/** 503 Service Unavailable error response. */\nexport class ServiceUnavailable extends HttpError {\n constructor(worker: Worker, 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} from \"./common\";\nimport { Worker } from \"./interfaces/worker\";\n\n/**\n * Base class for building HTTP responses.\n * Manages headers, status, and media type.\n */\nabstract class BaseResponse {\n constructor(public readonly worker: Worker) {}\n\n /** HTTP headers for the response. */\n public headers: Headers = new Headers();\n\n /** HTTP status code (default 200 OK). */\n public status: StatusCodes = StatusCodes.OK;\n\n /** Optional status text. Defaults to standard reason phrase. */\n public statusText?: string;\n\n /** Optional media type of the response body. */\n public mediaType?: MediaType;\n\n /** Converts current state to ResponseInit for constructing a Response. */\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 /** Sets a header, overwriting any existing value. */\n public setHeader(key: string, value: string | string[]): void {\n setHeader(this.headers, key, value);\n }\n\n /** Merges a header with existing values (does not overwrite). */\n public mergeHeader(key: string, value: string | string[]): void {\n mergeHeader(this.headers, key, value);\n }\n\n /** Adds a Content-Type header based on the media type if set. */\n public addContentType() {\n if (this.mediaType) {\n this.headers.set(HttpHeader.CONTENT_TYPE, getContentType(this.mediaType));\n }\n }\n}\n\n/**\n * Base response class that adds caching headers.\n */\nabstract class CacheResponse extends BaseResponse {\n constructor(\n worker: Worker,\n public cache?: CacheControl,\n ) {\n super(worker);\n }\n\n /** Adds Cache-Control header if caching is configured. */\n protected addCacheHeader(): void {\n if (this.cache) {\n this.headers.set(HttpHeader.CACHE_CONTROL, CacheControl.stringify(this.cache));\n }\n }\n}\n\n/**\n * Core worker response. Combines caching, and security headers.\n */\nexport abstract class WorkerResponse extends CacheResponse {\n constructor(\n worker: Worker,\n private readonly body: BodyInit | null = null,\n cache?: CacheControl,\n ) {\n super(worker, cache);\n }\n\n /** Builds the Response object with body, headers, and status. */\n public async getResponse(): Promise<Response> {\n this.addCacheHeader();\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\n/**\n * Wraps an existing Response and clones its body, headers, and status.\n */\nexport class ClonedResponse extends WorkerResponse {\n constructor(worker: Worker, 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\n/**\n * Represents a successful response with customizable body and status.\n */\nexport class SuccessResponse extends WorkerResponse {\n constructor(\n worker: Worker,\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\n/**\n * JSON response. Automatically sets Content-Type to application/json.\n */\nexport class JsonResponse extends SuccessResponse {\n constructor(\n worker: Worker,\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\n/**\n * HTML response. Automatically sets Content-Type to text/html.\n */\nexport class HtmlResponse extends SuccessResponse {\n constructor(\n worker: Worker,\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\n/**\n * Plain text response. Automatically sets Content-Type to text/plain.\n */\nexport class TextResponse extends SuccessResponse {\n constructor(\n worker: Worker,\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 * Response for HEAD requests. Clones headers but has no body.\n */\nexport class Head extends WorkerResponse {\n constructor(worker: Worker, get: Response) {\n super(worker);\n this.headers = new Headers(get.headers);\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 { Time } from \"../../common\";\nimport { CorsConfig } from \"../../interfaces/cors-config\";\n\nexport const OPTIONS = \"OPTIONS\";\n\n/**\n * Default configuration for CORS middleware.\n */\nexport const defaultCorsConfig: CorsConfig = {\n allowedOrigins: [\"*\"], // Origins allowed for CORS requests\n allowedHeaders: [\"Content-Type\"], // HTTP headers allowed in requests\n exposedHeaders: [], // Headers exposed to the client\n maxAge: Time.Week, // Max age in seconds for preflight caching\n} as const;\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, HttpHeader, mergeHeader, setHeader } from \"../../common\";\nimport { CorsConfig } from \"../../interfaces/cors-config\";\nimport { Worker } from \"../../interfaces/worker\";\nimport { OPTIONS } from \"./constants\";\n\n/**\n * Adds CORS headers to the given Headers object based on the request and config.\n */\nexport function addCorsHeaders(worker: Worker, cors: CorsConfig, headers: Headers): void {\n deleteCorsHeaders(headers);\n\n const origin = getOrigin(worker.request);\n if (!origin || !isCors(worker.request)) return;\n\n if (allowAnyOrigin(cors)) {\n // Allowed Origin: *\n setHeader(headers, HttpHeader.ALLOW_ORIGIN, HttpHeader.ALLOW_ALL_ORIGINS);\n } else {\n // Allowed Origin: \"https://example.com\"\n // Always add Vary: Origin\n mergeHeader(headers, HttpHeader.VARY, HttpHeader.ORIGIN);\n\n if (cors.allowedOrigins.includes(origin)) {\n // When the provided origin is allowed:\n setHeader(headers, HttpHeader.ALLOW_ORIGIN, origin);\n setHeader(headers, HttpHeader.ALLOW_CREDENTIALS, \"true\");\n }\n }\n\n // Add for all CORS requests.\n setHeader(headers, HttpHeader.MAX_AGE, String(cors.maxAge));\n setHeader(headers, HttpHeader.ALLOW_HEADERS, cors.allowedHeaders);\n mergeHeader(headers, HttpHeader.ALLOW_METHODS, [...worker.getAllowedMethods(), OPTIONS]);\n mergeHeader(headers, HttpHeader.EXPOSE_HEADERS, cors.exposedHeaders);\n}\n\n/** Returns true if the CORS config allows all origins (`*`). */\nexport function allowAnyOrigin(cors: CorsConfig): boolean {\n return cors.allowedOrigins.includes(\"*\");\n}\n\n/**\n * Determines whether a given request is a cross-origin request that requires CORS headers.\n *\n * @param request - The incoming Request object.\n * @returns `true` if the request is cross-origin and should have CORS headers, `false` otherwise.\n */\nfunction isCors(request: Request): boolean {\n const site = request.headers.get(HttpHeader.SEC_FETCH_SITE);\n return site === HttpHeader.CROSS_SITE;\n}\n\n/** Removes all standard CORS headers from a Headers object. */\nfunction deleteCorsHeaders(headers: Headers): void {\n headers.delete(HttpHeader.MAX_AGE);\n headers.delete(HttpHeader.ALLOW_ORIGIN);\n headers.delete(HttpHeader.ALLOW_HEADERS);\n headers.delete(HttpHeader.ALLOW_METHODS);\n headers.delete(HttpHeader.EXPOSE_HEADERS);\n headers.delete(HttpHeader.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 { Worker } from \"../interfaces/worker\";\n\n/**\n * Abstract base class for middleware.\n *\n * Middleware classes implement request/response processing logic in a\n * chainable manner. Each middleware receives a `Worker` object and a\n * `next` function that invokes the next middleware in the chain.\n *\n * Subclasses **must implement** the `handle` method.\n *\n * Example subclass:\n * ```ts\n * class LoggingMiddleware extends Middleware {\n * public async handle(worker: Worker, next: () => Promise<Response>): Promise<Response> {\n * console.log(`Processing request: ${worker.request.url}`);\n * const response = await next();\n * console.log(`Response status: ${response.status}`);\n * return response;\n * }\n * }\n * ```\n */\nexport abstract class Middleware {\n /**\n * Process a request in the middleware chain.\n *\n * @param worker - The `Worker` instance representing the request context.\n * @param next - Function to invoke the next middleware in the chain.\n * Must be called to continue the chain unless the middleware\n * terminates early (e.g., returns a response directly).\n * @returns A `Response` object, either returned directly or from `next()`.\n */\n public abstract handle(worker: Worker, next: () => Promise<Response>): Promise<Response>;\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 { addCorsHeaders } from \"./utils\";\nimport { Worker } from \"../../interfaces/worker\";\nimport { Middleware } from \"../middleware\";\nimport { CorsConfig, CorsInit } from \"../../interfaces/cors-config\";\nimport { defaultCorsConfig, OPTIONS } from \"./constants\";\nimport { StatusCodes } from \"../../common\";\nimport { SuccessResponse } from \"../../responses\";\n\n/**\n * Middleware that applies Cross-Origin Resource Sharing (CORS) headers to responses.\n *\n * Merges the initialization config (if provided), with {@link defaultCorsConfig}.\n *\n * ⚠️ **Important:** This middleware needs to run **after any caching**.\n * Otherwise, CORS headers can end up cached and cause unexpected errors.\n *\n * Example Worker:\n * ```ts\n * // Request → [CorsHandler] → [CacheHandler] → [Worker Handler]\n * // Response ← [CorsHandler] ← [CacheHandler] ↙\n * protected override init(): void {\n * worker.use(new CorsHandler());\n * worker.use(new CacheHandler());\n * }\n * ```\n */\nexport class CorsHandler extends Middleware {\n /** The configuration used for this instance, with all defaults applied. */\n private readonly config: CorsConfig;\n\n /**\n * Create a new CORS middleware instance.\n *\n * @param init - Partial configuration to override the defaults. Any values\n * not provided will use `defaultCorsConfig`.\n */\n constructor(init?: CorsInit) {\n super();\n this.config = { ...defaultCorsConfig, ...init };\n }\n\n /**\n * Handle a request by applying CORS headers to the response.\n *\n * @param worker - The Worker instance containing the request context.\n * @param next - Function to invoke the next middleware in the chain.\n * @returns A Response object with CORS headers applied.\n *\n * This middleware does not short-circuit the request; it always calls `next()`\n * and modifies the resulting response.\n */\n public override async handle(worker: Worker, next: () => Promise<Response>): Promise<Response> {\n if (worker.request.method === OPTIONS) {\n const options = new Options(worker);\n addCorsHeaders(worker, this.config, options.headers);\n return options.getResponse();\n }\n\n const response = await next();\n\n const mutable = new Response(response.body, response);\n addCorsHeaders(worker, this.config, mutable.headers);\n return mutable;\n }\n}\n\n/**\n * Response for OPTIONS preflight requests.\n * Sets CORS headers and returns 204 No Content.\n */\nclass Options extends SuccessResponse {\n constructor(worker: Worker) {\n super(worker, null, undefined, StatusCodes.NO_CONTENT);\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 { GET, normalizeUrl } from \"../../common\";\nimport { Middleware } from \"../middleware\";\nimport { Worker } from \"../../interfaces/worker\";\n\n/**\n * Middleware for caching GET requests.\n *\n * This middleware checks a cache (either a named cache or the default)\n * before passing the request down the middleware chain. Responses for\n * successful GET requests are automatically stored in the cache.\n *\n * Non-GET requests are never cached. The cache key can be customized\n * via the `getKey` function; otherwise, the URL is normalized and used.\n *\n * ```ts\n * worker.use(new CacheHandler());\n * ```\n */\nexport class CacheHandler extends Middleware {\n /**\n * @param cacheName - Optional name of the cache to use. If omitted,\n * `caches.default` is used.\n * @param getKey - Optional function to generate a cache key from a request.\n * Defaults to using the normalized request URL.\n */\n constructor(\n protected readonly cacheName?: string,\n protected readonly getKey?: (request: Request) => URL | RequestInfo,\n ) {\n super();\n }\n\n /**\n * Handle a request in the caching middleware.\n *\n * Checks the cache for GET requests and returns the cached response if available.\n * Otherwise, calls `next()` to continue the middleware chain and caches\n * the response if successful.\n *\n * @param worker - The Worker instance containing the request context.\n * @param next - Function to invoke the next middleware in the chain.\n * @returns A Response object, either from cache or the next middleware.\n */\n public override async handle(worker: Worker, next: () => Promise<Response>): Promise<Response> {\n const cache = this.cacheName ? await caches.open(this.cacheName) : caches.default;\n\n if (worker.request.method === GET) {\n const cached = await cache.match(this.getCacheKey(worker.request));\n if (cached) return cached;\n }\n\n const response = await next();\n\n if (worker.request.method === GET && response.ok) {\n worker.ctx.waitUntil(cache.put(this.getCacheKey(worker.request), response.clone()));\n }\n return response;\n }\n\n /**\n * Generate the cache key for a request.\n *\n * @param request - The Request object to generate a cache key for.\n * @returns A URL or RequestInfo used as the cache key.\n *\n * If a custom `getKey` function was provided in the constructor, it is used.\n * Otherwise, the request URL is normalized.\n */\n private getCacheKey(request: Request): URL | RequestInfo {\n return this.getKey ? this.getKey(request) : normalizeUrl(request.url);\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 { GET, HEAD, Method } from \"../common\";\nimport { FetchHandler } from \"../interfaces/fetch-handler\";\nimport { Worker, WorkerClass } from \"../interfaces/worker\";\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 * Dispatches the incoming request to the appropriate handler and produces a response.\n *\n * Subclasses must implement this method to define how the worker generates a `Response`\n * for the current request. This is the central point where request processing occurs.\n *\n * @returns A Promise that resolves to the `Response` for the request.\n */\n protected abstract dispatch(): Promise<Response>;\n\n /**\n * DEFAULT allowed HTTP methods for subclasses.\n */\n public getAllowedMethods(): Method[] {\n return [GET, HEAD];\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 WorkerClass<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 * ```ts\n * export default MyWorker.ignite();\n * ```\n */\n public static ignite<W extends Worker>(this: WorkerClass<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 { Middleware } from \"../middleware/middleware\";\n\n/** Internal base worker for handling middleware chains. */\nexport abstract class MiddlewareWorker extends BaseWorker {\n /** Middleware handlers registered for this worker. */\n protected readonly middlewares: Middleware[] = [];\n\n /**\n * Add a middleware instance to this worker.\n *\n * The middleware will run for every request handled by this worker,\n * in the order they are added.\n *\n * @param handler - The middleware to run.\n * @returns `this` to allow chaining multiple `.use()` calls.\n */\n public use(handler: Middleware): this {\n this.middlewares.push(handler);\n return this;\n }\n\n /**\n * Executes the middleware chain and dispatches the request.\n *\n * @returns The Response produced by the last middleware or `dispatch()`.\n */\n public override async fetch(): Promise<Response> {\n const chain = this.middlewares.reduceRight(\n (next, handler) => () => handler.handle(this, next),\n () => this.dispatch(),\n );\n return await chain();\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 { GET, isMethod, Method } from \"../common\";\nimport { MethodNotAllowed, InternalServerError, MethodNotImplemented } from \"../errors\";\nimport { MiddlewareWorker } from \"./middleware-worker\";\nimport { Head, WorkerResponse } from \"../responses\";\nimport { Worker } from \"../interfaces/worker\";\n\n/**\n * Basic worker class providing HTTP method dispatching and error handling.\n */\nexport abstract class BasicWorker extends MiddlewareWorker {\n /**\n * Entry point to handle a fetch request.\n */\n public override async fetch(): Promise<Response> {\n if (!this.isAllowed(this.request.method)) {\n return this.getResponse(MethodNotAllowed);\n }\n\n try {\n await this.init();\n return await super.fetch();\n } catch (error) {\n console.error(error);\n return this.getResponse(InternalServerError);\n }\n }\n\n /**\n * Dispatches the request to the method-specific handler.\n */\n protected override 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 };\n return (handler[method] ?? (() => this.getResponse(MethodNotAllowed)))();\n }\n\n /**\n * Hook for subclasses to perform any initialization.\n */\n protected init(): void | Promise<void> {\n return;\n }\n\n /**\n * Checks if the given HTTP method is allowed for this worker.\n * @param method HTTP method string\n * @returns true if the method is allowed\n */\n public isAllowed(method: string): boolean {\n return isMethod(method) && this.getAllowedMethods().includes(method);\n }\n\n /** Override and implement this method for GET requests. */\n protected async get(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n /** Override and implement this method for PUT requests. */\n protected async put(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n /** Override and implement this method for POST requests. */\n protected async post(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n /** Override and implement this method for PATCH requests. */\n protected async patch(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n /** Override and implement this method for DELETE requests. */\n protected async delete(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n /**\n * Default handler for HEAD requests.\n * Performs a GET request and removes the body for HEAD semantics.\n *\n * Usually does not need to be overridden, as this behavior covers\n * standard HEAD requirements.\n */\n protected async head(): Promise<Response> {\n const worker = this.create(new Request(this.request, { method: GET }));\n return this.getResponse(Head, await worker.fetch());\n }\n\n /**\n * Simplify and standardize {@link Response} creation by extending {@link WorkerResponse}\n * or any of its subclasses and passing to this method.\n *\n * Or directly use any of the built-in classes.\n *\n * ```ts\n * this.getResponse(TextResponse, \"Hello World!\")\n * ```\n *\n * @param ResponseClass The response class to instantiate\n * @param args Additional constructor arguments\n * @returns A Promise resolving to the {@link Response} object\n */\n protected async getResponse<\n T extends WorkerResponse,\n Ctor extends new (worker: Worker, ...args: any[]) => T,\n >(\n ResponseClass: Ctor,\n ...args: ConstructorParameters<Ctor> extends [Worker, ...infer R] ? R : never\n ): Promise<Response> {\n return new ResponseClass(this, ...args).getResponse();\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 { match } from \"path-to-regexp\";\nimport { Method } from \"./common\";\nimport { MatchedRoute, Route, PathParams, RouteTable } from \"./interfaces/route\";\n\n/**\n * Container for route definitions and matching logic.\n * Implements Iterable to allow iteration over all routes.\n */\nexport class Routes implements Iterable<Route> {\n /** Internal array of registered routes */\n private readonly routes: Route[] = [];\n\n /**\n * Add routes to the router.\n *\n * Accepts any iterable of [method, path, handler] tuples.\n * This includes arrays, Sets, or generators.\n *\n * @param routes - Iterable of route tuples to add.\n */\n public add(routes: RouteTable): void {\n for (const [method, path, handler] of routes) {\n const matcher = match<PathParams>(path);\n this.routes.push({ method, matcher, handler });\n }\n }\n\n /**\n * Attempt to match a URL against the registered routes.\n *\n * @param method - HTTP method of the request\n * @param url - Full URL string to match against\n * @returns A MatchedRoute object if a route matches, otherwise null\n */\n public match(method: Method, url: string): MatchedRoute | null {\n const pathname = new URL(url).pathname;\n\n for (const route of this) {\n if (route.method !== method) continue;\n\n const found = route.matcher(pathname);\n if (found) return { route, params: found.params };\n }\n\n return null;\n }\n\n /**\n * Iterate over all registered routes.\n */\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 { BasicWorker } from \"./basic-worker\";\nimport { Method } from \"../common\";\nimport { NotFound } from \"../errors\";\nimport { Routes } from \"../routes\";\nimport { RouteHandler, RouteTable } from \"../interfaces/route\";\nimport { WorkerClass } from \"../interfaces/worker\";\nimport { BaseWorker } from \"./base-worker\";\n\n/**\n * Base worker supporting route-based request handling.\n *\n * Subclass `RouteWorker` to define a worker with multiple route handlers.\n *\n * Routes can be registered individually via `route()` or in bulk via `routes()`.\n */\nexport abstract class RouteWorker extends BasicWorker {\n /** Internal table of registered routes. */\n private readonly _routes: Routes = new Routes();\n\n /**\n * Registers a single new route in the worker.\n *\n * When a request matches the specified method and path, the provided handler\n * will be executed. The handler can be either:\n * - A function that receives URL parameters, or\n * - A Worker subclass that will handle the request.\n *\n * @param method - HTTP method for the route (GET, POST, etc.).\n * @param path - URL path pattern (Express-style, e.g., \"/users/:id\").\n * @param handler - The function or Worker class to run when the route matches.\n * @returns The current worker instance, allowing method chaining.\n */\n protected route(method: Method, path: string, handler: RouteHandler): this {\n this.routes([[method, path, handler]]);\n return this;\n }\n\n /**\n * Registers multiple routes at once in the worker.\n *\n * Each route should be a tuple `[method, path, handler]` where:\n * - `method` - HTTP method for the route (GET, POST, etc.).\n * - `path` - URL path pattern (Express-style, e.g., \"/users/:id\").\n * - `handler` - A function that receives URL parameters or a Worker subclass\n * that will handle the request.\n *\n * @param routes - An iterable of routes to register. Each item is a `[method, path, handler]` tuple.\n * @returns The current worker instance, allowing method chaining.\n */\n protected routes(routes: RouteTable): this {\n this._routes.add(routes);\n return this;\n }\n\n /**\n * Matches the incoming request against registered routes and dispatches it.\n *\n * If a route is found:\n * - If the handler is a Worker class, a new instance is created and its `fetch()` is called.\n * - If the handler is a callback function, it is invoked with the extracted path parameters.\n *\n * If no route matches, the request is passed to the parent `dispatch()` handler.\n *\n * @returns A `Promise<Response>` from the matched handler or parent dispatch.\n */\n protected override 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 const { handler } = found.route;\n if (RouteWorker.isWorkerClass(handler)) {\n return new handler(this.request, this.env, this.ctx).fetch();\n }\n return handler.call(this, found.params);\n }\n\n /**\n * Runtime type guard to check if a given handler is a Worker class.\n *\n * A Worker class is any class that extends `BaseWorker`.\n *\n * @param handler - The constructor function to test.\n * @returns `true` if `handler` is a subclass of `BaseWorker` at runtime, `false` otherwise.\n */\n private static isWorkerClass(handler: RouteHandler): handler is WorkerClass {\n return BaseWorker.prototype.isPrototypeOf(handler.prototype);\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","getReasonPhrase","StatusCodes","StatusCodes","getReasonPhrase"]}
1
+ {"version":3,"sources":["../src/common.ts","../src/errors.ts","../src/responses.ts","../src/middleware/cors/utils.ts","../src/middleware/middleware.ts","../src/middleware/cors/constants.ts","../src/middleware/cors/handler.ts","../src/middleware/cache/handler.ts","../src/workers/base-worker.ts","../src/workers/middleware-worker.ts","../src/workers/basic-worker.ts","../src/routes.ts","../src/workers/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 USER_AGENT = \"User-Agent\";\n export const CONTENT_TYPE = \"Content-Type\";\n export const CACHE_CONTROL = \"Cache-Control\";\n export const SEC_FETCH_SITE = \"Sec-Fetch-Site\";\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 // Cors Headers\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\n // Values\n export const ORIGIN = \"Origin\";\n export const ALLOW_ALL_ORIGINS = \"*\";\n export const CROSS_SITE = \"cross-site\";\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}\n\n/**\n * Shorthand constants for each HTTP method.\n *\n * These are equivalent to the corresponding enum members in `Method`.\n * For example, `GET === Method.GET`.\n */\nexport const { GET, PUT, HEAD, POST, PATCH, DELETE, OPTIONS } = Method;\n\n/**\n * A set containing all supported HTTP methods.\n *\n * Useful for runtime checks like validating request methods.\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 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, any 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(lexCompare);\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]) => lexCompare(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 * Lexicographically compares two strings.\n *\n * This comparator can be used in `Array.prototype.sort()` to produce a\n * consistent, stable ordering of string arrays.\n *\n * @param a - The first string to compare.\n * @param b - The second string to compare.\n * @returns A number indicating the relative order of `a` and `b`.\n */\nexport function lexCompare(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 const origin = request.headers.get(HttpHeader.ORIGIN);\n return origin ? origin.trim() : null;\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 { JsonResponse } from \"./responses\";\nimport { Worker } from \"./interfaces/worker\";\nimport { ErrorJson } from \"./interfaces/error-json\";\n\n/**\n * Generic HTTP error response.\n * Sends a JSON body with status, error message, and details.\n */\nexport class HttpError extends JsonResponse {\n /**\n * @param worker The worker handling the request.\n * @param status HTTP status code.\n * @param details Optional detailed error message.\n */\n constructor(\n worker: Worker,\n status: StatusCodes,\n protected readonly details?: string,\n ) {\n const json: ErrorJson = {\n status,\n error: getReasonPhrase(status),\n details: details ?? \"\",\n };\n super(worker, json, CacheControl.DISABLE, status);\n }\n}\n\n/** 400 Bad Request error response. */\nexport class BadRequest extends HttpError {\n constructor(worker: Worker, details?: string) {\n super(worker, StatusCodes.BAD_REQUEST, details);\n }\n}\n\n/** 401 Unauthorized error response. */\nexport class Unauthorized extends HttpError {\n constructor(worker: Worker, details?: string) {\n super(worker, StatusCodes.UNAUTHORIZED, details);\n }\n}\n\n/** 403 Forbidden error response. */\nexport class Forbidden extends HttpError {\n constructor(worker: Worker, details?: string) {\n super(worker, StatusCodes.FORBIDDEN, details);\n }\n}\n\n/** 404 Not Found error response. */\nexport class NotFound extends HttpError {\n constructor(worker: Worker, details?: string) {\n super(worker, StatusCodes.NOT_FOUND, details);\n }\n}\n\n/** 405 Method Not Allowed error response. */\nexport class MethodNotAllowed extends HttpError {\n constructor(worker: Worker) {\n super(\n worker,\n StatusCodes.METHOD_NOT_ALLOWED,\n `${worker.request.method} method not allowed.`,\n );\n this.setHeader(HttpHeader.ALLOW, this.worker.getAllowedMethods());\n }\n}\n\n/** 500 Internal Server Error response. */\nexport class InternalServerError extends HttpError {\n constructor(worker: Worker, details?: string) {\n super(worker, StatusCodes.INTERNAL_SERVER_ERROR, details);\n }\n}\n\n/** 501 Not Implemented error response. */\nexport class NotImplemented extends HttpError {\n constructor(worker: Worker, details?: string) {\n super(worker, StatusCodes.NOT_IMPLEMENTED, details);\n }\n}\n\n/** 501 Method Not Implemented error response for unsupported HTTP methods. */\nexport class MethodNotImplemented extends NotImplemented {\n constructor(worker: Worker) {\n super(worker, `${worker.request.method} method not implemented.`);\n }\n}\n\n/** 503 Service Unavailable error response. */\nexport class ServiceUnavailable extends HttpError {\n constructor(worker: Worker, 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} from \"./common\";\nimport { Worker } from \"./interfaces/worker\";\n\n/**\n * Base class for building HTTP responses.\n * Manages headers, status, and media type.\n */\nabstract class BaseResponse {\n constructor() {}\n\n /** HTTP headers for the response. */\n public headers: Headers = new Headers();\n\n /** HTTP status code (default 200 OK). */\n public status: StatusCodes = StatusCodes.OK;\n\n /** Optional status text. Defaults to standard reason phrase. */\n public statusText?: string;\n\n /** Default media type of the response body. */\n public mediaType: MediaType = MediaType.PLAIN_TEXT;\n\n /** Converts current state to ResponseInit for constructing a Response. */\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 /** Sets a header, overwriting any existing value. */\n public setHeader(key: string, value: string | string[]): void {\n setHeader(this.headers, key, value);\n }\n\n /** Merges a header with existing values (does not overwrite). */\n public mergeHeader(key: string, value: string | string[]): void {\n mergeHeader(this.headers, key, value);\n }\n\n /** Adds a Content-Type header if not already existing (does not overwrite). */\n public addContentType() {\n if (!this.headers.get(HttpHeader.CONTENT_TYPE)) {\n this.headers.set(HttpHeader.CONTENT_TYPE, getContentType(this.mediaType));\n }\n }\n}\n\n/**\n * Base response class that adds caching headers.\n */\nabstract class CacheResponse extends BaseResponse {\n constructor(public cache?: CacheControl) {\n super();\n }\n\n /** Adds Cache-Control header if caching is configured. */\n protected addCacheHeader(): void {\n if (this.cache) {\n this.headers.set(HttpHeader.CACHE_CONTROL, CacheControl.stringify(this.cache));\n }\n }\n}\n\n/**\n * Core worker response. Combines caching, and security headers.\n */\nexport abstract class WorkerResponse extends CacheResponse {\n constructor(\n public readonly worker: Worker,\n private readonly body: BodyInit | null = null,\n cache?: CacheControl,\n ) {\n super(cache);\n }\n\n /** Builds the Response object with body, headers, and status. */\n public async getResponse(): Promise<Response> {\n this.addCacheHeader();\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\n/**\n * Wraps an existing Response and clones its body, headers, and status.\n */\nexport class ClonedResponse extends WorkerResponse {\n constructor(worker: Worker, 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\n/**\n * Represents a successful response with customizable body and status.\n */\nexport class SuccessResponse extends WorkerResponse {\n constructor(\n worker: Worker,\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\n/**\n * JSON response. Automatically sets Content-Type to application/json.\n */\nexport class JsonResponse extends SuccessResponse {\n constructor(\n worker: Worker,\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\n/**\n * HTML response. Automatically sets Content-Type to text/html.\n */\nexport class HtmlResponse extends SuccessResponse {\n constructor(\n worker: Worker,\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\n/**\n * Plain text response. Automatically sets Content-Type to text/plain.\n */\nexport class TextResponse extends SuccessResponse {\n constructor(\n worker: Worker,\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 * Response for HEAD requests. Clones headers but has no body.\n */\nexport class Head extends WorkerResponse {\n constructor(worker: Worker, get: Response) {\n super(worker);\n this.headers = new Headers(get.headers);\n }\n}\n\n/**\n * Response for OPTIONS preflight requests.\n * Sets CORS headers and returns 204 No Content.\n */\nexport class Options extends SuccessResponse {\n constructor(worker: Worker) {\n super(worker, null, undefined, StatusCodes.NO_CONTENT);\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, HttpHeader, mergeHeader, setHeader } from \"../../common\";\nimport { CorsConfig } from \"../../interfaces/cors-config\";\nimport { Worker } from \"../../interfaces/worker\";\n\n/**\n * Adds CORS headers to the given Headers object based on the request and config.\n */\nexport function addCorsHeaders(worker: Worker, cors: CorsConfig, headers: Headers): void {\n deleteCorsHeaders(headers);\n\n const origin = getOrigin(worker.request);\n if (!origin) return;\n\n if (allowAnyOrigin(cors)) {\n // Allowed Origin: *\n setHeader(headers, HttpHeader.ALLOW_ORIGIN, HttpHeader.ALLOW_ALL_ORIGINS);\n } else {\n // Allowed Origin: [\"https://example.com\"]\n // Always add Vary: Origin\n mergeHeader(headers, HttpHeader.VARY, HttpHeader.ORIGIN);\n\n if (cors.allowedOrigins.includes(origin)) {\n // When the provided origin is allowed:\n setHeader(headers, HttpHeader.ALLOW_ORIGIN, origin);\n setHeader(headers, HttpHeader.ALLOW_CREDENTIALS, \"true\");\n }\n }\n\n // Add for all CORS requests.\n setHeader(headers, HttpHeader.MAX_AGE, String(cors.maxAge));\n setHeader(headers, HttpHeader.ALLOW_HEADERS, cors.allowedHeaders);\n mergeHeader(headers, HttpHeader.ALLOW_METHODS, worker.getAllowedMethods());\n mergeHeader(headers, HttpHeader.EXPOSE_HEADERS, cors.exposedHeaders);\n}\n\n/** Returns true if the CORS config allows all origins (`*`). */\nexport function allowAnyOrigin(cors: CorsConfig): boolean {\n return cors.allowedOrigins.includes(\"*\");\n}\n\n/** Removes all standard CORS headers from a Headers object. */\nfunction deleteCorsHeaders(headers: Headers): void {\n headers.delete(HttpHeader.MAX_AGE);\n headers.delete(HttpHeader.ALLOW_ORIGIN);\n headers.delete(HttpHeader.ALLOW_HEADERS);\n headers.delete(HttpHeader.ALLOW_METHODS);\n headers.delete(HttpHeader.EXPOSE_HEADERS);\n headers.delete(HttpHeader.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 { Worker } from \"../interfaces/worker\";\n\n/**\n * Abstract base class for middleware.\n *\n * Middleware classes implement request/response processing logic in a\n * chainable manner. Each middleware receives a `Worker` object and a\n * `next` function that invokes the next middleware in the chain.\n *\n * Subclasses **must implement** the `handle` method.\n *\n * Example subclass:\n * ```ts\n * class LoggingMiddleware extends Middleware {\n * public async handle(worker: Worker, next: () => Promise<Response>): Promise<Response> {\n * console.log(`Processing request: ${worker.request.url}`);\n * const response = await next();\n * console.log(`Response status: ${response.status}`);\n * return response;\n * }\n * }\n * ```\n */\nexport abstract class Middleware {\n /**\n * Process a request in the middleware chain.\n *\n * @param worker - The `Worker` instance representing the request context.\n * @param next - Function to invoke the next middleware in the chain.\n * Must be called to continue the chain unless the middleware\n * terminates early (e.g., returns a response directly).\n * @returns A `Response` object, either returned directly or from `next()`.\n */\n public abstract handle(worker: Worker, next: () => Promise<Response>): Promise<Response>;\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 { Time } from \"../../common\";\nimport { CorsConfig } from \"../../interfaces/cors-config\";\n\n/**\n * Default configuration for CORS middleware.\n */\nexport const defaultCorsConfig: CorsConfig = {\n allowedOrigins: [\"*\"], // Origins allowed for CORS requests\n allowedHeaders: [\"Content-Type\"], // HTTP headers allowed in requests\n exposedHeaders: [], // Headers exposed to the client\n maxAge: Time.Week, // Max age in seconds for preflight caching\n} as const;\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 { addCorsHeaders } from \"./utils\";\nimport { Worker } from \"../../interfaces/worker\";\nimport { Middleware } from \"../middleware\";\nimport { CorsConfig, CorsInit } from \"../../interfaces/cors-config\";\nimport { defaultCorsConfig } from \"./constants\";\nimport { OPTIONS } from \"../../common\";\nimport { ClonedResponse, Options } from \"../../responses\";\n\nexport function cors(init?: CorsInit): Middleware {\n return new CorsHandler(init);\n}\n\n/**\n * Middleware that applies Cross-Origin Resource Sharing (CORS) headers to responses.\n *\n * Merges the initialization config (if provided), with {@link defaultCorsConfig}.\n *\n * Example Worker:\n * ```ts\n * // Request → [CorsHandler] → [CacheHandler] → [Worker Handler]\n * // Response ← [CorsHandler] ← [CacheHandler] ↙\n * protected override init(): void {\n * worker.use(new CorsHandler());\n * worker.use(new CacheHandler());\n * }\n * ```\n */\nclass CorsHandler extends Middleware {\n /** The configuration used for this instance, with all defaults applied. */\n private readonly config: CorsConfig;\n\n /**\n * Create a new CORS middleware instance.\n *\n * @param init - Partial configuration to override the defaults. Any values\n * not provided will use `defaultCorsConfig`.\n */\n constructor(init?: CorsInit) {\n super();\n this.config = { ...defaultCorsConfig, ...init };\n }\n\n /**\n * Handle a request by applying CORS headers to the response.\n *\n * @param worker - The Worker instance containing the request context.\n * @param next - Function to invoke the next middleware in the chain.\n * @returns A Response object with CORS headers applied.\n */\n public override async handle(worker: Worker, next: () => Promise<Response>): Promise<Response> {\n if (worker.request.method === OPTIONS) {\n const options = new Options(worker);\n addCorsHeaders(worker, this.config, options.headers);\n return options.getResponse();\n }\n\n const response = await next();\n\n const clone = new ClonedResponse(worker, response);\n addCorsHeaders(worker, this.config, clone.headers);\n return clone.getResponse();\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 { GET, normalizeUrl } from \"../../common\";\nimport { Middleware } from \"../middleware\";\nimport { Worker } from \"../../interfaces/worker\";\n\nexport function cache(\n cacheName?: string,\n getKey?: (request: Request) => URL | RequestInfo,\n): Middleware {\n return new CacheHandler(cacheName, getKey);\n}\n\n/**\n * Middleware for caching GET requests.\n *\n * This middleware checks a cache (either a named cache or the default)\n * before passing the request down the middleware chain. Responses for\n * successful GET requests are automatically stored in the cache.\n *\n * Non-GET requests are never cached. The cache key can be customized\n * via the `getKey` function; otherwise, the URL is normalized and used.\n *\n * ```ts\n * worker.use(new CacheHandler());\n * ```\n */\nclass CacheHandler extends Middleware {\n /**\n * @param cacheName - Optional name of the cache to use. If omitted,\n * `caches.default` is used.\n * @param getKey - Optional function to generate a cache key from a request.\n * Defaults to using the normalized request URL.\n */\n constructor(\n protected readonly cacheName?: string,\n protected readonly getKey?: (request: Request) => URL | RequestInfo,\n ) {\n super();\n }\n\n /**\n * Handle a request in the caching middleware.\n *\n * Checks the cache for GET requests and returns the cached response if available.\n * Otherwise, calls `next()` to continue the middleware chain and caches\n * the response if successful.\n *\n * @param worker - The Worker instance containing the request context.\n * @param next - Function to invoke the next middleware in the chain.\n * @returns A Response object, either from cache or the next middleware.\n */\n public override async handle(worker: Worker, next: () => Promise<Response>): Promise<Response> {\n const cache = this.cacheName ? await caches.open(this.cacheName) : caches.default;\n\n if (worker.request.method === GET) {\n const cached = await cache.match(this.getCacheKey(worker.request));\n if (cached) return cached;\n }\n\n const response = await next();\n\n if (worker.request.method === GET && response.ok) {\n worker.ctx.waitUntil(cache.put(this.getCacheKey(worker.request), response.clone()));\n }\n return response;\n }\n\n /**\n * Generate the cache key for a request.\n *\n * @param request - The Request object to generate a cache key for.\n * @returns A URL or RequestInfo used as the cache key.\n *\n * If a custom `getKey` function was provided in the constructor, it is used.\n * Otherwise, the request URL is normalized.\n */\n private getCacheKey(request: Request): URL | RequestInfo {\n return this.getKey ? this.getKey(request) : normalizeUrl(request.url);\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 { GET, HEAD, Method, OPTIONS } from \"../common\";\nimport { FetchHandler } from \"../interfaces/fetch-handler\";\nimport { Worker, WorkerClass } from \"../interfaces/worker\";\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 * Dispatches the incoming request to the appropriate handler and produces a response.\n *\n * Subclasses must implement this method to define how the worker generates a `Response`\n * for the current request. This is the central point where request processing occurs.\n *\n * @returns A Promise that resolves to the `Response` for the request.\n */\n protected abstract dispatch(): Promise<Response>;\n\n /**\n * DEFAULT allowed HTTP methods for subclasses.\n *\n * These defaults were selected for getting started quickly and should be\n * overridden for the specific worker.\n */\n public getAllowedMethods(): Method[] {\n return [GET, HEAD, OPTIONS];\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 WorkerClass<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 * ```ts\n * export default MyWorker.ignite();\n * ```\n */\n public static ignite<W extends Worker>(this: WorkerClass<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 { Middleware } from \"../middleware/middleware\";\n\n/** Internal base worker for handling middleware chains. */\nexport abstract class MiddlewareWorker extends BaseWorker {\n /** Middleware handlers registered for this worker. */\n protected readonly middlewares: Middleware[] = [];\n\n /**\n * Add a middleware instance to this worker.\n *\n * The middleware will run for every request handled by this worker,\n * in the order they are added.\n *\n * @param handler - The middleware to run.\n * @returns `this` to allow chaining multiple `.use()` calls.\n */\n public use(handler: Middleware): this {\n this.middlewares.push(handler);\n return this;\n }\n\n /**\n * Executes the middleware chain and dispatches the request.\n *\n * @returns The Response produced by the last middleware or `dispatch()`.\n */\n public override async fetch(): Promise<Response> {\n const chain = this.middlewares.reduceRight(\n (next, handler) => () => handler.handle(this, next),\n () => this.dispatch(),\n );\n return await chain();\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 { GET, isMethod, Method } from \"../common\";\nimport { MethodNotAllowed, InternalServerError, MethodNotImplemented } from \"../errors\";\nimport { MiddlewareWorker } from \"./middleware-worker\";\nimport { Head, WorkerResponse } from \"../responses\";\nimport { Worker } from \"../interfaces/worker\";\n\n/**\n * Basic worker class providing HTTP method dispatching and error handling.\n */\nexport abstract class BasicWorker extends MiddlewareWorker {\n /**\n * Entry point to handle a fetch request.\n */\n public override async fetch(): Promise<Response> {\n if (!this.isAllowed(this.request.method)) {\n return this.getResponse(MethodNotAllowed);\n }\n\n try {\n await this.init();\n return await super.fetch();\n } catch (error) {\n console.error(error);\n return this.getResponse(InternalServerError);\n }\n }\n\n /**\n * Dispatches the request to the method-specific handler.\n */\n protected override 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\n return (handler[method] ?? (() => this.getResponse(MethodNotAllowed)))();\n }\n\n /**\n * Hook for subclasses to perform any initialization.\n */\n protected init(): void | Promise<void> {\n return;\n }\n\n /**\n * Checks if the given HTTP method is allowed for this worker.\n * @param method HTTP method string\n * @returns true if the method is allowed\n */\n public isAllowed(method: string): boolean {\n return isMethod(method) && this.getAllowedMethods().includes(method);\n }\n\n /** Override and implement this method for GET requests. */\n protected async get(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n /** Override and implement this method for PUT requests. */\n protected async put(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n /** Override and implement this method for POST requests. */\n protected async post(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n /** Override and implement this method for PATCH requests. */\n protected async patch(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n /** Override and implement this method for DELETE requests. */\n protected async delete(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n /** Override and implement this method for OPTIONS requests. */\n protected async options(): Promise<Response> {\n return this.getResponse(MethodNotImplemented);\n }\n\n /**\n * Default handler for HEAD requests.\n * Performs a GET request and removes the body for HEAD semantics.\n *\n * Usually does not need to be overridden as this behavior covers\n * standard HEAD requirements.\n */\n protected async head(): Promise<Response> {\n const worker = this.create(new Request(this.request, { method: GET }));\n return this.getResponse(Head, await worker.fetch());\n }\n\n /**\n * Simplify and standardize {@link Response} creation by extending {@link WorkerResponse}\n * or any of its subclasses and passing to this method.\n *\n * Or directly use any of the built-in classes.\n *\n * ```ts\n * this.getResponse(TextResponse, \"Hello World!\")\n * ```\n *\n * @param ResponseClass The response class to instantiate\n * @param args Additional constructor arguments\n * @returns A Promise resolving to the {@link Response} object\n */\n protected async getResponse<\n T extends WorkerResponse,\n Ctor extends new (worker: Worker, ...args: any[]) => T,\n >(\n ResponseClass: Ctor,\n ...args: ConstructorParameters<Ctor> extends [Worker, ...infer R] ? R : never\n ): Promise<Response> {\n return new ResponseClass(this, ...args).getResponse();\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 { match } from \"path-to-regexp\";\nimport { Method } from \"./common\";\nimport { MatchedRoute, Route, PathParams, RouteTable } from \"./interfaces/route\";\n\n/**\n * Container for route definitions and matching logic.\n * Implements Iterable to allow iteration over all routes.\n */\nexport class Routes implements Iterable<Route> {\n /** Internal array of registered routes */\n private readonly routes: Route[] = [];\n\n /**\n * Add routes to the router.\n *\n * Accepts any iterable of [method, path, handler] tuples.\n * This includes arrays, Sets, or generators.\n *\n * @param routes - Iterable of route tuples to add.\n */\n public add(routes: RouteTable): void {\n for (const [method, path, handler] of routes) {\n const matcher = match<PathParams>(path);\n this.routes.push({ method, matcher, handler });\n }\n }\n\n /**\n * Attempt to match a URL against the registered routes.\n *\n * @param method - HTTP method of the request\n * @param url - Full URL string to match against\n * @returns A MatchedRoute object if a route matches, otherwise null\n */\n public match(method: Method, url: string): MatchedRoute | null {\n const pathname = new URL(url).pathname;\n\n for (const route of this) {\n if (route.method !== method) continue;\n\n const found = route.matcher(pathname);\n if (found) return { route, params: found.params };\n }\n\n return null;\n }\n\n /**\n * Iterate over all registered routes.\n */\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 { BasicWorker } from \"./basic-worker\";\nimport { Method } from \"../common\";\nimport { NotFound } from \"../errors\";\nimport { Routes } from \"../routes\";\nimport { RouteHandler, RouteTable } from \"../interfaces/route\";\nimport { WorkerClass } from \"../interfaces/worker\";\nimport { BaseWorker } from \"./base-worker\";\n\n/**\n * Base worker supporting route-based request handling.\n *\n * Subclass `RouteWorker` to define a worker with multiple route handlers.\n *\n * Routes can be registered individually via `route()` or in bulk via `routes()`.\n */\nexport abstract class RouteWorker extends BasicWorker {\n /** Internal table of registered routes. */\n private readonly _routes: Routes = new Routes();\n\n /**\n * Registers a single new route in the worker.\n *\n * When a request matches the specified method and path, the provided handler\n * will be executed. The handler can be either:\n * - A function that receives URL parameters, or\n * - A Worker subclass that will handle the request.\n *\n * @param method - HTTP method for the route (GET, POST, etc.).\n * @param path - URL path pattern (Express-style, e.g., \"/users/:id\").\n * @param handler - The function or Worker class to run when the route matches.\n * @returns The current worker instance, allowing method chaining.\n */\n protected route(method: Method, path: string, handler: RouteHandler): this {\n this.routes([[method, path, handler]]);\n return this;\n }\n\n /**\n * Registers multiple routes at once in the worker.\n *\n * Each route should be a tuple `[method, path, handler]` where:\n * - `method` - HTTP method for the route (GET, POST, etc.).\n * - `path` - URL path pattern (Express-style, e.g., \"/users/:id\").\n * - `handler` - A function that receives URL parameters or a Worker subclass\n * that will handle the request.\n *\n * @param routes - An iterable of routes to register. Each item is a `[method, path, handler]` tuple.\n * @returns The current worker instance, allowing method chaining.\n */\n protected routes(routes: RouteTable): this {\n this._routes.add(routes);\n return this;\n }\n\n /**\n * Matches the incoming request against registered routes and dispatches it.\n *\n * If a route is found:\n * - If the handler is a Worker class, a new instance is created and its `fetch()` is called.\n * - If the handler is a callback function, it is invoked with the extracted path parameters.\n *\n * If no route matches, the request is passed to the parent `dispatch()` handler.\n *\n * @returns A `Promise<Response>` from the matched handler or parent dispatch.\n */\n protected override 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 const { handler } = found.route;\n if (RouteWorker.isWorkerClass(handler)) {\n return new handler(this.request, this.env, this.ctx).fetch();\n }\n return handler.call(this, found.params);\n }\n\n /**\n * Runtime type guard to check if a given handler is a Worker class.\n *\n * A Worker class is any class that extends `BaseWorker`.\n *\n * @param handler - The constructor function to test.\n * @returns `true` if `handler` is a subclass of `BaseWorker` at runtime, `false` otherwise.\n */\n private static isWorkerClass(handler: RouteHandler): handler is WorkerClass {\n return BaseWorker.prototype.isPrototypeOf(handler.prototype);\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 protected override async options(): Promise<Response> {\n return this.getResponse(NotFound);\n }\n}\n"],"mappings":"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","names":["HttpHeader","Method","MediaType","getReasonPhrase","StatusCodes","StatusCodes","cache","getReasonPhrase","cors","cache"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adonix.org/cloud-spark",
3
- "version": "0.0.139",
3
+ "version": "0.0.141",
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",
@@ -45,6 +45,7 @@
45
45
  },
46
46
  "devDependencies": {
47
47
  "@cloudflare/workers-types": "^4.20250909.0",
48
+ "@types/node": "^24.3.1",
48
49
  "@vitest/coverage-v8": "^3.2.4",
49
50
  "prettier": "^3.6.2",
50
51
  "tsup": "^8.5.0",