@adonix.org/cloud-spark 0.0.80 → 0.0.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +208 -28
- package/dist/index.js +199 -135
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -6,34 +6,52 @@ interface Worker {
|
|
|
6
6
|
fetch(): Promise<Response>;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Provides the foundational structure for handling requests, environment bindings,
|
|
11
|
+
* and the worker execution context. Subclasses are expected to implement the
|
|
12
|
+
* `fetch` method to handle the request and return a Response.
|
|
13
|
+
*
|
|
14
|
+
* Features:
|
|
15
|
+
* - Holds the current `Request` object (`request` getter).
|
|
16
|
+
* - Provides access to environment bindings (`env` getter).
|
|
17
|
+
* - Provides access to the worker execution context (`ctx` getter), if available.
|
|
18
|
+
* - Subclasses must implement `fetch()` to process the request.
|
|
19
|
+
*/
|
|
9
20
|
declare abstract class BaseWorker implements Worker {
|
|
10
21
|
private readonly _request;
|
|
11
22
|
private readonly _env;
|
|
12
23
|
private readonly _ctx?;
|
|
13
24
|
constructor(_request: Request, _env?: Env, _ctx?: ExecutionContext | undefined);
|
|
25
|
+
/** The Request object associated with this worker invocation */
|
|
14
26
|
protected get request(): Request;
|
|
27
|
+
/** Environment bindings (e.g., KV, secrets, or other globals) */
|
|
15
28
|
protected get env(): Env;
|
|
29
|
+
/** Optional execution context for background tasks or `waitUntil` */
|
|
16
30
|
protected get ctx(): ExecutionContext | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Process the request and produce a Response.
|
|
33
|
+
* Subclasses must implement this method.
|
|
34
|
+
*
|
|
35
|
+
* @returns A Promise resolving to the Response for the request
|
|
36
|
+
*/
|
|
17
37
|
abstract fetch(): Promise<Response>;
|
|
18
38
|
}
|
|
19
39
|
|
|
20
|
-
declare abstract class CacheWorker extends BaseWorker {
|
|
21
|
-
protected getCacheKey(...values: Array<string | null | undefined>): URL | RequestInfo;
|
|
22
|
-
protected getCachedResponse(cacheName?: string): Promise<Response | undefined>;
|
|
23
|
-
protected setCachedResponse(response: Response, cacheName?: string): Promise<void>;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
40
|
/**
|
|
27
|
-
* https://github.com/etienne-martin/cache-control-parser
|
|
41
|
+
* - See https://github.com/etienne-martin/cache-control-parser
|
|
28
42
|
*/
|
|
29
|
-
|
|
30
43
|
type CacheControl = CacheLib.CacheControl;
|
|
31
44
|
declare const CacheControl: {
|
|
32
45
|
parse: (cacheControlHeader: string) => CacheLib.CacheControl;
|
|
33
46
|
stringify: (cacheControl: CacheLib.CacheControl) => string;
|
|
34
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* Standard HTTP header names and common values.
|
|
50
|
+
*/
|
|
35
51
|
declare namespace HttpHeader {
|
|
36
52
|
const VARY = "Vary";
|
|
53
|
+
const CONTENT_TYPE = "Content-Type";
|
|
54
|
+
const CACHE_CONTROL = "Cache-Control";
|
|
37
55
|
const X_CONTENT_TYPE_OPTIONS = "X-Content-Type-Options";
|
|
38
56
|
const X_FRAME_OPTIONS = "X-Frame-Options";
|
|
39
57
|
const STRICT_TRANSPORT_SECURITY = "Strict-Transport-Security";
|
|
@@ -43,14 +61,21 @@ declare namespace HttpHeader {
|
|
|
43
61
|
const NOSNIFF = "nosniff";
|
|
44
62
|
const ORIGIN = "Origin";
|
|
45
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Time constants in seconds. Month is approximated as 30 days.
|
|
66
|
+
*/
|
|
46
67
|
declare const Time: {
|
|
47
68
|
readonly Second: 1;
|
|
48
69
|
readonly Minute: 60;
|
|
49
|
-
readonly Hour:
|
|
50
|
-
readonly Day:
|
|
51
|
-
readonly Week:
|
|
52
|
-
readonly
|
|
70
|
+
readonly Hour: 3600;
|
|
71
|
+
readonly Day: 86400;
|
|
72
|
+
readonly Week: 604800;
|
|
73
|
+
readonly Month: 2592000;
|
|
74
|
+
readonly Year: 31536000;
|
|
53
75
|
};
|
|
76
|
+
/**
|
|
77
|
+
* Standard HTTP request methods.
|
|
78
|
+
*/
|
|
54
79
|
declare enum Method {
|
|
55
80
|
GET = "GET",
|
|
56
81
|
PUT = "PUT",
|
|
@@ -60,9 +85,25 @@ declare enum Method {
|
|
|
60
85
|
HEAD = "HEAD",
|
|
61
86
|
OPTIONS = "OPTIONS"
|
|
62
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Type guard that checks if a string is a valid HTTP method.
|
|
90
|
+
*
|
|
91
|
+
* @param value - The string to test.
|
|
92
|
+
* @returns True if `value` is a recognized HTTP method.
|
|
93
|
+
*/
|
|
63
94
|
declare function isMethod(value: string): value is Method;
|
|
64
|
-
|
|
65
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Returns the proper Content-Type string for a given media type.
|
|
97
|
+
* Appends `charset=utf-8` for text-based types that require it.
|
|
98
|
+
*
|
|
99
|
+
* @param type - The media type.
|
|
100
|
+
* @returns A string suitable for the `Content-Type` header.
|
|
101
|
+
*/
|
|
102
|
+
declare function getContentType(type: MediaType): string;
|
|
103
|
+
/**
|
|
104
|
+
* Common media types types used for HTTP headers.
|
|
105
|
+
*/
|
|
106
|
+
declare enum MediaType {
|
|
66
107
|
PLAIN_TEXT = "text/plain",
|
|
67
108
|
HTML = "text/html",
|
|
68
109
|
CSS = "text/css",
|
|
@@ -107,7 +148,29 @@ declare enum MimeType {
|
|
|
107
148
|
TAR = "application/x-tar",
|
|
108
149
|
BZIP2 = "application/x-bzip2"
|
|
109
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Sets a header on the given Headers object.
|
|
153
|
+
*
|
|
154
|
+
* - If `value` is an array, duplicates and empty strings are removed.
|
|
155
|
+
* - If the resulting value array is empty, the header is deleted.
|
|
156
|
+
* - Otherwise, values are joined with `", "` and set as the header value.
|
|
157
|
+
*
|
|
158
|
+
* @param headers - The Headers object to modify.
|
|
159
|
+
* @param key - The header name to set.
|
|
160
|
+
* @param value - The header value(s) to set. Can be a string or array of strings.
|
|
161
|
+
*/
|
|
110
162
|
declare function setHeader(headers: Headers, key: string, value: string | string[]): void;
|
|
163
|
+
/**
|
|
164
|
+
* Merges new value(s) into an existing header on the given Headers object.
|
|
165
|
+
*
|
|
166
|
+
* - Preserves any existing values and adds new ones.
|
|
167
|
+
* - Removes duplicates and trims all values.
|
|
168
|
+
* - If the header does not exist, it is created.
|
|
169
|
+
*
|
|
170
|
+
* @param headers - The Headers object to modify.
|
|
171
|
+
* @param key - The header name to merge into.
|
|
172
|
+
* @param value - The new header value(s) to add. Can be a string or array of strings.
|
|
173
|
+
*/
|
|
111
174
|
declare function mergeHeader(headers: Headers, key: string, value: string | string[]): void;
|
|
112
175
|
/**
|
|
113
176
|
* Normalizes a URL string for use as a consistent cache key.
|
|
@@ -120,17 +183,38 @@ declare function mergeHeader(headers: Headers, key: string, value: string | stri
|
|
|
120
183
|
* @returns A normalized URL string suitable for hashing or direct cache key use.
|
|
121
184
|
*/
|
|
122
185
|
declare function normalizeUrl(url: string): URL;
|
|
186
|
+
/**
|
|
187
|
+
* Encodes a given string into Base64 using UTF-8 encoding.
|
|
188
|
+
*
|
|
189
|
+
* This function correctly handles any Unicode characters.
|
|
190
|
+
*
|
|
191
|
+
* @param raw - The input string to encode.
|
|
192
|
+
* @returns The Base64-encoded string.
|
|
193
|
+
*/
|
|
123
194
|
declare function toBase64(raw: string): string;
|
|
124
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Provides information about the CORS policy for the current request.
|
|
198
|
+
*/
|
|
125
199
|
interface CorsProvider {
|
|
200
|
+
/** Returns the origin of the request, or null if none is provided. */
|
|
126
201
|
getOrigin(): string | null;
|
|
202
|
+
/** Returns a list of allowed origins. */
|
|
127
203
|
getAllowOrigins(): string[];
|
|
204
|
+
/** Returns true if any origin is allowed (`*`). */
|
|
128
205
|
allowAnyOrigin(): boolean;
|
|
206
|
+
/** Returns the HTTP methods allowed by CORS. */
|
|
129
207
|
getAllowMethods(): Method[];
|
|
208
|
+
/** Returns the HTTP headers allowed by CORS. */
|
|
130
209
|
getAllowHeaders(): string[];
|
|
210
|
+
/** Returns the HTTP headers that should be exposed to the browser. */
|
|
131
211
|
getExposeHeaders(): string[];
|
|
212
|
+
/** Returns the max age (in seconds) for CORS preflight caching. */
|
|
132
213
|
getMaxAge(): number;
|
|
133
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* Constants for common CORS headers.
|
|
217
|
+
*/
|
|
134
218
|
declare namespace Cors {
|
|
135
219
|
const ALLOW_ORIGIN = "Access-Control-Allow-Origin";
|
|
136
220
|
const ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
|
|
@@ -140,6 +224,110 @@ declare namespace Cors {
|
|
|
140
224
|
const MAX_AGE = "Access-Control-Max-Age";
|
|
141
225
|
const ALLOW_ALL_ORIGINS = "*";
|
|
142
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* Adds or updates CORS headers on a Headers object according to the provided policy.
|
|
229
|
+
*
|
|
230
|
+
* Behavior:
|
|
231
|
+
* - Removes any existing CORS headers to avoid stale values.
|
|
232
|
+
* - If the request has no origin, the function exits early.
|
|
233
|
+
* - If wildcard `*` is allowed, sets Access-Control-Allow-Origin to `*`.
|
|
234
|
+
* - If the origin is explicitly allowed, sets the correct headers including credentials and Vary: Origin.
|
|
235
|
+
* - Optional headers (Expose-Headers, Allow-Headers, Allow-Methods, Max-Age) are always applied.
|
|
236
|
+
*
|
|
237
|
+
* @param cors The CorsProvider instance that determines allowed origins and headers
|
|
238
|
+
* @param headers The Headers object to update
|
|
239
|
+
*/
|
|
240
|
+
declare function addCorsHeaders(cors: CorsProvider, headers: Headers): void;
|
|
241
|
+
/**
|
|
242
|
+
* Deletes all standard CORS headers from the given Headers object.
|
|
243
|
+
* Useful for cleaning cached responses or resetting headers before reapplying CORS.
|
|
244
|
+
*
|
|
245
|
+
* @param headers The Headers object to clean
|
|
246
|
+
*/
|
|
247
|
+
declare function deleteCorsHeaders(headers: Headers): void;
|
|
248
|
+
/**
|
|
249
|
+
* Returns a new Response with CORS headers applied according to the policy.
|
|
250
|
+
* Original response is not mutated.
|
|
251
|
+
*
|
|
252
|
+
* @param cors The CorsProvider instance for policy
|
|
253
|
+
* @param res The original Response object
|
|
254
|
+
* @returns A new Response with updated CORS headers
|
|
255
|
+
*/
|
|
256
|
+
declare function withCorsHeaders(cors: CorsProvider, res: Response): Response;
|
|
257
|
+
/**
|
|
258
|
+
* Returns a new Response with all standard CORS headers removed.
|
|
259
|
+
* Useful for storing responses in a cache without per-request CORS headers.
|
|
260
|
+
*
|
|
261
|
+
* @param res The original Response object
|
|
262
|
+
* @returns A new Response without CORS headers
|
|
263
|
+
*/
|
|
264
|
+
declare function withoutCorsHeaders(res: Response): Response;
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Abstract base class for Workers to provide a default CORS policy.
|
|
268
|
+
*
|
|
269
|
+
* Implements the `CorsProvider` interface and provides a standard policy:
|
|
270
|
+
* - Allows all origins (`*`) by default.
|
|
271
|
+
* - Allows GET, OPTIONS, and HEAD methods.
|
|
272
|
+
* - Allows the `Content-Type` header.
|
|
273
|
+
* - Exposes no additional headers.
|
|
274
|
+
* - Sets CORS preflight max-age to one week.
|
|
275
|
+
*
|
|
276
|
+
* Subclasses can override any of the methods to customize the CORS behavior.
|
|
277
|
+
*/
|
|
278
|
+
declare abstract class CorsWorker extends BaseWorker implements CorsProvider {
|
|
279
|
+
getAllowOrigins(): string[];
|
|
280
|
+
allowAnyOrigin(): boolean;
|
|
281
|
+
getAllowMethods(): Method[];
|
|
282
|
+
getAllowHeaders(): string[];
|
|
283
|
+
getExposeHeaders(): string[];
|
|
284
|
+
getMaxAge(): number;
|
|
285
|
+
getOrigin(): string | null;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Abstract base class for Workers that support caching of GET responses.
|
|
290
|
+
*
|
|
291
|
+
* Features:
|
|
292
|
+
* - URL-based caching using `Request.url`.
|
|
293
|
+
* - Removes per-request CORS headers before storing in cache.
|
|
294
|
+
* - Dynamically applies correct CORS headers when retrieving cached responses.
|
|
295
|
+
* - Only caches successful GET requests.
|
|
296
|
+
*/
|
|
297
|
+
declare abstract class CacheWorker extends CorsWorker {
|
|
298
|
+
/**
|
|
299
|
+
* Returns the cache key for the current request.
|
|
300
|
+
* By default, this is the normalized request URL.
|
|
301
|
+
*
|
|
302
|
+
* @returns A URL or RequestInfo to use as the cache key
|
|
303
|
+
*/
|
|
304
|
+
protected getCacheKey(): URL | RequestInfo;
|
|
305
|
+
/**
|
|
306
|
+
* Retrieves a cached Response for the current request, if one exists.
|
|
307
|
+
*
|
|
308
|
+
* Behavior:
|
|
309
|
+
* - Only GET requests are cached.
|
|
310
|
+
* - If a cached response is found, CORS headers are applied dynamically
|
|
311
|
+
* using `withCorsHeaders` before returning.
|
|
312
|
+
* - Returns undefined if no cached response is found or if request is not GET.
|
|
313
|
+
*
|
|
314
|
+
* @param cacheName Optional name of the cache to use; defaults to `caches.default`.
|
|
315
|
+
* @returns A Promise resolving to a Response with correct CORS headers, or undefined.
|
|
316
|
+
*/
|
|
317
|
+
protected getCachedResponse(cacheName?: string): Promise<Response | undefined>;
|
|
318
|
+
/**
|
|
319
|
+
* Stores a Response in the cache for the current request.
|
|
320
|
+
*
|
|
321
|
+
* Behavior:
|
|
322
|
+
* - Only caches successful GET responses (`response.ok === true`).
|
|
323
|
+
* - Removes all CORS headers before storing using `withoutCorsHeaders`.
|
|
324
|
+
* - Uses `ctx.waitUntil` to store asynchronously without blocking the worker.
|
|
325
|
+
*
|
|
326
|
+
* @param response The Response to cache
|
|
327
|
+
* @param cacheName Optional name of the cache to use; defaults to `caches.default`.
|
|
328
|
+
*/
|
|
329
|
+
protected setCachedResponse(response: Response, cacheName?: string): Promise<void>;
|
|
330
|
+
}
|
|
143
331
|
|
|
144
332
|
interface ErrorJson {
|
|
145
333
|
status: number;
|
|
@@ -151,7 +339,7 @@ declare abstract class BaseResponse {
|
|
|
151
339
|
body: BodyInit | null;
|
|
152
340
|
status: StatusCodes;
|
|
153
341
|
statusText?: string;
|
|
154
|
-
|
|
342
|
+
mediaType?: MediaType;
|
|
155
343
|
constructor(content?: BodyInit | null);
|
|
156
344
|
protected get responseInit(): ResponseInit;
|
|
157
345
|
setHeader(key: string, value: string | string[]): void;
|
|
@@ -164,8 +352,8 @@ declare abstract class CorsResponse extends BaseResponse {
|
|
|
164
352
|
protected addCorsHeaders(): void;
|
|
165
353
|
}
|
|
166
354
|
declare abstract class CacheResponse extends CorsResponse {
|
|
167
|
-
cache?: CacheControl;
|
|
168
|
-
constructor(cors: CorsProvider, body?: BodyInit | null, cache?: CacheControl);
|
|
355
|
+
cache?: CacheControl | undefined;
|
|
356
|
+
constructor(cors: CorsProvider, body?: BodyInit | null, cache?: CacheControl | undefined);
|
|
169
357
|
protected addCacheHeader(): void;
|
|
170
358
|
}
|
|
171
359
|
declare abstract class WorkerResponse extends CacheResponse {
|
|
@@ -230,7 +418,7 @@ declare class ServiceUnavailable extends HttpError {
|
|
|
230
418
|
constructor(cors: CorsProvider, details?: string);
|
|
231
419
|
}
|
|
232
420
|
|
|
233
|
-
declare abstract class BasicWorker extends CacheWorker
|
|
421
|
+
declare abstract class BasicWorker extends CacheWorker {
|
|
234
422
|
fetch(): Promise<Response>;
|
|
235
423
|
protected dispatch(request?: Request): Promise<Response>;
|
|
236
424
|
protected get(): Promise<Response>;
|
|
@@ -240,16 +428,8 @@ declare abstract class BasicWorker extends CacheWorker implements CorsProvider {
|
|
|
240
428
|
protected delete(): Promise<Response>;
|
|
241
429
|
protected options(): Promise<Response>;
|
|
242
430
|
protected head(): Promise<Response>;
|
|
243
|
-
protected
|
|
244
|
-
protected getResponse<T extends WorkerResponse, Ctor extends new (cors: CorsProvider, ...args: any[]) => T>(ResponseClass: Ctor, ...args: ConstructorParameters<Ctor> extends [any, ...infer R] ? R : never): Promise<Response>;
|
|
431
|
+
protected getResponse<T extends WorkerResponse, Ctor extends new (cors: CorsProvider, ...args: any[]) => T>(ResponseClass: Ctor, ...args: ConstructorParameters<Ctor> extends [CorsProvider, ...infer R] ? R : never): Promise<Response>;
|
|
245
432
|
isAllowed(method: string): boolean;
|
|
246
|
-
getAllowOrigins(): string[];
|
|
247
|
-
allowAnyOrigin(): boolean;
|
|
248
|
-
getAllowMethods(): Method[];
|
|
249
|
-
getAllowHeaders(): string[];
|
|
250
|
-
getExposeHeaders(): string[];
|
|
251
|
-
getMaxAge(): number;
|
|
252
|
-
getOrigin(): string | null;
|
|
253
433
|
}
|
|
254
434
|
|
|
255
435
|
type RouteCallback = (...matches: string[]) => Response | Promise<Response>;
|
|
@@ -277,4 +457,4 @@ declare abstract class RoutedWorker extends BasicWorker {
|
|
|
277
457
|
protected delete(): Promise<Response>;
|
|
278
458
|
}
|
|
279
459
|
|
|
280
|
-
export { BadRequest, BasicWorker, CacheControl, ClonedResponse, Cors, type CorsProvider, type ErrorJson, Forbidden, Head, HtmlResponse, HttpError, HttpHeader, InternalServerError, JsonResponse, Method, MethodNotAllowed,
|
|
460
|
+
export { BadRequest, BasicWorker, CacheControl, ClonedResponse, Cors, type CorsProvider, type ErrorJson, Forbidden, Head, HtmlResponse, HttpError, HttpHeader, InternalServerError, JsonResponse, MediaType, Method, MethodNotAllowed, NotFound, NotImplemented, Options, Route, type RouteCallback, type RouteInit, RoutedWorker, Routes, ServiceUnavailable, SuccessResponse, TextResponse, Time, Unauthorized, type Worker, WorkerResponse, addCorsHeaders, deleteCorsHeaders, getContentType, isMethod, mergeHeader, normalizeUrl, setHeader, toBase64, withCorsHeaders, withoutCorsHeaders };
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,8 @@ var CacheControl = {
|
|
|
10
10
|
var HttpHeader;
|
|
11
11
|
((HttpHeader2) => {
|
|
12
12
|
HttpHeader2.VARY = "Vary";
|
|
13
|
+
HttpHeader2.CONTENT_TYPE = "Content-Type";
|
|
14
|
+
HttpHeader2.CACHE_CONTROL = "Cache-Control";
|
|
13
15
|
HttpHeader2.X_CONTENT_TYPE_OPTIONS = "X-Content-Type-Options";
|
|
14
16
|
HttpHeader2.X_FRAME_OPTIONS = "X-Frame-Options";
|
|
15
17
|
HttpHeader2.STRICT_TRANSPORT_SECURITY = "Strict-Transport-Security";
|
|
@@ -22,20 +24,26 @@ var HttpHeader;
|
|
|
22
24
|
var Time = {
|
|
23
25
|
Second: 1,
|
|
24
26
|
Minute: 60,
|
|
25
|
-
Hour:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
Hour: 3600,
|
|
28
|
+
// 60 * 60
|
|
29
|
+
Day: 86400,
|
|
30
|
+
// 60 * 60 * 24
|
|
31
|
+
Week: 604800,
|
|
32
|
+
// 60 * 60 * 24 * 7
|
|
33
|
+
Month: 2592e3,
|
|
34
|
+
// 60 * 60 * 24 * 30
|
|
35
|
+
Year: 31536e3
|
|
36
|
+
// 60 * 60 * 24 * 365
|
|
29
37
|
};
|
|
30
|
-
var Method = /* @__PURE__ */ ((
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return
|
|
38
|
+
var Method = /* @__PURE__ */ ((Method4) => {
|
|
39
|
+
Method4["GET"] = "GET";
|
|
40
|
+
Method4["PUT"] = "PUT";
|
|
41
|
+
Method4["POST"] = "POST";
|
|
42
|
+
Method4["PATCH"] = "PATCH";
|
|
43
|
+
Method4["DELETE"] = "DELETE";
|
|
44
|
+
Method4["HEAD"] = "HEAD";
|
|
45
|
+
Method4["OPTIONS"] = "OPTIONS";
|
|
46
|
+
return Method4;
|
|
39
47
|
})(Method || {});
|
|
40
48
|
var METHOD_SET = new Set(Object.values(Method));
|
|
41
49
|
function isMethod(value) {
|
|
@@ -47,52 +55,52 @@ function getContentType(type) {
|
|
|
47
55
|
}
|
|
48
56
|
return type;
|
|
49
57
|
}
|
|
50
|
-
var
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
return
|
|
95
|
-
})(
|
|
58
|
+
var MediaType = /* @__PURE__ */ ((MediaType2) => {
|
|
59
|
+
MediaType2["PLAIN_TEXT"] = "text/plain";
|
|
60
|
+
MediaType2["HTML"] = "text/html";
|
|
61
|
+
MediaType2["CSS"] = "text/css";
|
|
62
|
+
MediaType2["CSV"] = "text/csv";
|
|
63
|
+
MediaType2["XML"] = "text/xml";
|
|
64
|
+
MediaType2["MARKDOWN"] = "text/markdown";
|
|
65
|
+
MediaType2["RICH_TEXT"] = "text/richtext";
|
|
66
|
+
MediaType2["JSON"] = "application/json";
|
|
67
|
+
MediaType2["XML_APP"] = "application/xml";
|
|
68
|
+
MediaType2["YAML"] = "application/x-yaml";
|
|
69
|
+
MediaType2["FORM_URLENCODED"] = "application/x-www-form-urlencoded";
|
|
70
|
+
MediaType2["NDJSON"] = "application/x-ndjson";
|
|
71
|
+
MediaType2["MSGPACK"] = "application/x-msgpack";
|
|
72
|
+
MediaType2["PROTOBUF"] = "application/x-protobuf";
|
|
73
|
+
MediaType2["MULTIPART_FORM_DATA"] = "multipart/form-data";
|
|
74
|
+
MediaType2["MULTIPART_MIXED"] = "multipart/mixed";
|
|
75
|
+
MediaType2["MULTIPART_ALTERNATIVE"] = "multipart/alternative";
|
|
76
|
+
MediaType2["MULTIPART_DIGEST"] = "multipart/digest";
|
|
77
|
+
MediaType2["MULTIPART_RELATED"] = "multipart/related";
|
|
78
|
+
MediaType2["MULTIPART_SIGNED"] = "multipart/signed";
|
|
79
|
+
MediaType2["MULTIPART_ENCRYPTED"] = "multipart/encrypted";
|
|
80
|
+
MediaType2["OCTET_STREAM"] = "application/octet-stream";
|
|
81
|
+
MediaType2["PDF"] = "application/pdf";
|
|
82
|
+
MediaType2["ZIP"] = "application/zip";
|
|
83
|
+
MediaType2["GZIP"] = "application/gzip";
|
|
84
|
+
MediaType2["MSWORD"] = "application/msword";
|
|
85
|
+
MediaType2["DOCX"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
86
|
+
MediaType2["EXCEL"] = "application/vnd.ms-excel";
|
|
87
|
+
MediaType2["XLSX"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
88
|
+
MediaType2["POWERPOINT"] = "application/vnd.ms-powerpoint";
|
|
89
|
+
MediaType2["PPTX"] = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
|
90
|
+
MediaType2["ICO"] = "image/x-icon";
|
|
91
|
+
MediaType2["ICO_MS"] = "image/vnd.microsoft.icon";
|
|
92
|
+
MediaType2["GIF"] = "image/gif";
|
|
93
|
+
MediaType2["PNG"] = "image/png";
|
|
94
|
+
MediaType2["JPEG"] = "image/jpeg";
|
|
95
|
+
MediaType2["WEBP"] = "image/webp";
|
|
96
|
+
MediaType2["SVG"] = "image/svg+xml";
|
|
97
|
+
MediaType2["HEIF"] = "image/heif";
|
|
98
|
+
MediaType2["AVIF"] = "image/avif";
|
|
99
|
+
MediaType2["EVENT_STREAM"] = "text/event-stream";
|
|
100
|
+
MediaType2["TAR"] = "application/x-tar";
|
|
101
|
+
MediaType2["BZIP2"] = "application/x-bzip2";
|
|
102
|
+
return MediaType2;
|
|
103
|
+
})(MediaType || {});
|
|
96
104
|
var ADD_CHARSET = /* @__PURE__ */ new Set([
|
|
97
105
|
"text/plain" /* PLAIN_TEXT */,
|
|
98
106
|
"text/html" /* HTML */,
|
|
@@ -145,6 +153,59 @@ function toBase64(raw) {
|
|
|
145
153
|
return btoa(binary);
|
|
146
154
|
}
|
|
147
155
|
|
|
156
|
+
// src/cors.ts
|
|
157
|
+
var Cors;
|
|
158
|
+
((Cors2) => {
|
|
159
|
+
Cors2.ALLOW_ORIGIN = "Access-Control-Allow-Origin";
|
|
160
|
+
Cors2.ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
|
|
161
|
+
Cors2.EXPOSE_HEADERS = "Access-Control-Expose-Headers";
|
|
162
|
+
Cors2.ALLOW_HEADERS = "Access-Control-Allow-Headers";
|
|
163
|
+
Cors2.ALLOW_METHODS = "Access-Control-Allow-Methods";
|
|
164
|
+
Cors2.MAX_AGE = "Access-Control-Max-Age";
|
|
165
|
+
Cors2.ALLOW_ALL_ORIGINS = "*";
|
|
166
|
+
})(Cors || (Cors = {}));
|
|
167
|
+
function addCorsHeaders(cors, headers) {
|
|
168
|
+
deleteCorsHeaders(headers);
|
|
169
|
+
const origin = cors.getOrigin();
|
|
170
|
+
if (!origin) return;
|
|
171
|
+
if (cors.allowAnyOrigin()) {
|
|
172
|
+
setHeader(headers, Cors.ALLOW_ORIGIN, Cors.ALLOW_ALL_ORIGINS);
|
|
173
|
+
} else if (cors.getAllowOrigins().includes(origin)) {
|
|
174
|
+
setHeader(headers, Cors.ALLOW_ORIGIN, origin);
|
|
175
|
+
setHeader(headers, Cors.ALLOW_CREDENTIALS, "true");
|
|
176
|
+
mergeHeader(headers, HttpHeader.VARY, HttpHeader.ORIGIN);
|
|
177
|
+
}
|
|
178
|
+
mergeHeader(headers, Cors.EXPOSE_HEADERS, cors.getExposeHeaders());
|
|
179
|
+
setHeader(headers, Cors.ALLOW_HEADERS, cors.getAllowHeaders());
|
|
180
|
+
setHeader(headers, Cors.ALLOW_METHODS, cors.getAllowMethods());
|
|
181
|
+
setHeader(headers, Cors.MAX_AGE, String(cors.getMaxAge()));
|
|
182
|
+
}
|
|
183
|
+
function deleteCorsHeaders(headers) {
|
|
184
|
+
headers.delete(Cors.ALLOW_ORIGIN);
|
|
185
|
+
headers.delete(Cors.ALLOW_CREDENTIALS);
|
|
186
|
+
headers.delete(Cors.EXPOSE_HEADERS);
|
|
187
|
+
headers.delete(Cors.ALLOW_METHODS);
|
|
188
|
+
headers.delete(Cors.MAX_AGE);
|
|
189
|
+
}
|
|
190
|
+
function withCorsHeaders(cors, res) {
|
|
191
|
+
const headers = new Headers(res.headers);
|
|
192
|
+
addCorsHeaders(cors, headers);
|
|
193
|
+
return new Response(res.body, {
|
|
194
|
+
status: res.status,
|
|
195
|
+
statusText: res.statusText,
|
|
196
|
+
headers
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
function withoutCorsHeaders(res) {
|
|
200
|
+
const headers = new Headers(res.headers);
|
|
201
|
+
deleteCorsHeaders(headers);
|
|
202
|
+
return new Response(res.body, {
|
|
203
|
+
status: res.status,
|
|
204
|
+
statusText: res.statusText,
|
|
205
|
+
headers
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
148
209
|
// src/base-worker.ts
|
|
149
210
|
var BaseWorker = class {
|
|
150
211
|
constructor(_request, _env = {}, _ctx) {
|
|
@@ -152,63 +213,101 @@ var BaseWorker = class {
|
|
|
152
213
|
this._env = _env;
|
|
153
214
|
this._ctx = _ctx;
|
|
154
215
|
}
|
|
216
|
+
/** The Request object associated with this worker invocation */
|
|
155
217
|
get request() {
|
|
156
218
|
return this._request;
|
|
157
219
|
}
|
|
220
|
+
/** Environment bindings (e.g., KV, secrets, or other globals) */
|
|
158
221
|
get env() {
|
|
159
222
|
return this._env;
|
|
160
223
|
}
|
|
224
|
+
/** Optional execution context for background tasks or `waitUntil` */
|
|
161
225
|
get ctx() {
|
|
162
226
|
return this._ctx;
|
|
163
227
|
}
|
|
164
228
|
};
|
|
165
229
|
|
|
166
|
-
// src/
|
|
167
|
-
var
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
return
|
|
230
|
+
// src/cors-worker.ts
|
|
231
|
+
var CorsWorker = class extends BaseWorker {
|
|
232
|
+
getAllowOrigins() {
|
|
233
|
+
return ["*"];
|
|
234
|
+
}
|
|
235
|
+
allowAnyOrigin() {
|
|
236
|
+
return this.getAllowOrigins().includes("*");
|
|
237
|
+
}
|
|
238
|
+
getAllowMethods() {
|
|
239
|
+
return ["GET" /* GET */, "OPTIONS" /* OPTIONS */, "HEAD" /* HEAD */];
|
|
240
|
+
}
|
|
241
|
+
getAllowHeaders() {
|
|
242
|
+
return ["Content-Type"];
|
|
243
|
+
}
|
|
244
|
+
getExposeHeaders() {
|
|
245
|
+
return [];
|
|
246
|
+
}
|
|
247
|
+
getMaxAge() {
|
|
248
|
+
return Time.Week;
|
|
249
|
+
}
|
|
250
|
+
getOrigin() {
|
|
251
|
+
return this.request.headers.get("Origin");
|
|
176
252
|
}
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
// src/cache-worker.ts
|
|
256
|
+
var CacheWorker = class extends CorsWorker {
|
|
257
|
+
/**
|
|
258
|
+
* Returns the cache key for the current request.
|
|
259
|
+
* By default, this is the normalized request URL.
|
|
260
|
+
*
|
|
261
|
+
* @returns A URL or RequestInfo to use as the cache key
|
|
262
|
+
*/
|
|
263
|
+
getCacheKey() {
|
|
264
|
+
return normalizeUrl(this.request.url);
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Retrieves a cached Response for the current request, if one exists.
|
|
268
|
+
*
|
|
269
|
+
* Behavior:
|
|
270
|
+
* - Only GET requests are cached.
|
|
271
|
+
* - If a cached response is found, CORS headers are applied dynamically
|
|
272
|
+
* using `withCorsHeaders` before returning.
|
|
273
|
+
* - Returns undefined if no cached response is found or if request is not GET.
|
|
274
|
+
*
|
|
275
|
+
* @param cacheName Optional name of the cache to use; defaults to `caches.default`.
|
|
276
|
+
* @returns A Promise resolving to a Response with correct CORS headers, or undefined.
|
|
277
|
+
*/
|
|
177
278
|
async getCachedResponse(cacheName) {
|
|
178
279
|
if (this.request.method !== "GET" /* GET */) return;
|
|
179
280
|
const cache = cacheName ? await caches.open(cacheName) : caches.default;
|
|
180
|
-
|
|
181
|
-
|
|
281
|
+
const response = await cache.match(this.getCacheKey());
|
|
282
|
+
return response ? withCorsHeaders(this, response) : void 0;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Stores a Response in the cache for the current request.
|
|
286
|
+
*
|
|
287
|
+
* Behavior:
|
|
288
|
+
* - Only caches successful GET responses (`response.ok === true`).
|
|
289
|
+
* - Removes all CORS headers before storing using `withoutCorsHeaders`.
|
|
290
|
+
* - Uses `ctx.waitUntil` to store asynchronously without blocking the worker.
|
|
291
|
+
*
|
|
292
|
+
* @param response The Response to cache
|
|
293
|
+
* @param cacheName Optional name of the cache to use; defaults to `caches.default`.
|
|
294
|
+
*/
|
|
182
295
|
async setCachedResponse(response, cacheName) {
|
|
183
296
|
if (!response.ok) return;
|
|
184
297
|
if (this.request.method !== "GET" /* GET */) return;
|
|
185
298
|
const cache = cacheName ? await caches.open(cacheName) : caches.default;
|
|
186
|
-
this.ctx?.waitUntil(cache.put(this.getCacheKey(), response
|
|
299
|
+
this.ctx?.waitUntil(cache.put(this.getCacheKey(), withoutCorsHeaders(response)));
|
|
187
300
|
}
|
|
188
301
|
};
|
|
189
302
|
|
|
190
303
|
// src/response.ts
|
|
191
304
|
import { getReasonPhrase, StatusCodes } from "http-status-codes";
|
|
192
|
-
|
|
193
|
-
// src/cors.ts
|
|
194
|
-
var Cors;
|
|
195
|
-
((Cors2) => {
|
|
196
|
-
Cors2.ALLOW_ORIGIN = "Access-Control-Allow-Origin";
|
|
197
|
-
Cors2.ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
|
|
198
|
-
Cors2.EXPOSE_HEADERS = "Access-Control-Expose-Headers";
|
|
199
|
-
Cors2.ALLOW_HEADERS = "Access-Control-Allow-Headers";
|
|
200
|
-
Cors2.ALLOW_METHODS = "Access-Control-Allow-Methods";
|
|
201
|
-
Cors2.MAX_AGE = "Access-Control-Max-Age";
|
|
202
|
-
Cors2.ALLOW_ALL_ORIGINS = "*";
|
|
203
|
-
})(Cors || (Cors = {}));
|
|
204
|
-
|
|
205
|
-
// src/response.ts
|
|
206
305
|
var BaseResponse = class {
|
|
207
306
|
headers = new Headers();
|
|
208
307
|
body;
|
|
209
308
|
status = StatusCodes.OK;
|
|
210
309
|
statusText;
|
|
211
|
-
|
|
310
|
+
mediaType;
|
|
212
311
|
constructor(content = null) {
|
|
213
312
|
this.body = this.status === StatusCodes.NO_CONTENT ? null : content;
|
|
214
313
|
}
|
|
@@ -226,8 +325,8 @@ var BaseResponse = class {
|
|
|
226
325
|
mergeHeader(this.headers, key, value);
|
|
227
326
|
}
|
|
228
327
|
addContentType() {
|
|
229
|
-
if (this.
|
|
230
|
-
this.headers.set(
|
|
328
|
+
if (this.mediaType) {
|
|
329
|
+
this.headers.set(HttpHeader.CONTENT_TYPE, getContentType(this.mediaType));
|
|
231
330
|
}
|
|
232
331
|
}
|
|
233
332
|
};
|
|
@@ -237,32 +336,17 @@ var CorsResponse = class extends BaseResponse {
|
|
|
237
336
|
this.cors = cors;
|
|
238
337
|
}
|
|
239
338
|
addCorsHeaders() {
|
|
240
|
-
|
|
241
|
-
if (!origin) return;
|
|
242
|
-
this.headers.delete(Cors.ALLOW_ORIGIN);
|
|
243
|
-
this.headers.delete(Cors.ALLOW_CREDENTIALS);
|
|
244
|
-
if (this.cors.allowAnyOrigin()) {
|
|
245
|
-
this.setHeader(Cors.ALLOW_ORIGIN, Cors.ALLOW_ALL_ORIGINS);
|
|
246
|
-
} else if (this.cors.getAllowOrigins().includes(origin)) {
|
|
247
|
-
this.setHeader(Cors.ALLOW_ORIGIN, origin);
|
|
248
|
-
this.setHeader(Cors.ALLOW_CREDENTIALS, String(true));
|
|
249
|
-
this.mergeHeader(HttpHeader.VARY, HttpHeader.ORIGIN);
|
|
250
|
-
}
|
|
251
|
-
this.mergeHeader(Cors.EXPOSE_HEADERS, this.cors.getExposeHeaders());
|
|
252
|
-
this.setHeader(Cors.ALLOW_HEADERS, this.cors.getAllowHeaders());
|
|
253
|
-
this.setHeader(Cors.ALLOW_METHODS, this.cors.getAllowMethods());
|
|
254
|
-
this.setHeader(Cors.MAX_AGE, String(this.cors.getMaxAge()));
|
|
339
|
+
addCorsHeaders(this.cors, this.headers);
|
|
255
340
|
}
|
|
256
341
|
};
|
|
257
342
|
var CacheResponse = class extends CorsResponse {
|
|
258
|
-
cache;
|
|
259
343
|
constructor(cors, body = null, cache) {
|
|
260
344
|
super(cors, body);
|
|
261
345
|
this.cache = cache;
|
|
262
346
|
}
|
|
263
347
|
addCacheHeader() {
|
|
264
348
|
if (this.cache) {
|
|
265
|
-
this.headers.set(
|
|
349
|
+
this.headers.set(HttpHeader.CACHE_CONTROL, CacheControl.stringify(this.cache));
|
|
266
350
|
}
|
|
267
351
|
}
|
|
268
352
|
};
|
|
@@ -297,19 +381,19 @@ var SuccessResponse = class extends WorkerResponse {
|
|
|
297
381
|
var JsonResponse = class extends SuccessResponse {
|
|
298
382
|
constructor(cors, json = {}, cache, status = StatusCodes.OK) {
|
|
299
383
|
super(cors, JSON.stringify(json), cache, status);
|
|
300
|
-
this.
|
|
384
|
+
this.mediaType = "application/json" /* JSON */;
|
|
301
385
|
}
|
|
302
386
|
};
|
|
303
387
|
var HtmlResponse = class extends SuccessResponse {
|
|
304
388
|
constructor(cors, body, cache, status = StatusCodes.OK) {
|
|
305
389
|
super(cors, body, cache, status);
|
|
306
|
-
this.
|
|
390
|
+
this.mediaType = "text/html" /* HTML */;
|
|
307
391
|
}
|
|
308
392
|
};
|
|
309
393
|
var TextResponse = class extends SuccessResponse {
|
|
310
394
|
constructor(cors, content, cache, status = StatusCodes.OK) {
|
|
311
395
|
super(cors, content, cache, status);
|
|
312
|
-
this.
|
|
396
|
+
this.mediaType = "text/plain" /* PLAIN_TEXT */;
|
|
313
397
|
}
|
|
314
398
|
};
|
|
315
399
|
var Head = class extends WorkerResponse {
|
|
@@ -444,9 +528,6 @@ var BasicWorker = class extends CacheWorker {
|
|
|
444
528
|
await this.dispatch(new Request(this.request, { method: "GET" /* GET */ }))
|
|
445
529
|
);
|
|
446
530
|
}
|
|
447
|
-
getCacheKey() {
|
|
448
|
-
return super.getCacheKey(this.getOrigin());
|
|
449
|
-
}
|
|
450
531
|
async getResponse(ResponseClass, ...args) {
|
|
451
532
|
const response = new ResponseClass(this, ...args).createResponse();
|
|
452
533
|
this.setCachedResponse(response);
|
|
@@ -455,27 +536,6 @@ var BasicWorker = class extends CacheWorker {
|
|
|
455
536
|
isAllowed(method) {
|
|
456
537
|
return isMethod(method) && this.getAllowMethods().includes(method);
|
|
457
538
|
}
|
|
458
|
-
getAllowOrigins() {
|
|
459
|
-
return ["*"];
|
|
460
|
-
}
|
|
461
|
-
allowAnyOrigin() {
|
|
462
|
-
return this.getAllowOrigins().includes("*");
|
|
463
|
-
}
|
|
464
|
-
getAllowMethods() {
|
|
465
|
-
return ["GET" /* GET */, "OPTIONS" /* OPTIONS */, "HEAD" /* HEAD */];
|
|
466
|
-
}
|
|
467
|
-
getAllowHeaders() {
|
|
468
|
-
return ["Content-Type"];
|
|
469
|
-
}
|
|
470
|
-
getExposeHeaders() {
|
|
471
|
-
return [];
|
|
472
|
-
}
|
|
473
|
-
getMaxAge() {
|
|
474
|
-
return Time.Week;
|
|
475
|
-
}
|
|
476
|
-
getOrigin() {
|
|
477
|
-
return this.request.headers.get("Origin");
|
|
478
|
-
}
|
|
479
539
|
};
|
|
480
540
|
|
|
481
541
|
// src/routes.ts
|
|
@@ -552,9 +612,9 @@ export {
|
|
|
552
612
|
HttpHeader,
|
|
553
613
|
InternalServerError,
|
|
554
614
|
JsonResponse,
|
|
615
|
+
MediaType,
|
|
555
616
|
Method,
|
|
556
617
|
MethodNotAllowed,
|
|
557
|
-
MimeType,
|
|
558
618
|
NotFound,
|
|
559
619
|
NotImplemented,
|
|
560
620
|
Options,
|
|
@@ -568,11 +628,15 @@ export {
|
|
|
568
628
|
Time,
|
|
569
629
|
Unauthorized,
|
|
570
630
|
WorkerResponse,
|
|
631
|
+
addCorsHeaders,
|
|
632
|
+
deleteCorsHeaders,
|
|
571
633
|
getContentType,
|
|
572
634
|
isMethod,
|
|
573
635
|
mergeHeader,
|
|
574
636
|
normalizeUrl,
|
|
575
637
|
setHeader,
|
|
576
|
-
toBase64
|
|
638
|
+
toBase64,
|
|
639
|
+
withCorsHeaders,
|
|
640
|
+
withoutCorsHeaders
|
|
577
641
|
};
|
|
578
642
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/common.ts","../src/base-worker.ts","../src/cache-worker.ts","../src/response.ts","../src/cors.ts","../src/basic-worker.ts","../src/routes.ts","../src/routed-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\nexport { StatusCodes } from \"http-status-codes\";\n\nexport * from \"./basic-worker\";\nexport * from \"./common\";\nexport * from \"./cors\";\nexport * from \"./response\";\nexport * from \"./routed-worker\";\nexport * from \"./routes\";\nexport * from \"./worker\";\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\n/**\n * https://github.com/etienne-martin/cache-control-parser\n */\nimport CacheLib from \"cache-control-parser\";\n\nexport type CacheControl = CacheLib.CacheControl;\nexport const CacheControl = {\n parse: CacheLib.parse,\n stringify: CacheLib.stringify,\n};\n\nexport namespace HttpHeader {\n export const VARY = \"Vary\";\n\n // Security Headers\n export const X_CONTENT_TYPE_OPTIONS = \"X-Content-Type-Options\"; // usually \"nosniff\"\n export const X_FRAME_OPTIONS = \"X-Frame-Options\"; // e.g. \"DENY\" or \"SAMEORIGIN\"\n export const STRICT_TRANSPORT_SECURITY = \"Strict-Transport-Security\"; // e.g. \"max-age=63072000; includeSubDomains; preload\"\n export const CONTENT_SECURITY_POLICY = \"Content-Security-Policy\"; // fine-grained script/style/image restrictions\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\n // Values\n export const NOSNIFF = \"nosniff\";\n export const ORIGIN = \"Origin\";\n}\n\nexport const Time = {\n Second: 1,\n Minute: 60,\n Hour: 60 * 60,\n Day: 60 * 60 * 24,\n Week: 60 * 60 * 24 * 7,\n Year: 60 * 60 * 24 * 365,\n} as const;\n\nexport enum Method {\n GET = \"GET\",\n PUT = \"PUT\",\n POST = \"POST\",\n PATCH = \"PATCH\",\n DELETE = \"DELETE\",\n HEAD = \"HEAD\",\n OPTIONS = \"OPTIONS\",\n}\nconst METHOD_SET: Set<string> = new Set(Object.values(Method));\n\nexport function isMethod(value: string): value is Method {\n return METHOD_SET.has(value);\n}\n\nexport function getContentType(type: MimeType): string {\n if (ADD_CHARSET.has(type)) {\n return `${type}; charset=utf-8`;\n }\n return type;\n}\n\nexport enum MimeType {\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\nconst ADD_CHARSET: Set<MimeType> = new Set([\n MimeType.PLAIN_TEXT,\n MimeType.HTML,\n MimeType.CSS,\n MimeType.CSV,\n MimeType.MARKDOWN,\n MimeType.XML,\n MimeType.JSON,\n MimeType.XML_APP,\n MimeType.FORM_URLENCODED,\n MimeType.NDJSON,\n MimeType.RICH_TEXT,\n MimeType.SVG,\n]);\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()))).filter((v) => v.length);\n\n if (!values.length) {\n headers.delete(key);\n return;\n }\n\n headers.set(key, values.join(\", \"));\n}\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\nexport function toBase64(raw: string): string {\n const bytes = new TextEncoder().encode(raw);\n let binary = \"\";\n for (const b of bytes) {\n binary += String.fromCharCode(b);\n }\n return btoa(binary);\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Worker } from \"./worker\";\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 protected get request(): Request {\n return this._request;\n }\n\n protected get env(): Env {\n return this._env;\n }\n\n protected get ctx(): ExecutionContext | undefined {\n return this._ctx;\n }\n\n public abstract fetch(): Promise<Response>;\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Method, normalizeUrl, toBase64 } from \"./common\";\nimport { BaseWorker } from \"./base-worker\";\n\nexport abstract class CacheWorker extends BaseWorker {\n protected getCacheKey(...values: Array<string | null | undefined>): URL | RequestInfo {\n const raw = [\n normalizeUrl(this.request.url),\n ...values\n .filter((v) => v != null) // remove null/undefined\n .map((v) => v!.trim()) // trim whitespace\n .filter((v) => v.length > 0), // skip empty strings after trim\n ].join(\"\\u0001\");\n const base64 = toBase64(raw).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n return new URL(`http://cache/${base64}`);\n }\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 return cache.match(this.getCacheKey());\n }\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(cache.put(this.getCacheKey(), response.clone()));\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 Method,\n MimeType,\n setHeader,\n} from \"./common\";\nimport { Cors, CorsProvider } from \"./cors\";\n\nexport interface ErrorJson {\n status: number;\n error: string;\n details: string;\n}\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 mimeType?: MimeType;\n\n constructor(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.mimeType) {\n this.headers.set(\"Content-Type\", getContentType(this.mimeType));\n }\n }\n}\n\nabstract class CorsResponse extends BaseResponse {\n constructor(public readonly cors: CorsProvider, content: BodyInit | null = null) {\n super(content);\n }\n\n protected addCorsHeaders(): void {\n const origin = this.cors.getOrigin();\n if (!origin) return; // no Origin, skip CORS\n\n this.headers.delete(Cors.ALLOW_ORIGIN);\n this.headers.delete(Cors.ALLOW_CREDENTIALS);\n\n if (this.cors.allowAnyOrigin()) {\n this.setHeader(Cors.ALLOW_ORIGIN, Cors.ALLOW_ALL_ORIGINS);\n } else if (this.cors.getAllowOrigins().includes(origin)) {\n this.setHeader(Cors.ALLOW_ORIGIN, origin);\n this.setHeader(Cors.ALLOW_CREDENTIALS, String(true));\n this.mergeHeader(HttpHeader.VARY, HttpHeader.ORIGIN);\n }\n\n this.mergeHeader(Cors.EXPOSE_HEADERS, this.cors.getExposeHeaders());\n this.setHeader(Cors.ALLOW_HEADERS, this.cors.getAllowHeaders());\n this.setHeader(Cors.ALLOW_METHODS, this.cors.getAllowMethods());\n this.setHeader(Cors.MAX_AGE, String(this.cors.getMaxAge()));\n }\n}\n\nabstract class CacheResponse extends CorsResponse {\n public cache?: CacheControl;\n\n constructor(cors: CorsProvider, body: BodyInit | null = null, cache?: CacheControl) {\n super(cors, body);\n this.cache = cache;\n }\n\n protected addCacheHeader(): void {\n if (this.cache) {\n this.headers.set(\"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.addCacheHeader();\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(cors: CorsProvider, response: Response, cache?: CacheControl) {\n const clone = response.clone();\n super(cors, 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 cors: CorsProvider,\n body: BodyInit | null = null,\n cache?: CacheControl,\n status: StatusCodes = StatusCodes.OK\n ) {\n super(cors, body, cache);\n this.status = status;\n }\n}\n\nexport class JsonResponse extends SuccessResponse {\n constructor(\n cors: CorsProvider,\n json: unknown = {},\n cache?: CacheControl,\n status: StatusCodes = StatusCodes.OK\n ) {\n super(cors, JSON.stringify(json), cache, status);\n this.mimeType = MimeType.JSON;\n }\n}\n\nexport class HtmlResponse extends SuccessResponse {\n constructor(\n cors: CorsProvider,\n body: string,\n cache?: CacheControl,\n status: StatusCodes = StatusCodes.OK\n ) {\n super(cors, body, cache, status);\n this.mimeType = MimeType.HTML;\n }\n}\n\nexport class TextResponse extends SuccessResponse {\n constructor(\n cors: CorsProvider,\n content: string,\n cache?: CacheControl,\n status: StatusCodes = StatusCodes.OK\n ) {\n super(cors, content, cache, status);\n this.mimeType = MimeType.PLAIN_TEXT;\n }\n}\n\n/**\n * Removes the body from a GET response.\n */\nexport class Head extends WorkerResponse {\n constructor(cors: CorsProvider, get: Response) {\n super(cors);\n this.headers = new Headers(get.headers);\n }\n}\n\nexport class Options extends SuccessResponse {\n constructor(cors: CorsProvider) {\n super(cors, null, undefined, StatusCodes.NO_CONTENT);\n this.setHeader(\"Allow\", this.cors.getAllowMethods());\n }\n}\n\nexport class HttpError extends JsonResponse {\n constructor(cors: CorsProvider, status: StatusCodes, protected readonly details?: string) {\n const cache: CacheControl = {\n \"no-cache\": true,\n \"no-store\": true,\n \"must-revalidate\": true,\n \"max-age\": 0,\n };\n super(cors, undefined, cache, 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(cors: CorsProvider, details?: string) {\n super(cors, StatusCodes.BAD_REQUEST, details);\n }\n}\n\nexport class Unauthorized extends HttpError {\n constructor(cors: CorsProvider, details?: string) {\n super(cors, StatusCodes.UNAUTHORIZED, details);\n }\n}\n\nexport class Forbidden extends HttpError {\n constructor(cors: CorsProvider, details?: string) {\n super(cors, StatusCodes.FORBIDDEN, details);\n }\n}\n\nexport class NotFound extends HttpError {\n constructor(cors: CorsProvider, details?: string) {\n super(cors, StatusCodes.NOT_FOUND, details);\n }\n}\n\nexport class MethodNotAllowed extends HttpError {\n constructor(cors: CorsProvider, method: string) {\n super(cors, StatusCodes.METHOD_NOT_ALLOWED, `${method} method not allowed.`);\n this.setHeader(\"Allow\", this.cors.getAllowMethods());\n }\n\n public override get json(): ErrorJson & { allowed: Method[] } {\n return {\n ...super.json,\n allowed: this.cors.getAllowMethods(),\n };\n }\n}\n\nexport class InternalServerError extends HttpError {\n constructor(cors: CorsProvider, details?: string) {\n super(cors, StatusCodes.INTERNAL_SERVER_ERROR, details);\n }\n}\n\nexport class NotImplemented extends HttpError {\n constructor(cors: CorsProvider) {\n super(cors, StatusCodes.NOT_IMPLEMENTED);\n }\n}\n\nexport class ServiceUnavailable extends HttpError {\n constructor(cors: CorsProvider, details?: string) {\n super(cors, 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 { Method } from \"./common\";\n\nexport interface CorsProvider {\n getOrigin(): string | null;\n getAllowOrigins(): string[];\n allowAnyOrigin(): boolean;\n getAllowMethods(): Method[];\n getAllowHeaders(): string[];\n getExposeHeaders(): string[];\n getMaxAge(): number;\n}\n\nexport namespace Cors {\n export const ALLOW_ORIGIN = \"Access-Control-Allow-Origin\";\n export const ALLOW_CREDENTIALS = \"Access-Control-Allow-Credentials\";\n export const EXPOSE_HEADERS = \"Access-Control-Expose-Headers\";\n export const ALLOW_HEADERS = \"Access-Control-Allow-Headers\";\n export const ALLOW_METHODS = \"Access-Control-Allow-Methods\";\n export const MAX_AGE = \"Access-Control-Max-Age\";\n export const ALLOW_ALL_ORIGINS = \"*\";\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, Time } from \"./common\";\nimport { CorsProvider } from \"./cors\";\nimport {\n Head,\n InternalServerError,\n MethodNotAllowed,\n NotImplemented,\n Options,\n WorkerResponse,\n} from \"./response\";\n\nexport abstract class BasicWorker extends CacheWorker implements CorsProvider {\n public async fetch(): Promise<Response> {\n if (!this.isAllowed(this.request.method)) {\n return this.getResponse(MethodNotAllowed, this.request.method);\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(request: Request = this.request): Promise<Response> {\n const method = request.method as Method;\n const handler: Record<Method, () => Promise<Response>> = {\n GET: () => this.get(),\n PUT: () => this.put(),\n POST: () => this.post(),\n PATCH: () => this.patch(),\n DELETE: () => this.delete(),\n HEAD: () => this.head(),\n OPTIONS: () => this.options(),\n };\n return (handler[method] ?? (() => this.getResponse(MethodNotAllowed, method)))();\n }\n\n protected async get(): Promise<Response> {\n return this.getResponse(NotImplemented);\n }\n\n protected async put(): Promise<Response> {\n return this.getResponse(NotImplemented);\n }\n\n protected async post(): Promise<Response> {\n return this.getResponse(NotImplemented);\n }\n\n protected async patch(): Promise<Response> {\n return this.getResponse(NotImplemented);\n }\n\n protected async delete(): Promise<Response> {\n return this.getResponse(NotImplemented);\n }\n\n protected async options(): Promise<Response> {\n return this.getResponse(Options);\n }\n\n protected async head(): Promise<Response> {\n // Dispatch a new GET request created from the HEAD request\n // and return the GET response with the body removed.\n return this.getResponse(\n Head,\n await this.dispatch(new Request(this.request, { method: Method.GET }))\n );\n }\n\n protected override getCacheKey(): URL | RequestInfo {\n return super.getCacheKey(this.getOrigin());\n }\n\n protected async getResponse<\n T extends WorkerResponse,\n Ctor extends new (cors: CorsProvider, ...args: any[]) => T\n >(\n ResponseClass: Ctor,\n ...args: ConstructorParameters<Ctor> extends [any, ...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 public isAllowed(method: string): boolean {\n return isMethod(method) && this.getAllowMethods().includes(method);\n }\n\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.OPTIONS, Method.HEAD];\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 public getOrigin(): string | null {\n return this.request.headers.get(\"Origin\");\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\nexport type RouteCallback = (...matches: string[]) => Response | Promise<Response>;\n\nexport type RouteInit = [Method, string, RouteCallback];\n\nexport class Route {\n public readonly pattern: RegExp;\n\n constructor(pattern: RegExp | string, public readonly callback: RouteCallback) {\n this.pattern = new RegExp(pattern);\n }\n}\n\nexport class Routes {\n private readonly map = new Map<Method, Route[]>();\n\n public add(method: Method, route: Route) {\n const existing = this.map.get(method);\n if (existing) {\n existing.push(route);\n } else {\n this.map.set(method, [route]);\n }\n return this;\n }\n\n public get(method: Method, url: string): Route | undefined {\n const routes = this.map.get(method);\n if (!routes) return undefined;\n\n const pathname = new URL(url).pathname;\n return routes.find(({ pattern }) => pattern.test(pathname));\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 \"./response\";\nimport { Route, Routes, RouteInit, RouteCallback } from \"./routes\";\n\nexport abstract class RoutedWorker extends BasicWorker {\n private readonly routes: Routes = new Routes();\n\n protected initialize(routes: RouteInit[]) {\n routes.forEach(([method, pattern, callback]) => {\n this.add(method, pattern, callback);\n });\n }\n\n protected add(method: Method, pattern: RegExp | string, callback: RouteCallback) {\n this.routes.add(method, new Route(pattern, callback));\n return this;\n }\n\n protected async dispatch(request: Request = this.request): Promise<Response> {\n const route = this.routes.get(request.method as Method, request.url);\n if (!route) return super.dispatch(request);\n\n const match = new URL(request.url).pathname.match(route.pattern) ?? [];\n return route.callback.call(this, ...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":["StatusCodes","HttpHeader","Method","MimeType","Cors"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/common.ts","../src/cors.ts","../src/base-worker.ts","../src/cors-worker.ts","../src/cache-worker.ts","../src/response.ts","../src/basic-worker.ts","../src/routes.ts","../src/routed-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\nexport { StatusCodes } from \"http-status-codes\";\n\nexport * from \"./basic-worker\";\nexport * from \"./common\";\nexport * from \"./cors\";\nexport * from \"./response\";\nexport * from \"./routed-worker\";\nexport * from \"./routes\";\nexport * from \"./worker\";\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 CacheLib from \"cache-control-parser\";\n\n/**\n * - See https://github.com/etienne-martin/cache-control-parser\n */\nexport type CacheControl = CacheLib.CacheControl;\nexport const CacheControl = {\n parse: CacheLib.parse,\n stringify: CacheLib.stringify,\n};\n\n/**\n * Standard HTTP header names and common values.\n */\nexport namespace HttpHeader {\n export const VARY = \"Vary\";\n export const CONTENT_TYPE = \"Content-Type\";\n export const CACHE_CONTROL = \"Cache-Control\";\n\n // Security Headers\n export const X_CONTENT_TYPE_OPTIONS = \"X-Content-Type-Options\"; // usually \"nosniff\"\n export const X_FRAME_OPTIONS = \"X-Frame-Options\"; // e.g. \"DENY\" or \"SAMEORIGIN\"\n export const STRICT_TRANSPORT_SECURITY = \"Strict-Transport-Security\"; // e.g. \"max-age=63072000; includeSubDomains; preload\"\n export const CONTENT_SECURITY_POLICY = \"Content-Security-Policy\"; // fine-grained script/style/image restrictions\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\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 POST = \"POST\",\n PATCH = \"PATCH\",\n DELETE = \"DELETE\",\n HEAD = \"HEAD\",\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.PLAIN_TEXT,\n MediaType.HTML,\n MediaType.CSS,\n MediaType.CSV,\n MediaType.MARKDOWN,\n MediaType.XML,\n MediaType.JSON,\n MediaType.XML_APP,\n MediaType.FORM_URLENCODED,\n MediaType.NDJSON,\n MediaType.RICH_TEXT,\n MediaType.SVG,\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()))).filter((v) => v.length);\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 * Encodes a given string into Base64 using UTF-8 encoding.\n *\n * This function correctly handles any Unicode characters.\n *\n * @param raw - The input string to encode.\n * @returns The Base64-encoded string.\n */\nexport function toBase64(raw: string): string {\n const bytes = new TextEncoder().encode(raw);\n let binary = \"\";\n for (const b of bytes) {\n binary += String.fromCharCode(b);\n }\n return btoa(binary);\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 { HttpHeader, mergeHeader, Method, setHeader } from \"./common\";\n\n/**\n * Provides information about the CORS policy for the current request.\n */\nexport interface CorsProvider {\n /** Returns the origin of the request, or null if none is provided. */\n getOrigin(): string | null;\n\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 ALLOW_ORIGIN = \"Access-Control-Allow-Origin\";\n export const ALLOW_CREDENTIALS = \"Access-Control-Allow-Credentials\";\n export const EXPOSE_HEADERS = \"Access-Control-Expose-Headers\";\n export const ALLOW_HEADERS = \"Access-Control-Allow-Headers\";\n export const ALLOW_METHODS = \"Access-Control-Allow-Methods\";\n export const MAX_AGE = \"Access-Control-Max-Age\";\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(cors: CorsProvider, headers: Headers): void {\n // Remove stale headers if from cache\n deleteCorsHeaders(headers);\n\n const origin = cors.getOrigin();\n if (!origin) 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 mergeHeader(headers, HttpHeader.VARY, HttpHeader.ORIGIN);\n }\n\n // Optional headers always applied\n mergeHeader(headers, Cors.EXPOSE_HEADERS, cors.getExposeHeaders());\n setHeader(headers, Cors.ALLOW_HEADERS, cors.getAllowHeaders());\n setHeader(headers, Cors.ALLOW_METHODS, cors.getAllowMethods());\n setHeader(headers, Cors.MAX_AGE, String(cors.getMaxAge()));\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 */\nexport function deleteCorsHeaders(headers: Headers) {\n headers.delete(Cors.ALLOW_ORIGIN);\n headers.delete(Cors.ALLOW_CREDENTIALS);\n headers.delete(Cors.EXPOSE_HEADERS);\n headers.delete(Cors.ALLOW_METHODS);\n headers.delete(Cors.MAX_AGE);\n}\n\n/**\n * Returns a new Response with CORS headers applied according to the policy.\n * Original response is not mutated.\n *\n * @param cors The CorsProvider instance for policy\n * @param res The original Response object\n * @returns A new Response with updated CORS headers\n */\nexport function withCorsHeaders(cors: CorsProvider, res: Response): Response {\n const headers = new Headers(res.headers);\n addCorsHeaders(cors, headers);\n return new Response(res.body, {\n status: res.status,\n statusText: res.statusText,\n headers,\n });\n}\n\n/**\n * Returns a new Response with all standard CORS headers removed.\n * Useful for storing responses in a cache without per-request CORS headers.\n *\n * @param res The original Response object\n * @returns A new Response without CORS headers\n */\nexport function withoutCorsHeaders(res: Response): Response {\n const headers = new Headers(res.headers);\n deleteCorsHeaders(headers);\n return new Response(res.body, {\n status: res.status,\n statusText: res.statusText,\n headers,\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 } from \"./worker\";\n\n/**\n * Provides the foundational structure for handling requests, environment bindings,\n * and the worker execution context. Subclasses are expected to implement the\n * `fetch` method to handle the request and return a Response.\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), if available.\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 protected get request(): Request {\n return this._request;\n }\n\n /** Environment bindings (e.g., KV, secrets, or other globals) */\n protected get env(): Env {\n return this._env;\n }\n\n /** Optional execution context for background tasks or `waitUntil` */\n protected get ctx(): ExecutionContext | undefined {\n return this._ctx;\n }\n\n /**\n * Process the request and produce a Response.\n * Subclasses must implement this method.\n *\n * @returns A Promise resolving to the Response for the request\n */\n public abstract fetch(): Promise<Response>;\n}\n","/*\n * Copyright (C) 2025 Ty Busby\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { 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.OPTIONS, Method.HEAD];\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 public getOrigin(): string | null {\n return this.request.headers.get(\"Origin\");\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, normalizeUrl } from \"./common\";\nimport { withCorsHeaders, withoutCorsHeaders } from \"./cors\";\nimport { CorsWorker } from \"./cors-worker\";\n\n/**\n * Abstract base class for Workers that support caching of GET responses.\n *\n * Features:\n * - URL-based caching using `Request.url`.\n * - Removes per-request CORS headers before storing in cache.\n * - Dynamically applies correct CORS headers when retrieving cached responses.\n * - Only caches successful GET requests.\n */\nexport abstract class CacheWorker extends CorsWorker {\n /**\n * Returns the cache key for the current request.\n * By default, this is the normalized request URL.\n *\n * @returns A URL or RequestInfo to use 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 cached.\n * - If a cached response is found, CORS headers are applied dynamically\n * using `withCorsHeaders` before returning.\n * - Returns undefined if no cached response is found or if request is not GET.\n *\n * @param cacheName Optional name of the cache to use; defaults to `caches.default`.\n * @returns A Promise resolving to a Response with correct CORS headers, or undefined.\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\n const response = await cache.match(this.getCacheKey());\n return response ? withCorsHeaders(this, 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 * - Removes all CORS headers before storing using `withoutCorsHeaders`.\n * - Uses `ctx.waitUntil` to store asynchronously without blocking the worker.\n *\n * @param response The Response to cache\n * @param cacheName Optional name of the cache to use; defaults to `caches.default`.\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(cache.put(this.getCacheKey(), withoutCorsHeaders(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 { getReasonPhrase, StatusCodes } from \"http-status-codes\";\nimport {\n CacheControl,\n getContentType,\n HttpHeader,\n mergeHeader,\n Method,\n MediaType,\n setHeader,\n} from \"./common\";\nimport { addCorsHeaders, CorsProvider } from \"./cors\";\n\nexport interface ErrorJson {\n status: number;\n error: string;\n details: string;\n}\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(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(public readonly cors: CorsProvider, content: BodyInit | null = null) {\n super(content);\n }\n\n protected addCorsHeaders(): void {\n addCorsHeaders(this.cors, this.headers);\n }\n}\n\nabstract class CacheResponse extends CorsResponse {\n constructor(cors: CorsProvider, body: BodyInit | null = null, public cache?: CacheControl) {\n super(cors, body);\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 public createResponse(): Response {\n this.addCorsHeaders();\n this.addCacheHeader();\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(cors: CorsProvider, response: Response, cache?: CacheControl) {\n const clone = response.clone();\n super(cors, 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 cors: CorsProvider,\n body: BodyInit | null = null,\n cache?: CacheControl,\n status: StatusCodes = StatusCodes.OK\n ) {\n super(cors, body, cache);\n this.status = status;\n }\n}\n\nexport class JsonResponse extends SuccessResponse {\n constructor(\n cors: CorsProvider,\n json: unknown = {},\n cache?: CacheControl,\n status: StatusCodes = StatusCodes.OK\n ) {\n super(cors, JSON.stringify(json), cache, status);\n this.mediaType = MediaType.JSON;\n }\n}\n\nexport class HtmlResponse extends SuccessResponse {\n constructor(\n cors: CorsProvider,\n body: string,\n cache?: CacheControl,\n status: StatusCodes = StatusCodes.OK\n ) {\n super(cors, body, cache, status);\n this.mediaType = MediaType.HTML;\n }\n}\n\nexport class TextResponse extends SuccessResponse {\n constructor(\n cors: CorsProvider,\n content: string,\n cache?: CacheControl,\n status: StatusCodes = StatusCodes.OK\n ) {\n super(cors, 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(cors: CorsProvider, get: Response) {\n super(cors);\n this.headers = new Headers(get.headers);\n }\n}\n\nexport class Options extends SuccessResponse {\n constructor(cors: CorsProvider) {\n super(cors, null, undefined, StatusCodes.NO_CONTENT);\n this.setHeader(\"Allow\", this.cors.getAllowMethods());\n }\n}\n\nexport class HttpError extends JsonResponse {\n constructor(cors: CorsProvider, status: StatusCodes, protected readonly details?: string) {\n const cache: CacheControl = {\n \"no-cache\": true,\n \"no-store\": true,\n \"must-revalidate\": true,\n \"max-age\": 0,\n };\n super(cors, undefined, cache, 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(cors: CorsProvider, details?: string) {\n super(cors, StatusCodes.BAD_REQUEST, details);\n }\n}\n\nexport class Unauthorized extends HttpError {\n constructor(cors: CorsProvider, details?: string) {\n super(cors, StatusCodes.UNAUTHORIZED, details);\n }\n}\n\nexport class Forbidden extends HttpError {\n constructor(cors: CorsProvider, details?: string) {\n super(cors, StatusCodes.FORBIDDEN, details);\n }\n}\n\nexport class NotFound extends HttpError {\n constructor(cors: CorsProvider, details?: string) {\n super(cors, StatusCodes.NOT_FOUND, details);\n }\n}\n\nexport class MethodNotAllowed extends HttpError {\n constructor(cors: CorsProvider, method: string) {\n super(cors, StatusCodes.METHOD_NOT_ALLOWED, `${method} method not allowed.`);\n this.setHeader(\"Allow\", this.cors.getAllowMethods());\n }\n\n public override get json(): ErrorJson & { allowed: Method[] } {\n return {\n ...super.json,\n allowed: this.cors.getAllowMethods(),\n };\n }\n}\n\nexport class InternalServerError extends HttpError {\n constructor(cors: CorsProvider, details?: string) {\n super(cors, StatusCodes.INTERNAL_SERVER_ERROR, details);\n }\n}\n\nexport class NotImplemented extends HttpError {\n constructor(cors: CorsProvider) {\n super(cors, StatusCodes.NOT_IMPLEMENTED);\n }\n}\n\nexport class ServiceUnavailable extends HttpError {\n constructor(cors: CorsProvider, details?: string) {\n super(cors, 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 { CacheWorker } from \"./cache-worker\";\nimport { isMethod, Method } from \"./common\";\nimport { CorsProvider } from \"./cors\";\nimport {\n Head,\n InternalServerError,\n MethodNotAllowed,\n NotImplemented,\n Options,\n WorkerResponse,\n} 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, this.request.method);\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(request: Request = this.request): Promise<Response> {\n const method = request.method as Method;\n const handler: Record<Method, () => Promise<Response>> = {\n GET: () => this.get(),\n PUT: () => this.put(),\n POST: () => this.post(),\n PATCH: () => this.patch(),\n DELETE: () => this.delete(),\n HEAD: () => this.head(),\n OPTIONS: () => this.options(),\n };\n return (handler[method] ?? (() => this.getResponse(MethodNotAllowed, method)))();\n }\n\n protected async get(): Promise<Response> {\n return this.getResponse(NotImplemented);\n }\n\n protected async put(): Promise<Response> {\n return this.getResponse(NotImplemented);\n }\n\n protected async post(): Promise<Response> {\n return this.getResponse(NotImplemented);\n }\n\n protected async patch(): Promise<Response> {\n return this.getResponse(NotImplemented);\n }\n\n protected async delete(): Promise<Response> {\n return this.getResponse(NotImplemented);\n }\n\n protected async options(): Promise<Response> {\n return this.getResponse(Options);\n }\n\n protected async head(): Promise<Response> {\n // Dispatch a new GET request created from the HEAD request\n // and return the GET response with the body removed.\n return this.getResponse(\n Head,\n await this.dispatch(new Request(this.request, { method: Method.GET }))\n );\n }\n\n protected async getResponse<\n T extends WorkerResponse,\n Ctor extends new (cors: CorsProvider, ...args: any[]) => T\n >(\n ResponseClass: Ctor,\n ...args: ConstructorParameters<Ctor> extends [CorsProvider, ...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 public isAllowed(method: string): boolean {\n return isMethod(method) && this.getAllowMethods().includes(method);\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\nexport type RouteCallback = (...matches: string[]) => Response | Promise<Response>;\n\nexport type RouteInit = [Method, string, RouteCallback];\n\nexport class Route {\n public readonly pattern: RegExp;\n\n constructor(pattern: RegExp | string, public readonly callback: RouteCallback) {\n this.pattern = new RegExp(pattern);\n }\n}\n\nexport class Routes {\n private readonly map = new Map<Method, Route[]>();\n\n public add(method: Method, route: Route) {\n const existing = this.map.get(method);\n if (existing) {\n existing.push(route);\n } else {\n this.map.set(method, [route]);\n }\n return this;\n }\n\n public get(method: Method, url: string): Route | undefined {\n const routes = this.map.get(method);\n if (!routes) return undefined;\n\n const pathname = new URL(url).pathname;\n return routes.find(({ pattern }) => pattern.test(pathname));\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 \"./response\";\nimport { Route, Routes, RouteInit, RouteCallback } from \"./routes\";\n\nexport abstract class RoutedWorker extends BasicWorker {\n private readonly routes: Routes = new Routes();\n\n protected initialize(routes: RouteInit[]) {\n routes.forEach(([method, pattern, callback]) => {\n this.add(method, pattern, callback);\n });\n }\n\n protected add(method: Method, pattern: RegExp | string, callback: RouteCallback) {\n this.routes.add(method, new Route(pattern, callback));\n return this;\n }\n\n protected async dispatch(request: Request = this.request): Promise<Response> {\n const route = this.routes.get(request.method as Method, request.url);\n if (!route) return super.dispatch(request);\n\n const match = new URL(request.url).pathname.match(route.pattern) ?? [];\n return route.callback.call(this, ...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":["StatusCodes","HttpHeader","Method","MediaType","Cors"]}
|