mirror of
https://github.com/JonasunderscoreJones/api.jonasjones.dev.git
synced 2025-10-23 12:09:19 +02:00
Initial commit (by create-cloudflare CLI)
This commit is contained in:
commit
58a42872a0
1745 changed files with 741893 additions and 0 deletions
36
node_modules/@cloudflare/kv-asset-handler/dist/index.d.ts
generated
vendored
Normal file
36
node_modules/@cloudflare/kv-asset-handler/dist/index.d.ts
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { Options, CacheControl, MethodNotAllowedError, NotFoundError, InternalError } from './types';
|
||||
declare global {
|
||||
var __STATIC_CONTENT: any, __STATIC_CONTENT_MANIFEST: string;
|
||||
}
|
||||
/**
|
||||
* maps the path of incoming request to the request pathKey to look up
|
||||
* in bucket and in cache
|
||||
* e.g. for a path '/' returns '/index.html' which serves
|
||||
* the content of bucket/index.html
|
||||
* @param {Request} request incoming request
|
||||
*/
|
||||
declare const mapRequestToAsset: (request: Request, options?: Partial<Options>) => Request;
|
||||
/**
|
||||
* maps the path of incoming request to /index.html if it evaluates to
|
||||
* any HTML file.
|
||||
* @param {Request} request incoming request
|
||||
*/
|
||||
declare function serveSinglePageApp(request: Request, options?: Partial<Options>): Request;
|
||||
/**
|
||||
* takes the path of the incoming request, gathers the appropriate content from KV, and returns
|
||||
* the response
|
||||
*
|
||||
* @param {FetchEvent} event the fetch event of the triggered request
|
||||
* @param {{mapRequestToAsset: (string: Request) => Request, cacheControl: {bypassCache:boolean, edgeTTL: number, browserTTL:number}, ASSET_NAMESPACE: any, ASSET_MANIFEST:any}} [options] configurable options
|
||||
* @param {CacheControl} [options.cacheControl] determine how to cache on Cloudflare and the browser
|
||||
* @param {typeof(options.mapRequestToAsset)} [options.mapRequestToAsset] maps the path of incoming request to the request pathKey to look up
|
||||
* @param {Object | string} [options.ASSET_NAMESPACE] the binding to the namespace that script references
|
||||
* @param {any} [options.ASSET_MANIFEST] the map of the key to cache and store in KV
|
||||
* */
|
||||
declare type Evt = {
|
||||
request: Request;
|
||||
waitUntil: (promise: Promise<any>) => void;
|
||||
};
|
||||
declare const getAssetFromKV: (event: Evt, options?: Partial<Options>) => Promise<Response>;
|
||||
export { getAssetFromKV, mapRequestToAsset, serveSinglePageApp };
|
||||
export { Options, CacheControl, MethodNotAllowedError, NotFoundError, InternalError };
|
267
node_modules/@cloudflare/kv-asset-handler/dist/index.js
generated
vendored
Normal file
267
node_modules/@cloudflare/kv-asset-handler/dist/index.js
generated
vendored
Normal file
|
@ -0,0 +1,267 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.InternalError = exports.NotFoundError = exports.MethodNotAllowedError = exports.serveSinglePageApp = exports.mapRequestToAsset = exports.getAssetFromKV = void 0;
|
||||
const mime = require("mime");
|
||||
const types_1 = require("./types");
|
||||
Object.defineProperty(exports, "MethodNotAllowedError", { enumerable: true, get: function () { return types_1.MethodNotAllowedError; } });
|
||||
Object.defineProperty(exports, "NotFoundError", { enumerable: true, get: function () { return types_1.NotFoundError; } });
|
||||
Object.defineProperty(exports, "InternalError", { enumerable: true, get: function () { return types_1.InternalError; } });
|
||||
const defaultCacheControl = {
|
||||
browserTTL: null,
|
||||
edgeTTL: 2 * 60 * 60 * 24,
|
||||
bypassCache: false, // do not bypass Cloudflare's cache
|
||||
};
|
||||
const parseStringAsObject = (maybeString) => typeof maybeString === 'string' ? JSON.parse(maybeString) : maybeString;
|
||||
const getAssetFromKVDefaultOptions = {
|
||||
ASSET_NAMESPACE: typeof __STATIC_CONTENT !== 'undefined' ? __STATIC_CONTENT : undefined,
|
||||
ASSET_MANIFEST: typeof __STATIC_CONTENT_MANIFEST !== 'undefined'
|
||||
? parseStringAsObject(__STATIC_CONTENT_MANIFEST)
|
||||
: {},
|
||||
cacheControl: defaultCacheControl,
|
||||
defaultMimeType: 'text/plain',
|
||||
defaultDocument: 'index.html',
|
||||
pathIsEncoded: false,
|
||||
};
|
||||
function assignOptions(options) {
|
||||
// Assign any missing options passed in to the default
|
||||
// options.mapRequestToAsset is handled manually later
|
||||
return Object.assign({}, getAssetFromKVDefaultOptions, options);
|
||||
}
|
||||
/**
|
||||
* maps the path of incoming request to the request pathKey to look up
|
||||
* in bucket and in cache
|
||||
* e.g. for a path '/' returns '/index.html' which serves
|
||||
* the content of bucket/index.html
|
||||
* @param {Request} request incoming request
|
||||
*/
|
||||
const mapRequestToAsset = (request, options) => {
|
||||
options = assignOptions(options);
|
||||
const parsedUrl = new URL(request.url);
|
||||
let pathname = parsedUrl.pathname;
|
||||
if (pathname.endsWith('/')) {
|
||||
// If path looks like a directory append options.defaultDocument
|
||||
// e.g. If path is /about/ -> /about/index.html
|
||||
pathname = pathname.concat(options.defaultDocument);
|
||||
}
|
||||
else if (!mime.getType(pathname)) {
|
||||
// If path doesn't look like valid content
|
||||
// e.g. /about.me -> /about.me/index.html
|
||||
pathname = pathname.concat('/' + options.defaultDocument);
|
||||
}
|
||||
parsedUrl.pathname = pathname;
|
||||
return new Request(parsedUrl.toString(), request);
|
||||
};
|
||||
exports.mapRequestToAsset = mapRequestToAsset;
|
||||
/**
|
||||
* maps the path of incoming request to /index.html if it evaluates to
|
||||
* any HTML file.
|
||||
* @param {Request} request incoming request
|
||||
*/
|
||||
function serveSinglePageApp(request, options) {
|
||||
options = assignOptions(options);
|
||||
// First apply the default handler, which already has logic to detect
|
||||
// paths that should map to HTML files.
|
||||
request = mapRequestToAsset(request, options);
|
||||
const parsedUrl = new URL(request.url);
|
||||
// Detect if the default handler decided to map to
|
||||
// a HTML file in some specific directory.
|
||||
if (parsedUrl.pathname.endsWith('.html')) {
|
||||
// If expected HTML file was missing, just return the root index.html (or options.defaultDocument)
|
||||
return new Request(`${parsedUrl.origin}/${options.defaultDocument}`, request);
|
||||
}
|
||||
else {
|
||||
// The default handler decided this is not an HTML page. It's probably
|
||||
// an image, CSS, or JS file. Leave it as-is.
|
||||
return request;
|
||||
}
|
||||
}
|
||||
exports.serveSinglePageApp = serveSinglePageApp;
|
||||
const getAssetFromKV = async (event, options) => {
|
||||
options = assignOptions(options);
|
||||
const request = event.request;
|
||||
const ASSET_NAMESPACE = options.ASSET_NAMESPACE;
|
||||
const ASSET_MANIFEST = parseStringAsObject(options.ASSET_MANIFEST);
|
||||
if (typeof ASSET_NAMESPACE === 'undefined') {
|
||||
throw new types_1.InternalError(`there is no KV namespace bound to the script`);
|
||||
}
|
||||
const rawPathKey = new URL(request.url).pathname.replace(/^\/+/, ''); // strip any preceding /'s
|
||||
let pathIsEncoded = options.pathIsEncoded;
|
||||
let requestKey;
|
||||
// if options.mapRequestToAsset is explicitly passed in, always use it and assume user has own intentions
|
||||
// otherwise handle request as normal, with default mapRequestToAsset below
|
||||
if (options.mapRequestToAsset) {
|
||||
requestKey = options.mapRequestToAsset(request);
|
||||
}
|
||||
else if (ASSET_MANIFEST[rawPathKey]) {
|
||||
requestKey = request;
|
||||
}
|
||||
else if (ASSET_MANIFEST[decodeURIComponent(rawPathKey)]) {
|
||||
pathIsEncoded = true;
|
||||
requestKey = request;
|
||||
}
|
||||
else {
|
||||
const mappedRequest = mapRequestToAsset(request);
|
||||
const mappedRawPathKey = new URL(mappedRequest.url).pathname.replace(/^\/+/, '');
|
||||
if (ASSET_MANIFEST[decodeURIComponent(mappedRawPathKey)]) {
|
||||
pathIsEncoded = true;
|
||||
requestKey = mappedRequest;
|
||||
}
|
||||
else {
|
||||
// use default mapRequestToAsset
|
||||
requestKey = mapRequestToAsset(request, options);
|
||||
}
|
||||
}
|
||||
const SUPPORTED_METHODS = ['GET', 'HEAD'];
|
||||
if (!SUPPORTED_METHODS.includes(requestKey.method)) {
|
||||
throw new types_1.MethodNotAllowedError(`${requestKey.method} is not a valid request method`);
|
||||
}
|
||||
const parsedUrl = new URL(requestKey.url);
|
||||
const pathname = pathIsEncoded ? decodeURIComponent(parsedUrl.pathname) : parsedUrl.pathname; // decode percentage encoded path only when necessary
|
||||
// pathKey is the file path to look up in the manifest
|
||||
let pathKey = pathname.replace(/^\/+/, ''); // remove prepended /
|
||||
// @ts-ignore
|
||||
const cache = caches.default;
|
||||
let mimeType = mime.getType(pathKey) || options.defaultMimeType;
|
||||
if (mimeType.startsWith('text') || mimeType === 'application/javascript') {
|
||||
mimeType += '; charset=utf-8';
|
||||
}
|
||||
let shouldEdgeCache = false; // false if storing in KV by raw file path i.e. no hash
|
||||
// check manifest for map from file path to hash
|
||||
if (typeof ASSET_MANIFEST !== 'undefined') {
|
||||
if (ASSET_MANIFEST[pathKey]) {
|
||||
pathKey = ASSET_MANIFEST[pathKey];
|
||||
// if path key is in asset manifest, we can assume it contains a content hash and can be cached
|
||||
shouldEdgeCache = true;
|
||||
}
|
||||
}
|
||||
// TODO this excludes search params from cache, investigate ideal behavior
|
||||
let cacheKey = new Request(`${parsedUrl.origin}/${pathKey}`, request);
|
||||
// if argument passed in for cacheControl is a function then
|
||||
// evaluate that function. otherwise return the Object passed in
|
||||
// or default Object
|
||||
const evalCacheOpts = (() => {
|
||||
switch (typeof options.cacheControl) {
|
||||
case 'function':
|
||||
return options.cacheControl(request);
|
||||
case 'object':
|
||||
return options.cacheControl;
|
||||
default:
|
||||
return defaultCacheControl;
|
||||
}
|
||||
})();
|
||||
// formats the etag depending on the response context. if the entityId
|
||||
// is invalid, returns an empty string (instead of null) to prevent the
|
||||
// the potentially disastrous scenario where the value of the Etag resp
|
||||
// header is "null". Could be modified in future to base64 encode etc
|
||||
const formatETag = (entityId = pathKey, validatorType = 'strong') => {
|
||||
if (!entityId) {
|
||||
return '';
|
||||
}
|
||||
switch (validatorType) {
|
||||
case 'weak':
|
||||
if (!entityId.startsWith('W/')) {
|
||||
return `W/${entityId}`;
|
||||
}
|
||||
return entityId;
|
||||
case 'strong':
|
||||
if (entityId.startsWith(`W/"`)) {
|
||||
entityId = entityId.replace('W/', '');
|
||||
}
|
||||
if (!entityId.endsWith(`"`)) {
|
||||
entityId = `"${entityId}"`;
|
||||
}
|
||||
return entityId;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
};
|
||||
options.cacheControl = Object.assign({}, defaultCacheControl, evalCacheOpts);
|
||||
// override shouldEdgeCache if options say to bypassCache
|
||||
if (options.cacheControl.bypassCache ||
|
||||
options.cacheControl.edgeTTL === null ||
|
||||
request.method == 'HEAD') {
|
||||
shouldEdgeCache = false;
|
||||
}
|
||||
// only set max-age if explicitly passed in a number as an arg
|
||||
const shouldSetBrowserCache = typeof options.cacheControl.browserTTL === 'number';
|
||||
let response = null;
|
||||
if (shouldEdgeCache) {
|
||||
response = await cache.match(cacheKey);
|
||||
}
|
||||
if (response) {
|
||||
if (response.status > 300 && response.status < 400) {
|
||||
if (response.body && 'cancel' in Object.getPrototypeOf(response.body)) {
|
||||
// Body exists and environment supports readable streams
|
||||
response.body.cancel();
|
||||
}
|
||||
else {
|
||||
// Environment doesnt support readable streams, or null repsonse body. Nothing to do
|
||||
}
|
||||
response = new Response(null, response);
|
||||
}
|
||||
else {
|
||||
// fixes #165
|
||||
let opts = {
|
||||
headers: new Headers(response.headers),
|
||||
status: 0,
|
||||
statusText: '',
|
||||
};
|
||||
opts.headers.set('cf-cache-status', 'HIT');
|
||||
if (response.status) {
|
||||
opts.status = response.status;
|
||||
opts.statusText = response.statusText;
|
||||
}
|
||||
else if (opts.headers.has('Content-Range')) {
|
||||
opts.status = 206;
|
||||
opts.statusText = 'Partial Content';
|
||||
}
|
||||
else {
|
||||
opts.status = 200;
|
||||
opts.statusText = 'OK';
|
||||
}
|
||||
response = new Response(response.body, opts);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const body = await ASSET_NAMESPACE.get(pathKey, 'arrayBuffer');
|
||||
if (body === null) {
|
||||
throw new types_1.NotFoundError(`could not find ${pathKey} in your content namespace`);
|
||||
}
|
||||
response = new Response(body);
|
||||
if (shouldEdgeCache) {
|
||||
response.headers.set('Accept-Ranges', 'bytes');
|
||||
response.headers.set('Content-Length', body.length);
|
||||
// set etag before cache insertion
|
||||
if (!response.headers.has('etag')) {
|
||||
response.headers.set('etag', formatETag(pathKey, 'strong'));
|
||||
}
|
||||
// determine Cloudflare cache behavior
|
||||
response.headers.set('Cache-Control', `max-age=${options.cacheControl.edgeTTL}`);
|
||||
event.waitUntil(cache.put(cacheKey, response.clone()));
|
||||
response.headers.set('CF-Cache-Status', 'MISS');
|
||||
}
|
||||
}
|
||||
response.headers.set('Content-Type', mimeType);
|
||||
if (response.status === 304) {
|
||||
let etag = formatETag(response.headers.get('etag'), 'strong');
|
||||
let ifNoneMatch = cacheKey.headers.get('if-none-match');
|
||||
let proxyCacheStatus = response.headers.get('CF-Cache-Status');
|
||||
if (etag) {
|
||||
if (ifNoneMatch && ifNoneMatch === etag && proxyCacheStatus === 'MISS') {
|
||||
response.headers.set('CF-Cache-Status', 'EXPIRED');
|
||||
}
|
||||
else {
|
||||
response.headers.set('CF-Cache-Status', 'REVALIDATED');
|
||||
}
|
||||
response.headers.set('etag', formatETag(etag, 'weak'));
|
||||
}
|
||||
}
|
||||
if (shouldSetBrowserCache) {
|
||||
response.headers.set('Cache-Control', `max-age=${options.cacheControl.browserTTL}`);
|
||||
}
|
||||
else {
|
||||
response.headers.delete('Cache-Control');
|
||||
}
|
||||
return response;
|
||||
};
|
||||
exports.getAssetFromKV = getAssetFromKV;
|
14
node_modules/@cloudflare/kv-asset-handler/dist/mocks.d.ts
generated
vendored
Normal file
14
node_modules/@cloudflare/kv-asset-handler/dist/mocks.d.ts
generated
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
export declare const getEvent: (request: Request) => any;
|
||||
export declare const mockKV: (store: any) => {
|
||||
get: (path: string) => any;
|
||||
};
|
||||
export declare const mockManifest: () => string;
|
||||
export declare const mockCaches: () => {
|
||||
default: {
|
||||
match(key: any): Promise<any>;
|
||||
put(key: any, val: Response): Promise<void>;
|
||||
};
|
||||
};
|
||||
export declare function mockRequestScope(): void;
|
||||
export declare function mockGlobalScope(): void;
|
||||
export declare const sleep: (milliseconds: number) => Promise<unknown>;
|
146
node_modules/@cloudflare/kv-asset-handler/dist/mocks.js
generated
vendored
Normal file
146
node_modules/@cloudflare/kv-asset-handler/dist/mocks.js
generated
vendored
Normal file
|
@ -0,0 +1,146 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.sleep = exports.mockGlobalScope = exports.mockRequestScope = exports.mockCaches = exports.mockManifest = exports.mockKV = exports.getEvent = void 0;
|
||||
const makeServiceWorkerEnv = require('service-worker-mock');
|
||||
const HASH = '123HASHBROWN';
|
||||
const getEvent = (request) => {
|
||||
const waitUntil = async (callback) => {
|
||||
await callback;
|
||||
};
|
||||
return {
|
||||
request,
|
||||
waitUntil,
|
||||
};
|
||||
};
|
||||
exports.getEvent = getEvent;
|
||||
const store = {
|
||||
'key1.123HASHBROWN.txt': 'val1',
|
||||
'key1.123HASHBROWN.png': 'val1',
|
||||
'index.123HASHBROWN.html': 'index.html',
|
||||
'cache.123HASHBROWN.html': 'cache me if you can',
|
||||
'测试.123HASHBROWN.html': 'My filename is non-ascii',
|
||||
'%not-really-percent-encoded.123HASHBROWN.html': 'browser percent encoded',
|
||||
'%2F.123HASHBROWN.html': 'user percent encoded',
|
||||
'你好.123HASHBROWN.html': 'I shouldnt be served',
|
||||
'%E4%BD%A0%E5%A5%BD.123HASHBROWN.html': 'Im important',
|
||||
'nohash.txt': 'no hash but still got some result',
|
||||
'sub/blah.123HASHBROWN.png': 'picturedis',
|
||||
'sub/index.123HASHBROWN.html': 'picturedis',
|
||||
'client.123HASHBROWN': 'important file',
|
||||
'client.123HASHBROWN/index.html': 'Im here but serve my big bro above',
|
||||
'image.123HASHBROWN.png': 'imagepng',
|
||||
'image.123HASHBROWN.webp': 'imagewebp',
|
||||
'你好/index.123HASHBROWN.html': 'My path is non-ascii',
|
||||
};
|
||||
const mockKV = (store) => {
|
||||
return {
|
||||
get: (path) => store[path] || null,
|
||||
};
|
||||
};
|
||||
exports.mockKV = mockKV;
|
||||
const mockManifest = () => {
|
||||
return JSON.stringify({
|
||||
'key1.txt': `key1.${HASH}.txt`,
|
||||
'key1.png': `key1.${HASH}.png`,
|
||||
'cache.html': `cache.${HASH}.html`,
|
||||
'测试.html': `测试.${HASH}.html`,
|
||||
'你好.html': `你好.${HASH}.html`,
|
||||
'%not-really-percent-encoded.html': `%not-really-percent-encoded.${HASH}.html`,
|
||||
'%2F.html': `%2F.${HASH}.html`,
|
||||
'%E4%BD%A0%E5%A5%BD.html': `%E4%BD%A0%E5%A5%BD.${HASH}.html`,
|
||||
'index.html': `index.${HASH}.html`,
|
||||
'sub/blah.png': `sub/blah.${HASH}.png`,
|
||||
'sub/index.html': `sub/index.${HASH}.html`,
|
||||
client: `client.${HASH}`,
|
||||
'client/index.html': `client.${HASH}`,
|
||||
'image.png': `image.${HASH}.png`,
|
||||
'image.webp': `image.${HASH}.webp`,
|
||||
'你好/index.html': `你好/index.${HASH}.html`,
|
||||
});
|
||||
};
|
||||
exports.mockManifest = mockManifest;
|
||||
let cacheStore = new Map();
|
||||
const mockCaches = () => {
|
||||
return {
|
||||
default: {
|
||||
async match(key) {
|
||||
let cacheKey = {
|
||||
url: key.url,
|
||||
headers: {},
|
||||
};
|
||||
let response;
|
||||
if (key.headers.has('if-none-match')) {
|
||||
let makeStrongEtag = key.headers.get('if-none-match').replace('W/', '');
|
||||
Reflect.set(cacheKey.headers, 'etag', makeStrongEtag);
|
||||
response = cacheStore.get(JSON.stringify(cacheKey));
|
||||
}
|
||||
else {
|
||||
// if client doesn't send if-none-match, we need to iterate through these keys
|
||||
// and just test the URL
|
||||
const activeCacheKeys = Array.from(cacheStore.keys());
|
||||
for (const cacheStoreKey of activeCacheKeys) {
|
||||
if (JSON.parse(cacheStoreKey).url === key.url) {
|
||||
response = cacheStore.get(cacheStoreKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: write test to accomodate for rare scenarios with where range requests accomodate etags
|
||||
if (response && !key.headers.has('if-none-match')) {
|
||||
// this appears overly verbose, but is necessary to document edge cache behavior
|
||||
// The Range request header triggers the response header Content-Range ...
|
||||
const range = key.headers.get('range');
|
||||
if (range) {
|
||||
response.headers.set('content-range', `bytes ${range.split('=').pop()}/${response.headers.get('content-length')}`);
|
||||
}
|
||||
// ... which we are using in this repository to set status 206
|
||||
if (response.headers.has('content-range')) {
|
||||
response.status = 206;
|
||||
}
|
||||
else {
|
||||
response.status = 200;
|
||||
}
|
||||
let etag = response.headers.get('etag');
|
||||
if (etag && !etag.includes('W/')) {
|
||||
response.headers.set('etag', `W/${etag}`);
|
||||
}
|
||||
}
|
||||
return response;
|
||||
},
|
||||
async put(key, val) {
|
||||
let headers = new Headers(val.headers);
|
||||
let url = new URL(key.url);
|
||||
let resWithBody = new Response(val.body, { headers, status: 200 });
|
||||
let resNoBody = new Response(null, { headers, status: 304 });
|
||||
let cacheKey = {
|
||||
url: key.url,
|
||||
headers: {
|
||||
etag: `"${url.pathname.replace('/', '')}"`,
|
||||
},
|
||||
};
|
||||
cacheStore.set(JSON.stringify(cacheKey), resNoBody);
|
||||
cacheKey.headers = {};
|
||||
cacheStore.set(JSON.stringify(cacheKey), resWithBody);
|
||||
return;
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
exports.mockCaches = mockCaches;
|
||||
// mocks functionality used inside worker request
|
||||
function mockRequestScope() {
|
||||
Object.assign(global, makeServiceWorkerEnv());
|
||||
Object.assign(global, { __STATIC_CONTENT_MANIFEST: (0, exports.mockManifest)() });
|
||||
Object.assign(global, { __STATIC_CONTENT: (0, exports.mockKV)(store) });
|
||||
Object.assign(global, { caches: (0, exports.mockCaches)() });
|
||||
}
|
||||
exports.mockRequestScope = mockRequestScope;
|
||||
// mocks functionality used on global isolate scope. such as the KV namespace bind
|
||||
function mockGlobalScope() {
|
||||
Object.assign(global, { __STATIC_CONTENT_MANIFEST: (0, exports.mockManifest)() });
|
||||
Object.assign(global, { __STATIC_CONTENT: (0, exports.mockKV)(store) });
|
||||
}
|
||||
exports.mockGlobalScope = mockGlobalScope;
|
||||
const sleep = (milliseconds) => {
|
||||
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
||||
};
|
||||
exports.sleep = sleep;
|
1
node_modules/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV-optional.d.ts
generated
vendored
Normal file
1
node_modules/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV-optional.d.ts
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
export {};
|
22
node_modules/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV-optional.js
generated
vendored
Normal file
22
node_modules/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV-optional.js
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const ava_1 = require("ava");
|
||||
const mocks_1 = require("../mocks");
|
||||
(0, mocks_1.mockGlobalScope)();
|
||||
// manually reset manifest global, to test optional behaviour
|
||||
Object.assign(global, { __STATIC_CONTENT_MANIFEST: undefined });
|
||||
const index_1 = require("../index");
|
||||
(0, ava_1.default)('getAssetFromKV return correct val from KV without manifest', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
// manually reset manifest global, to test optional behaviour
|
||||
Object.assign(global, { __STATIC_CONTENT_MANIFEST: undefined });
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://blah.com/key1.123HASHBROWN.txt'));
|
||||
const res = await (0, index_1.getAssetFromKV)(event);
|
||||
if (res) {
|
||||
t.is(await res.text(), 'val1');
|
||||
t.true(res.headers.get('content-type').includes('text'));
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
1
node_modules/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts
generated
vendored
Normal file
1
node_modules/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
export {};
|
446
node_modules/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js
generated
vendored
Normal file
446
node_modules/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js
generated
vendored
Normal file
|
@ -0,0 +1,446 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const ava_1 = require("ava");
|
||||
const mocks_1 = require("../mocks");
|
||||
(0, mocks_1.mockGlobalScope)();
|
||||
const index_1 = require("../index");
|
||||
(0, ava_1.default)('getAssetFromKV return correct val from KV and default caching', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://blah.com/key1.txt'));
|
||||
const res = await (0, index_1.getAssetFromKV)(event);
|
||||
if (res) {
|
||||
t.is(res.headers.get('cache-control'), null);
|
||||
t.is(res.headers.get('cf-cache-status'), 'MISS');
|
||||
t.is(await res.text(), 'val1');
|
||||
t.true(res.headers.get('content-type').includes('text'));
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV evaluated the file matching the extensionless path first /client/ -> client', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request(`https://foo.com/client/`));
|
||||
const res = await (0, index_1.getAssetFromKV)(event);
|
||||
t.is(await res.text(), 'important file');
|
||||
t.true(res.headers.get('content-type').includes('text'));
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV evaluated the file matching the extensionless path first /client -> client', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request(`https://foo.com/client`));
|
||||
const res = await (0, index_1.getAssetFromKV)(event);
|
||||
t.is(await res.text(), 'important file');
|
||||
t.true(res.headers.get('content-type').includes('text'));
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV if not in asset manifest still returns nohash.txt', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://blah.com/nohash.txt'));
|
||||
const res = await (0, index_1.getAssetFromKV)(event);
|
||||
if (res) {
|
||||
t.is(await res.text(), 'no hash but still got some result');
|
||||
t.true(res.headers.get('content-type').includes('text'));
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV if no asset manifest /client -> client fails', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request(`https://foo.com/client`));
|
||||
const error = await t.throwsAsync((0, index_1.getAssetFromKV)(event, { ASSET_MANIFEST: {} }));
|
||||
t.is(error.status, 404);
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV if sub/ -> sub/index.html served', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request(`https://foo.com/sub`));
|
||||
const res = await (0, index_1.getAssetFromKV)(event);
|
||||
if (res) {
|
||||
t.is(await res.text(), 'picturedis');
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV gets index.html by default for / requests', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://blah.com/'));
|
||||
const res = await (0, index_1.getAssetFromKV)(event);
|
||||
if (res) {
|
||||
t.is(await res.text(), 'index.html');
|
||||
t.true(res.headers.get('content-type').includes('html'));
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV non ASCII path support', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://blah.com/测试.html'));
|
||||
const res = await (0, index_1.getAssetFromKV)(event);
|
||||
if (res) {
|
||||
t.is(await res.text(), 'My filename is non-ascii');
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV supports browser percent encoded URLs', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://example.com/%not-really-percent-encoded.html'));
|
||||
const res = await (0, index_1.getAssetFromKV)(event);
|
||||
if (res) {
|
||||
t.is(await res.text(), 'browser percent encoded');
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV supports user percent encoded URLs', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://blah.com/%2F.html'));
|
||||
const res = await (0, index_1.getAssetFromKV)(event);
|
||||
if (res) {
|
||||
t.is(await res.text(), 'user percent encoded');
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV only decode URL when necessary', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event1 = (0, mocks_1.getEvent)(new Request('https://blah.com/%E4%BD%A0%E5%A5%BD.html'));
|
||||
const event2 = (0, mocks_1.getEvent)(new Request('https://blah.com/你好.html'));
|
||||
const res1 = await (0, index_1.getAssetFromKV)(event1);
|
||||
const res2 = await (0, index_1.getAssetFromKV)(event2);
|
||||
if (res1 && res2) {
|
||||
t.is(await res1.text(), 'Im important');
|
||||
t.is(await res2.text(), 'Im important');
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV Support for user decode url path', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event1 = (0, mocks_1.getEvent)(new Request('https://blah.com/%E4%BD%A0%E5%A5%BD/'));
|
||||
const event2 = (0, mocks_1.getEvent)(new Request('https://blah.com/你好/'));
|
||||
const res1 = await (0, index_1.getAssetFromKV)(event1);
|
||||
const res2 = await (0, index_1.getAssetFromKV)(event2);
|
||||
if (res1 && res2) {
|
||||
t.is(await res1.text(), 'My path is non-ascii');
|
||||
t.is(await res2.text(), 'My path is non-ascii');
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV custom key modifier', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://blah.com/docs/sub/blah.png'));
|
||||
const customRequestMapper = (request) => {
|
||||
let defaultModifiedRequest = (0, index_1.mapRequestToAsset)(request);
|
||||
let url = new URL(defaultModifiedRequest.url);
|
||||
url.pathname = url.pathname.replace('/docs', '');
|
||||
return new Request(url.toString(), request);
|
||||
};
|
||||
const res = await (0, index_1.getAssetFromKV)(event, { mapRequestToAsset: customRequestMapper });
|
||||
if (res) {
|
||||
t.is(await res.text(), 'picturedis');
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV request override with existing manifest file', async (t) => {
|
||||
// see https://github.com/cloudflare/kv-asset-handler/pull/159 for more info
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://blah.com/image.png')); // real file in manifest
|
||||
const customRequestMapper = (request) => {
|
||||
let defaultModifiedRequest = (0, index_1.mapRequestToAsset)(request);
|
||||
let url = new URL(defaultModifiedRequest.url);
|
||||
url.pathname = '/image.webp'; // other different file in manifest
|
||||
return new Request(url.toString(), request);
|
||||
};
|
||||
const res = await (0, index_1.getAssetFromKV)(event, { mapRequestToAsset: customRequestMapper });
|
||||
if (res) {
|
||||
t.is(await res.text(), 'imagewebp');
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV when setting browser caching', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://blah.com/'));
|
||||
const res = await (0, index_1.getAssetFromKV)(event, { cacheControl: { browserTTL: 22 } });
|
||||
if (res) {
|
||||
t.is(res.headers.get('cache-control'), 'max-age=22');
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV when setting custom cache setting', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event1 = (0, mocks_1.getEvent)(new Request('https://blah.com/'));
|
||||
const event2 = (0, mocks_1.getEvent)(new Request('https://blah.com/key1.png?blah=34'));
|
||||
const cacheOnlyPngs = (req) => {
|
||||
if (new URL(req.url).pathname.endsWith('.png'))
|
||||
return {
|
||||
browserTTL: 720,
|
||||
edgeTTL: 720,
|
||||
};
|
||||
else
|
||||
return {
|
||||
bypassCache: true,
|
||||
};
|
||||
};
|
||||
const res1 = await (0, index_1.getAssetFromKV)(event1, { cacheControl: cacheOnlyPngs });
|
||||
const res2 = await (0, index_1.getAssetFromKV)(event2, { cacheControl: cacheOnlyPngs });
|
||||
if (res1 && res2) {
|
||||
t.is(res1.headers.get('cache-control'), null);
|
||||
t.true(res2.headers.get('content-type').includes('png'));
|
||||
t.is(res2.headers.get('cache-control'), 'max-age=720');
|
||||
t.is(res2.headers.get('cf-cache-status'), 'MISS');
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV caches on two sequential requests', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const resourceKey = 'cache.html';
|
||||
const resourceVersion = JSON.parse((0, mocks_1.mockManifest)())[resourceKey];
|
||||
const event1 = (0, mocks_1.getEvent)(new Request(`https://blah.com/${resourceKey}`));
|
||||
const event2 = (0, mocks_1.getEvent)(new Request(`https://blah.com/${resourceKey}`, {
|
||||
headers: {
|
||||
'if-none-match': `"${resourceVersion}"`,
|
||||
},
|
||||
}));
|
||||
const res1 = await (0, index_1.getAssetFromKV)(event1, { cacheControl: { edgeTTL: 720, browserTTL: 720 } });
|
||||
await (0, mocks_1.sleep)(1);
|
||||
const res2 = await (0, index_1.getAssetFromKV)(event2);
|
||||
if (res1 && res2) {
|
||||
t.is(res1.headers.get('cf-cache-status'), 'MISS');
|
||||
t.is(res1.headers.get('cache-control'), 'max-age=720');
|
||||
t.is(res2.headers.get('cf-cache-status'), 'REVALIDATED');
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV does not store max-age on two sequential requests', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const resourceKey = 'cache.html';
|
||||
const resourceVersion = JSON.parse((0, mocks_1.mockManifest)())[resourceKey];
|
||||
const event1 = (0, mocks_1.getEvent)(new Request(`https://blah.com/${resourceKey}`));
|
||||
const event2 = (0, mocks_1.getEvent)(new Request(`https://blah.com/${resourceKey}`, {
|
||||
headers: {
|
||||
'if-none-match': `"${resourceVersion}"`,
|
||||
},
|
||||
}));
|
||||
const res1 = await (0, index_1.getAssetFromKV)(event1, { cacheControl: { edgeTTL: 720 } });
|
||||
await (0, mocks_1.sleep)(100);
|
||||
const res2 = await (0, index_1.getAssetFromKV)(event2);
|
||||
if (res1 && res2) {
|
||||
t.is(res1.headers.get('cf-cache-status'), 'MISS');
|
||||
t.is(res1.headers.get('cache-control'), null);
|
||||
t.is(res2.headers.get('cf-cache-status'), 'REVALIDATED');
|
||||
t.is(res2.headers.get('cache-control'), null);
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV does not cache on Cloudflare when bypass cache set', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://blah.com/'));
|
||||
const res = await (0, index_1.getAssetFromKV)(event, { cacheControl: { bypassCache: true } });
|
||||
if (res) {
|
||||
t.is(res.headers.get('cache-control'), null);
|
||||
t.is(res.headers.get('cf-cache-status'), null);
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV with no trailing slash on root', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://blah.com'));
|
||||
const res = await (0, index_1.getAssetFromKV)(event);
|
||||
if (res) {
|
||||
t.is(await res.text(), 'index.html');
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV with no trailing slash on a subdirectory', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://blah.com/sub/blah.png'));
|
||||
const res = await (0, index_1.getAssetFromKV)(event);
|
||||
if (res) {
|
||||
t.is(await res.text(), 'picturedis');
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV no result throws an error', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://blah.com/random'));
|
||||
const error = await t.throwsAsync((0, index_1.getAssetFromKV)(event));
|
||||
t.is(error.status, 404);
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV TTls set to null should not cache on browser or edge', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://blah.com/'));
|
||||
const res1 = await (0, index_1.getAssetFromKV)(event, { cacheControl: { browserTTL: null, edgeTTL: null } });
|
||||
await (0, mocks_1.sleep)(100);
|
||||
const res2 = await (0, index_1.getAssetFromKV)(event, { cacheControl: { browserTTL: null, edgeTTL: null } });
|
||||
if (res1 && res2) {
|
||||
t.is(res1.headers.get('cf-cache-status'), null);
|
||||
t.is(res1.headers.get('cache-control'), null);
|
||||
t.is(res2.headers.get('cf-cache-status'), null);
|
||||
t.is(res2.headers.get('cache-control'), null);
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV passing in a custom NAMESPACE serves correct asset', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
let CUSTOM_NAMESPACE = (0, mocks_1.mockKV)({
|
||||
'key1.123HASHBROWN.txt': 'val1',
|
||||
});
|
||||
Object.assign(global, { CUSTOM_NAMESPACE });
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://blah.com/'));
|
||||
const res = await (0, index_1.getAssetFromKV)(event);
|
||||
if (res) {
|
||||
t.is(await res.text(), 'index.html');
|
||||
t.true(res.headers.get('content-type').includes('html'));
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV when custom namespace without the asset should fail', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
let CUSTOM_NAMESPACE = (0, mocks_1.mockKV)({
|
||||
'key5.123HASHBROWN.txt': 'customvalu',
|
||||
});
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://blah.com'));
|
||||
const error = await t.throwsAsync((0, index_1.getAssetFromKV)(event, { ASSET_NAMESPACE: CUSTOM_NAMESPACE }));
|
||||
t.is(error.status, 404);
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV when namespace not bound fails', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
var MY_CUSTOM_NAMESPACE = undefined;
|
||||
Object.assign(global, { MY_CUSTOM_NAMESPACE });
|
||||
const event = (0, mocks_1.getEvent)(new Request('https://blah.com/'));
|
||||
const error = await t.throwsAsync((0, index_1.getAssetFromKV)(event, { ASSET_NAMESPACE: MY_CUSTOM_NAMESPACE }));
|
||||
t.is(error.status, 500);
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV when if-none-match === active resource version, should revalidate', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const resourceKey = 'key1.png';
|
||||
const resourceVersion = JSON.parse((0, mocks_1.mockManifest)())[resourceKey];
|
||||
const event1 = (0, mocks_1.getEvent)(new Request(`https://blah.com/${resourceKey}`));
|
||||
const event2 = (0, mocks_1.getEvent)(new Request(`https://blah.com/${resourceKey}`, {
|
||||
headers: {
|
||||
'if-none-match': `W/"${resourceVersion}"`,
|
||||
},
|
||||
}));
|
||||
const res1 = await (0, index_1.getAssetFromKV)(event1, { cacheControl: { edgeTTL: 720 } });
|
||||
await (0, mocks_1.sleep)(100);
|
||||
const res2 = await (0, index_1.getAssetFromKV)(event2);
|
||||
if (res1 && res2) {
|
||||
t.is(res1.headers.get('cf-cache-status'), 'MISS');
|
||||
t.is(res2.headers.get('cf-cache-status'), 'REVALIDATED');
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV when if-none-match equals etag of stale resource then should bypass cache', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const resourceKey = 'key1.png';
|
||||
const resourceVersion = JSON.parse((0, mocks_1.mockManifest)())[resourceKey];
|
||||
const req1 = new Request(`https://blah.com/${resourceKey}`, {
|
||||
headers: {
|
||||
'if-none-match': `"${resourceVersion}"`,
|
||||
},
|
||||
});
|
||||
const req2 = new Request(`https://blah.com/${resourceKey}`, {
|
||||
headers: {
|
||||
'if-none-match': `"${resourceVersion}-another-version"`,
|
||||
},
|
||||
});
|
||||
const event = (0, mocks_1.getEvent)(req1);
|
||||
const event2 = (0, mocks_1.getEvent)(req2);
|
||||
const res1 = await (0, index_1.getAssetFromKV)(event, { cacheControl: { edgeTTL: 720 } });
|
||||
const res2 = await (0, index_1.getAssetFromKV)(event);
|
||||
const res3 = await (0, index_1.getAssetFromKV)(event2);
|
||||
if (res1 && res2 && res3) {
|
||||
t.is(res1.headers.get('cf-cache-status'), 'MISS');
|
||||
t.is(res2.headers.get('etag'), `W/${req1.headers.get('if-none-match')}`);
|
||||
t.is(res2.headers.get('cf-cache-status'), 'REVALIDATED');
|
||||
t.not(res3.headers.get('etag'), req2.headers.get('if-none-match'));
|
||||
t.is(res3.headers.get('cf-cache-status'), 'MISS');
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV when resource in cache, etag should be weakened before returned to eyeball', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
const resourceKey = 'key1.png';
|
||||
const resourceVersion = JSON.parse((0, mocks_1.mockManifest)())[resourceKey];
|
||||
const req1 = new Request(`https://blah.com/${resourceKey}`, {
|
||||
headers: {
|
||||
'if-none-match': `"${resourceVersion}"`,
|
||||
},
|
||||
});
|
||||
const event = (0, mocks_1.getEvent)(req1);
|
||||
const res1 = await (0, index_1.getAssetFromKV)(event, { cacheControl: { edgeTTL: 720 } });
|
||||
const res2 = await (0, index_1.getAssetFromKV)(event);
|
||||
if (res1 && res2) {
|
||||
t.is(res1.headers.get('cf-cache-status'), 'MISS');
|
||||
t.is(res2.headers.get('etag'), `W/${req1.headers.get('if-none-match')}`);
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV if-none-match not sent but resource in cache, should return cache hit 200 OK', async (t) => {
|
||||
const resourceKey = 'cache.html';
|
||||
const event = (0, mocks_1.getEvent)(new Request(`https://blah.com/${resourceKey}`));
|
||||
const res1 = await (0, index_1.getAssetFromKV)(event, { cacheControl: { edgeTTL: 720 } });
|
||||
await (0, mocks_1.sleep)(1);
|
||||
const res2 = await (0, index_1.getAssetFromKV)(event);
|
||||
if (res1 && res2) {
|
||||
t.is(res1.headers.get('cf-cache-status'), 'MISS');
|
||||
t.is(res1.headers.get('cache-control'), null);
|
||||
t.is(res2.status, 200);
|
||||
t.is(res2.headers.get('cf-cache-status'), 'HIT');
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
(0, ava_1.default)('getAssetFromKV if range request submitted and resource in cache, request fulfilled', async (t) => {
|
||||
const resourceKey = 'cache.html';
|
||||
const event1 = (0, mocks_1.getEvent)(new Request(`https://blah.com/${resourceKey}`));
|
||||
const event2 = (0, mocks_1.getEvent)(new Request(`https://blah.com/${resourceKey}`, { headers: { range: 'bytes=0-10' } }));
|
||||
const res1 = (0, index_1.getAssetFromKV)(event1, { cacheControl: { edgeTTL: 720 } });
|
||||
await res1;
|
||||
await (0, mocks_1.sleep)(2);
|
||||
const res2 = await (0, index_1.getAssetFromKV)(event2);
|
||||
if (res2.headers.has('content-range')) {
|
||||
t.is(res2.status, 206);
|
||||
}
|
||||
else {
|
||||
t.fail('Response was undefined');
|
||||
}
|
||||
});
|
||||
ava_1.default.todo('getAssetFromKV when body not empty, should invoke .cancel()');
|
1
node_modules/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts
generated
vendored
Normal file
1
node_modules/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
export {};
|
34
node_modules/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js
generated
vendored
Normal file
34
node_modules/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js
generated
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const ava_1 = require("ava");
|
||||
const mocks_1 = require("../mocks");
|
||||
(0, mocks_1.mockGlobalScope)();
|
||||
const index_1 = require("../index");
|
||||
(0, ava_1.default)('mapRequestToAsset() correctly changes /about -> /about/index.html', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
let path = '/about';
|
||||
let request = new Request(`https://foo.com${path}`);
|
||||
let newRequest = (0, index_1.mapRequestToAsset)(request);
|
||||
t.is(newRequest.url, request.url + '/index.html');
|
||||
});
|
||||
(0, ava_1.default)('mapRequestToAsset() correctly changes /about/ -> /about/index.html', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
let path = '/about/';
|
||||
let request = new Request(`https://foo.com${path}`);
|
||||
let newRequest = (0, index_1.mapRequestToAsset)(request);
|
||||
t.is(newRequest.url, request.url + 'index.html');
|
||||
});
|
||||
(0, ava_1.default)('mapRequestToAsset() correctly changes /about.me/ -> /about.me/index.html', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
let path = '/about.me/';
|
||||
let request = new Request(`https://foo.com${path}`);
|
||||
let newRequest = (0, index_1.mapRequestToAsset)(request);
|
||||
t.is(newRequest.url, request.url + 'index.html');
|
||||
});
|
||||
(0, ava_1.default)('mapRequestToAsset() correctly changes /about -> /about/default.html', async (t) => {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
let path = '/about';
|
||||
let request = new Request(`https://foo.com${path}`);
|
||||
let newRequest = (0, index_1.mapRequestToAsset)(request, { defaultDocument: 'default.html' });
|
||||
t.is(newRequest.url, request.url + '/default.html');
|
||||
});
|
1
node_modules/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts
generated
vendored
Normal file
1
node_modules/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
export {};
|
34
node_modules/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js
generated
vendored
Normal file
34
node_modules/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js
generated
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const ava_1 = require("ava");
|
||||
const mocks_1 = require("../mocks");
|
||||
(0, mocks_1.mockGlobalScope)();
|
||||
const index_1 = require("../index");
|
||||
function testRequest(path) {
|
||||
(0, mocks_1.mockRequestScope)();
|
||||
let url = new URL('https://example.com');
|
||||
url.pathname = path;
|
||||
let request = new Request(url.toString());
|
||||
return request;
|
||||
}
|
||||
(0, ava_1.default)('serveSinglePageApp returns root asset path when request path ends in .html', async (t) => {
|
||||
let path = '/foo/thing.html';
|
||||
let request = testRequest(path);
|
||||
let expected_request = testRequest('/index.html');
|
||||
let actual_request = (0, index_1.serveSinglePageApp)(request);
|
||||
t.deepEqual(expected_request, actual_request);
|
||||
});
|
||||
(0, ava_1.default)('serveSinglePageApp returns root asset path when request path does not have extension', async (t) => {
|
||||
let path = '/foo/thing';
|
||||
let request = testRequest(path);
|
||||
let expected_request = testRequest('/index.html');
|
||||
let actual_request = (0, index_1.serveSinglePageApp)(request);
|
||||
t.deepEqual(expected_request, actual_request);
|
||||
});
|
||||
(0, ava_1.default)('serveSinglePageApp returns requested asset when request path has non-html extension', async (t) => {
|
||||
let path = '/foo/thing.js';
|
||||
let request = testRequest(path);
|
||||
let expected_request = request;
|
||||
let actual_request = (0, index_1.serveSinglePageApp)(request);
|
||||
t.deepEqual(expected_request, actual_request);
|
||||
});
|
28
node_modules/@cloudflare/kv-asset-handler/dist/types.d.ts
generated
vendored
Normal file
28
node_modules/@cloudflare/kv-asset-handler/dist/types.d.ts
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
export declare type CacheControl = {
|
||||
browserTTL: number;
|
||||
edgeTTL: number;
|
||||
bypassCache: boolean;
|
||||
};
|
||||
export declare type AssetManifestType = Record<string, string>;
|
||||
export declare type Options = {
|
||||
cacheControl: ((req: Request) => Partial<CacheControl>) | Partial<CacheControl>;
|
||||
ASSET_NAMESPACE: any;
|
||||
ASSET_MANIFEST: AssetManifestType | string;
|
||||
mapRequestToAsset?: (req: Request, options?: Partial<Options>) => Request;
|
||||
defaultMimeType: string;
|
||||
defaultDocument: string;
|
||||
pathIsEncoded: boolean;
|
||||
};
|
||||
export declare class KVError extends Error {
|
||||
constructor(message?: string, status?: number);
|
||||
status: number;
|
||||
}
|
||||
export declare class MethodNotAllowedError extends KVError {
|
||||
constructor(message?: string, status?: number);
|
||||
}
|
||||
export declare class NotFoundError extends KVError {
|
||||
constructor(message?: string, status?: number);
|
||||
}
|
||||
export declare class InternalError extends KVError {
|
||||
constructor(message?: string, status?: number);
|
||||
}
|
31
node_modules/@cloudflare/kv-asset-handler/dist/types.js
generated
vendored
Normal file
31
node_modules/@cloudflare/kv-asset-handler/dist/types.js
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.InternalError = exports.NotFoundError = exports.MethodNotAllowedError = exports.KVError = void 0;
|
||||
class KVError extends Error {
|
||||
constructor(message, status = 500) {
|
||||
super(message);
|
||||
// see: typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html
|
||||
Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
|
||||
this.name = KVError.name; // stack traces display correctly now
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
exports.KVError = KVError;
|
||||
class MethodNotAllowedError extends KVError {
|
||||
constructor(message = `Not a valid request method`, status = 405) {
|
||||
super(message, status);
|
||||
}
|
||||
}
|
||||
exports.MethodNotAllowedError = MethodNotAllowedError;
|
||||
class NotFoundError extends KVError {
|
||||
constructor(message = `Not Found`, status = 404) {
|
||||
super(message, status);
|
||||
}
|
||||
}
|
||||
exports.NotFoundError = NotFoundError;
|
||||
class InternalError extends KVError {
|
||||
constructor(message = `Internal Error in KV Asset Handler`, status = 500) {
|
||||
super(message, status);
|
||||
}
|
||||
}
|
||||
exports.InternalError = InternalError;
|
Loading…
Add table
Add a link
Reference in a new issue