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